Start converting to use github.com/ian-kent/gotcha

This commit is contained in:
Ian Kent 2014-06-23 19:21:20 +01:00
parent bc56772c03
commit 5409809872
5 changed files with 114 additions and 270 deletions

View file

@ -11,6 +11,8 @@ release: release-deps
gox gox
deps: deps:
go get github.com/ian-kent/gotcha/...
go get github.com/ian-kent/go-log/...
go get github.com/jteeuwen/go-bindata/... go get github.com/jteeuwen/go-bindata/...
go get labix.org/v2/mgo go get labix.org/v2/mgo

View file

@ -4,28 +4,25 @@ import (
"log" "log"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net"
"net/http"
"net/smtp" "net/smtp"
"strconv" "strconv"
"bufio"
"strings" "strings"
"github.com/ian-kent/Go-MailHog/mailhog/data" "github.com/ian-kent/Go-MailHog/mailhog/data"
"github.com/ian-kent/Go-MailHog/mailhog/config" "github.com/ian-kent/Go-MailHog/mailhog/config"
"github.com/ian-kent/Go-MailHog/mailhog/storage" "github.com/ian-kent/Go-MailHog/mailhog/storage"
"github.com/ian-kent/Go-MailHog/mailhog/http/router" gotcha "github.com/ian-kent/gotcha/app"
"github.com/ian-kent/gotcha/http"
) )
type APIv1 struct { type APIv1 struct {
config *config.Config config *config.Config
exitChannel chan int
server *http.Server
eventlisteners []*EventListener eventlisteners []*EventListener
app *gotcha.App
} }
type EventListener struct { type EventListener struct {
conn net.Conn session *http.Session
bufrw *bufio.ReadWriter ch chan []byte
} }
type ReleaseConfig struct { type ReleaseConfig struct {
@ -34,25 +31,24 @@ type ReleaseConfig struct {
Port string Port string
} }
func CreateAPIv1(exitCh chan int, conf *config.Config, server *http.Server) *APIv1 { func CreateAPIv1(conf *config.Config, app *gotcha.App) *APIv1 {
log.Println("Creating API v1") log.Println("Creating API v1")
apiv1 := &APIv1{ apiv1 := &APIv1{
config: conf, config: conf,
exitChannel: exitCh,
server: server,
eventlisteners: make([]*EventListener, 0), eventlisteners: make([]*EventListener, 0),
app: app,
} }
r := server.Handler.(*router.Router) r := app.Router
r.Get("^/api/v1/messages/?$", apiv1.messages) r.Get("/api/v1/messages/?", apiv1.messages)
r.Delete("^/api/v1/messages/?$", apiv1.delete_all) r.Delete("/api/v1/messages/?", apiv1.delete_all)
r.Get("^/api/v1/messages/([0-9a-f]+)/?$", apiv1.message) r.Get("/api/v1/messages/(?P<id>[0-9a-f]+)/?", apiv1.message)
r.Delete("^/api/v1/messages/([0-9a-f]+)/?$", apiv1.delete_one) r.Delete("/api/v1/messages/(?P<id>[0-9a-f]+)/?", apiv1.delete_one)
r.Get("^/api/v1/messages/([0-9a-f]+)/download/?$", apiv1.download) r.Get("/api/v1/messages/(?P<id>[0-9a-f]+)/download/?", apiv1.download)
r.Get("^/api/v1/messages/([0-9a-f]+)/mime/part/(\\d+)/download/?$", apiv1.download_part) r.Get("/api/v1/messages/(?P<id>[0-9a-f]+)/mime/part/(\\d+)/download/?", apiv1.download_part)
r.Post("^/api/v1/messages/([0-9a-f]+)/release/?$", apiv1.release_one) r.Post("/api/v1/messages/(?P<id>[0-9a-f]+)/release/?", apiv1.release_one)
r.Get("^/api/v1/events/?$", apiv1.eventstream) r.Get("/api/v1/events/?", apiv1.eventstream)
go func() { go func() {
for { for {
@ -63,8 +59,6 @@ func CreateAPIv1(exitCh chan int, conf *config.Config, server *http.Server) *API
json := string(bytes) json := string(bytes)
log.Printf("Sending content: %s\n", json) log.Printf("Sending content: %s\n", json)
apiv1.broadcast(json) apiv1.broadcast(json)
case <- exitCh:
break;
} }
} }
}() }()
@ -75,7 +69,7 @@ func CreateAPIv1(exitCh chan int, conf *config.Config, server *http.Server) *API
func (apiv1 *APIv1) broadcast(json string) { func (apiv1 *APIv1) broadcast(json string) {
log.Println("[APIv1] BROADCAST /api/v1/events") log.Println("[APIv1] BROADCAST /api/v1/events")
for _, l := range apiv1.eventlisteners { for _, l := range apiv1.eventlisteners {
log.Printf("Sending to connection: %s\n", l.conn.RemoteAddr()) log.Printf("Sending to connection: %s\n", l.session.Request.RemoteAddr)
lines := strings.Split(json, "\n") lines := strings.Split(json, "\n")
data := "" data := ""
@ -85,49 +79,32 @@ func (apiv1 *APIv1) broadcast(json string) {
data += "\n" data += "\n"
size := fmt.Sprintf("%X", len(data) + 1) size := fmt.Sprintf("%X", len(data) + 1)
l.bufrw.Write([]byte(size + "\r\n")) l.ch <- []byte(size + "\r\n")
lines = strings.Split(data, "\n") lines = strings.Split(data, "\n")
for _, ln := range lines { for _, ln := range lines {
l.bufrw.Write([]byte(ln + "\n")) l.ch <- []byte(ln + "\n")
}
_, err := l.bufrw.Write([]byte("\r\n"))
if err != nil {
log.Printf("Error writing to connection: %s\n", err)
l.conn.Close()
// TODO remove from array
}
err = l.bufrw.Flush()
if err != nil {
log.Printf("Error flushing buffer: %s\n", err)
l.conn.Close()
// TODO remove from array
} }
l.ch <- []byte("\r\n")
} }
} }
func (apiv1 *APIv1) eventstream(w http.ResponseWriter, r *http.Request, route *router.Route) { func (apiv1 *APIv1) eventstream(session *http.Session) {
log.Println("[APIv1] GET /api/v1/events") log.Println("[APIv1] GET /api/v1/events")
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache") apiv1.eventlisteners = append(apiv1.eventlisteners, &EventListener{
w.Header().Set("Connection", "keep-alive") session,
w.Write([]byte("\n\n")) session.Response.Chunked(),
hj, ok := w.(http.Hijacker) })
if !ok {
log.Println("[APIv1] Connection hijack failed") session.Response.Headers.Add("Content-Type", "text/event-stream")
return session.Response.Headers.Add("Cache-Control", "no-cache")
} session.Response.Headers.Add("Connection", "keep-alive")
conn, bufrw, err := hj.Hijack() session.Response.Write([]byte("\n\n"))
if err != nil { session.Response.Send()
log.Println("[APIv1] Connection hijack failed")
return
}
apiv1.eventlisteners = append(apiv1.eventlisteners, &EventListener{conn, bufrw})
} }
func (apiv1 *APIv1) messages(w http.ResponseWriter, r *http.Request, route *router.Route) { func (apiv1 *APIv1) messages(session *http.Session) {
log.Println("[APIv1] GET /api/v1/messages") log.Println("[APIv1] GET /api/v1/messages")
// TODO start, limit // TODO start, limit
@ -135,122 +112,118 @@ func (apiv1 *APIv1) messages(w http.ResponseWriter, r *http.Request, route *rout
case *storage.MongoDB: case *storage.MongoDB:
messages, _ := apiv1.config.Storage.(*storage.MongoDB).List(0, 1000) messages, _ := apiv1.config.Storage.(*storage.MongoDB).List(0, 1000)
bytes, _ := json.Marshal(messages) bytes, _ := json.Marshal(messages)
w.Header().Set("Content-Type", "text/json") session.Response.Headers.Add("Content-Type", "text/json")
w.Write(bytes) session.Response.Write(bytes)
case *storage.Memory: case *storage.Memory:
messages, _ := apiv1.config.Storage.(*storage.Memory).List(0, 1000) messages, _ := apiv1.config.Storage.(*storage.Memory).List(0, 1000)
bytes, _ := json.Marshal(messages) bytes, _ := json.Marshal(messages)
w.Header().Set("Content-Type", "text/json") session.Response.Headers.Add("Content-Type", "text/json")
w.Write(bytes) session.Response.Write(bytes)
default: default:
w.WriteHeader(500) session.Response.Status = 500
} }
} }
func (apiv1 *APIv1) message(w http.ResponseWriter, r *http.Request, route *router.Route) { func (apiv1 *APIv1) message(session *http.Session) {
id := session.Stash["id"].(string)
match := route.Pattern.FindStringSubmatch(r.URL.Path)
id := match[1]
log.Printf("[APIv1] GET /api/v1/messages/%s\n", id) log.Printf("[APIv1] GET /api/v1/messages/%s\n", id)
switch apiv1.config.Storage.(type) { switch apiv1.config.Storage.(type) {
case *storage.MongoDB: case *storage.MongoDB:
message, _ := apiv1.config.Storage.(*storage.MongoDB).Load(id) message, _ := apiv1.config.Storage.(*storage.MongoDB).Load(id)
bytes, _ := json.Marshal(message) bytes, _ := json.Marshal(message)
w.Header().Set("Content-Type", "text/json") session.Response.Headers.Add("Content-Type", "text/json")
w.Write(bytes) session.Response.Write(bytes)
case *storage.Memory: case *storage.Memory:
message, _ := apiv1.config.Storage.(*storage.Memory).Load(id) message, _ := apiv1.config.Storage.(*storage.Memory).Load(id)
bytes, _ := json.Marshal(message) bytes, _ := json.Marshal(message)
w.Header().Set("Content-Type", "text/json") session.Response.Headers.Add("Content-Type", "text/json")
w.Write(bytes) session.Response.Write(bytes)
default: default:
w.WriteHeader(500) session.Response.Status = 500
} }
} }
func (apiv1 *APIv1) download(w http.ResponseWriter, r *http.Request, route *router.Route) { func (apiv1 *APIv1) download(session *http.Session) {
match := route.Pattern.FindStringSubmatch(r.URL.Path) id := session.Stash["id"].(string)
id := match[1] log.Printf("[APIv1] GET /api/v1/messages/%s\n", id)
log.Printf("[APIv1] GET /api/v1/messages/%s/download\n", id)
w.Header().Set("Content-Type", "message/rfc822") session.Response.Headers.Add("Content-Type", "message/rfc822")
w.Header().Set("Content-Disposition", "attachment; filename=\"" + id + ".eml\"") session.Response.Headers.Add("Content-Disposition", "attachment; filename=\"" + id + ".eml\"")
switch apiv1.config.Storage.(type) { switch apiv1.config.Storage.(type) {
case *storage.MongoDB: case *storage.MongoDB:
message, _ := apiv1.config.Storage.(*storage.MongoDB).Load(id) message, _ := apiv1.config.Storage.(*storage.MongoDB).Load(id)
for h, l := range message.Content.Headers { for h, l := range message.Content.Headers {
for _, v := range l { for _, v := range l {
w.Write([]byte(h + ": " + v + "\r\n")) session.Response.Write([]byte(h + ": " + v + "\r\n"))
} }
} }
w.Write([]byte("\r\n" + message.Content.Body)) session.Response.Write([]byte("\r\n" + message.Content.Body))
case *storage.Memory: case *storage.Memory:
message, _ := apiv1.config.Storage.(*storage.Memory).Load(id) message, _ := apiv1.config.Storage.(*storage.Memory).Load(id)
for h, l := range message.Content.Headers { for h, l := range message.Content.Headers {
for _, v := range l { for _, v := range l {
w.Write([]byte(h + ": " + v + "\r\n")) session.Response.Write([]byte(h + ": " + v + "\r\n"))
} }
} }
w.Write([]byte("\r\n" + message.Content.Body)) session.Response.Write([]byte("\r\n" + message.Content.Body))
default: default:
w.WriteHeader(500) session.Response.Status = 500
} }
} }
func (apiv1 *APIv1) download_part(w http.ResponseWriter, r *http.Request, route *router.Route) { func (apiv1 *APIv1) download_part(session *http.Session) {
match := route.Pattern.FindStringSubmatch(r.URL.Path) id := session.Stash["id"].(string)
id := match[1] part, _ := strconv.Atoi(session.Stash["part"].(string))
part, _ := strconv.Atoi(match[2])
log.Printf("[APIv1] GET /api/v1/messages/%s/mime/part/%d/download\n", id, part) log.Printf("[APIv1] GET /api/v1/messages/%s/mime/part/%d/download\n", id, part)
// TODO extension from content-type? // TODO extension from content-type?
w.Header().Set("Content-Disposition", "attachment; filename=\"" + id + "-part-" + match[2] + "\"") session.Response.Headers.Add("Content-Disposition", "attachment; filename=\"" + id + "-part-" + strconv.Itoa(part) + "\"")
switch apiv1.config.Storage.(type) { switch apiv1.config.Storage.(type) {
case *storage.MongoDB: case *storage.MongoDB:
message, _ := apiv1.config.Storage.(*storage.MongoDB).Load(id) message, _ := apiv1.config.Storage.(*storage.MongoDB).Load(id)
for h, l := range message.MIME.Parts[part].Headers { for h, l := range message.MIME.Parts[part].Headers {
for _, v := range l { for _, v := range l {
w.Header().Set(h, v) session.Response.Headers.Add(h, v)
} }
} }
w.Write([]byte("\r\n" + message.MIME.Parts[part].Body)) session.Response.Write([]byte("\r\n" + message.MIME.Parts[part].Body))
case *storage.Memory: case *storage.Memory:
message, _ := apiv1.config.Storage.(*storage.Memory).Load(id) message, _ := apiv1.config.Storage.(*storage.Memory).Load(id)
for h, l := range message.MIME.Parts[part].Headers { for h, l := range message.MIME.Parts[part].Headers {
for _, v := range l { for _, v := range l {
w.Header().Set(h, v) session.Response.Headers.Add(h, v)
} }
} }
w.Write([]byte("\r\n" + message.MIME.Parts[part].Body)) session.Response.Write([]byte("\r\n" + message.MIME.Parts[part].Body))
default: default:
w.WriteHeader(500) session.Response.Status = 500
} }
} }
func (apiv1 *APIv1) delete_all(w http.ResponseWriter, r *http.Request, route *router.Route) { func (apiv1 *APIv1) delete_all(session *http.Session) {
log.Println("[APIv1] POST /api/v1/messages") log.Println("[APIv1] POST /api/v1/messages")
w.Header().Set("Content-Type", "text/json") session.Response.Headers.Add("Content-Type", "text/json")
switch apiv1.config.Storage.(type) { switch apiv1.config.Storage.(type) {
case *storage.MongoDB: case *storage.MongoDB:
apiv1.config.Storage.(*storage.MongoDB).DeleteAll() apiv1.config.Storage.(*storage.MongoDB).DeleteAll()
case *storage.Memory: case *storage.Memory:
apiv1.config.Storage.(*storage.Memory).DeleteAll() apiv1.config.Storage.(*storage.Memory).DeleteAll()
default: default:
w.WriteHeader(500) session.Response.Status = 500
return
} }
} }
func (apiv1 *APIv1) release_one(w http.ResponseWriter, r *http.Request, route *router.Route) { func (apiv1 *APIv1) release_one(session *http.Session) {
match := route.Pattern.FindStringSubmatch(r.URL.Path) id := session.Stash["id"].(string)
id := match[1]
log.Printf("[APIv1] POST /api/v1/messages/%s/release\n", id) log.Printf("[APIv1] POST /api/v1/messages/%s/release\n", id)
w.Header().Set("Content-Type", "text/json") session.Response.Headers.Add("Content-Type", "text/json")
var msg = &data.Message{} var msg = &data.Message{}
switch apiv1.config.Storage.(type) { switch apiv1.config.Storage.(type) {
case *storage.MongoDB: case *storage.MongoDB:
@ -258,16 +231,17 @@ func (apiv1 *APIv1) release_one(w http.ResponseWriter, r *http.Request, route *r
case *storage.Memory: case *storage.Memory:
msg, _ = apiv1.config.Storage.(*storage.Memory).Load(id) msg, _ = apiv1.config.Storage.(*storage.Memory).Load(id)
default: default:
w.WriteHeader(500) session.Response.Status = 500
return
} }
decoder := json.NewDecoder(r.Body) decoder := json.NewDecoder(session.Request.Body())
var cfg ReleaseConfig var cfg ReleaseConfig
err := decoder.Decode(&cfg) err := decoder.Decode(&cfg)
if err != nil { if err != nil {
log.Printf("Error decoding request body: %s", err) log.Printf("Error decoding request body: %s", err)
w.WriteHeader(500) session.Response.Status = 500
w.Write([]byte("Error decoding request body")) session.Response.Write([]byte("Error decoding request body"))
return return
} }
@ -285,24 +259,23 @@ func (apiv1 *APIv1) release_one(w http.ResponseWriter, r *http.Request, route *r
err = smtp.SendMail(cfg.Host + ":" + cfg.Port, nil, "nobody@" + apiv1.config.Hostname, []string{cfg.Email}, bytes) err = smtp.SendMail(cfg.Host + ":" + cfg.Port, nil, "nobody@" + apiv1.config.Hostname, []string{cfg.Email}, bytes)
if err != nil { if err != nil {
log.Printf("Failed to release message: %s", err) log.Printf("Failed to release message: %s", err)
w.WriteHeader(500) session.Response.Status = 500
return return
} }
log.Printf("Message released successfully") log.Printf("Message released successfully")
} }
func (apiv1 *APIv1) delete_one(w http.ResponseWriter, r *http.Request, route *router.Route) { func (apiv1 *APIv1) delete_one(session *http.Session) {
match := route.Pattern.FindStringSubmatch(r.URL.Path) id := session.Stash["id"].(string)
id := match[1]
log.Printf("[APIv1] POST /api/v1/messages/%s/delete\n", id) log.Printf("[APIv1] POST /api/v1/messages/%s/delete\n", id)
w.Header().Set("Content-Type", "text/json") session.Response.Headers.Add("Content-Type", "text/json")
switch apiv1.config.Storage.(type) { switch apiv1.config.Storage.(type) {
case *storage.MongoDB: case *storage.MongoDB:
apiv1.config.Storage.(*storage.MongoDB).DeleteOne(id) apiv1.config.Storage.(*storage.MongoDB).DeleteOne(id)
case *storage.Memory: case *storage.Memory:
apiv1.config.Storage.(*storage.Memory).DeleteOne(id) apiv1.config.Storage.(*storage.Memory).DeleteOne(id)
default: default:
w.WriteHeader(500) session.Response.Status = 500
} }
} }

View file

@ -1,79 +0,0 @@
package router;
import (
"regexp"
"net/http"
)
// http://stackoverflow.com/questions/6564558/wildcards-in-the-pattern-for-http-handlefunc
type Route struct {
Methods map[string]int
Pattern *regexp.Regexp
Handler HandlerFunc
}
type HandlerFunc func(http.ResponseWriter, *http.Request, *Route)
//type Handler http.Handler
func (f HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request, route *Route) {
f(w, r, route)
}
type Router struct {
routes []*Route
}
func (h *Router) Get(pattern string, handler HandlerFunc) {
h.Handler([]string{"GET"}, regexp.MustCompile(pattern), handler)
}
func (h *Router) Post(pattern string, handler HandlerFunc) {
h.Handler([]string{"POST"}, regexp.MustCompile(pattern), handler)
}
func (h *Router) Put(pattern string, handler HandlerFunc) {
h.Handler([]string{"PUT"}, regexp.MustCompile(pattern), handler)
}
func (h *Router) Delete(pattern string, handler HandlerFunc) {
h.Handler([]string{"DELETE"}, regexp.MustCompile(pattern), handler)
}
func (h *Router) Patch(pattern string, handler HandlerFunc) {
h.Handler([]string{"PATCH"}, regexp.MustCompile(pattern), handler)
}
func (h *Router) Options(pattern string, handler HandlerFunc) {
h.Handler([]string{"OPTIONS"}, regexp.MustCompile(pattern), handler)
}
func (h *Router) Handler(methods []string, pattern *regexp.Regexp, handler HandlerFunc) {
m := make(map[string]int,0)
for _, v := range methods {
m[v] = 1
}
h.routes = append(h.routes, &Route{m, pattern, handler})
}
func (h *Router) HandleFunc(methods []string, pattern *regexp.Regexp, handler func(http.ResponseWriter, *http.Request, *Route)) {
m := make(map[string]int,0)
for _, v := range methods {
m[v] = 1
}
h.routes = append(h.routes, &Route{m, pattern, HandlerFunc(handler)})
}
func (h *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
for _, route := range h.routes {
if route.Pattern.MatchString(r.URL.Path) {
_, ok := route.Methods[r.Method]
if ok {
route.Handler.ServeHTTP(w, r, route)
return
}
}
}
// no pattern matched; send 404 response
http.NotFound(w, r)
}

View file

@ -1,86 +1,14 @@
package http package http
import ( import (
"net/http" "github.com/ian-kent/gotcha/http"
"strings" "html/template"
"log"
"github.com/ian-kent/Go-MailHog/mailhog/config"
"github.com/ian-kent/Go-MailHog/mailhog/http/api"
"github.com/ian-kent/Go-MailHog/mailhog/http/router"
) )
var exitChannel chan int func Index(session *http.Session) {
var cfg *config.Config html, _ := session.RenderTemplate("index.html")
// TODO clean this mess up session.Stash["Page"] = "Browse"
session.Stash["Content"] = template.HTML(html)
func web_exit(w http.ResponseWriter, r *http.Request, route *router.Route) { session.Render("layout.html")
web_headers(w)
w.Write([]byte("Exiting MailHog!"))
exitChannel <- 1
}
func web_index(w http.ResponseWriter, r *http.Request, route *router.Route) {
web_headers(w)
data, _ := cfg.Assets("assets/templates/index.html")
w.Write([]byte(web_render(string(data))))
}
func web_static(w http.ResponseWriter, r *http.Request, route *router.Route) {
match := route.Pattern.FindStringSubmatch(r.URL.Path)
file := match[1]
log.Printf("[HTTP] GET %s\n", file)
if strings.HasSuffix(file, ".gif") {
w.Header().Set("Content-Type", "image/gif")
} else if strings.HasSuffix(file, ".png") {
w.Header().Set("Content-Type", "image/png")
} else if strings.HasSuffix(file, ".js") {
w.Header().Set("Content-Type", "text/javascript")
} else {
w.Header().Set("Content-Type", "text/plain")
}
data, err := cfg.Assets("assets" + file)
if err != nil {
w.WriteHeader(404)
return
}
w.Write(data)
}
func web_render(content string) string {
data, _ := cfg.Assets("assets/templates/layout.html")
layout := string(data)
html := strings.Replace(layout, "<%= content %>", content, -1)
// TODO clean this up
html = strings.Replace(html, "<%= config[Hostname] %>", cfg.Hostname, -1)
return html
}
func web_headers(w http.ResponseWriter) {
w.Header().Set("Content-Type", "text/html")
}
func Start(exitCh chan int, conf *config.Config) {
exitChannel = exitCh
cfg = conf
r := &router.Router{}
server := &http.Server{
Addr: conf.HTTPBindAddr,
Handler: r,
}
r.Get("^/exit/?$", web_exit)
r.Get("^(/js/controllers.js)$", web_static)
r.Get("^(/images/hog.png)$", web_static)
r.Get("^(/images/github.png)$", web_static)
r.Get("^(/images/ajax-loader.gif)$", web_static)
r.Get("^/$", web_index)
api.CreateAPIv1(exitCh, conf, server)
server.ListenAndServe()
} }

28
main.go
View file

@ -3,12 +3,14 @@ package main
import ( import (
"flag" "flag"
"github.com/ian-kent/Go-MailHog/mailhog/config" "github.com/ian-kent/Go-MailHog/mailhog/config"
"github.com/ian-kent/Go-MailHog/mailhog/http"
"github.com/ian-kent/Go-MailHog/mailhog/smtp" "github.com/ian-kent/Go-MailHog/mailhog/smtp"
"github.com/ian-kent/Go-MailHog/mailhog/http/api"
"github.com/ian-kent/Go-MailHog/mailhog/storage" "github.com/ian-kent/Go-MailHog/mailhog/storage"
"log" gotcha "github.com/ian-kent/gotcha/app"
"github.com/ian-kent/go-log/log"
"net" "net"
"os" "os"
mhhttp "github.com/ian-kent/Go-MailHog/mailhog/http"
) )
var conf *config.Config var conf *config.Config
@ -73,8 +75,26 @@ func main() {
} }
func web_listen() { func web_listen() {
log.Printf("[HTTP] Binding to address: %s\n", conf.HTTPBindAddr) log.Info("[HTTP] Binding to address: %s", conf.HTTPBindAddr)
http.Start(exitCh, conf)
var app = gotcha.Create(Asset)
app.Config.Listen = conf.HTTPBindAddr
r := app.Router
r.Get("/images/(?P<file>.*)", r.Static("assets/images/{{file}}"))
r.Get("/js/(?P<file>.*)", r.Static("assets/js/{{file}}"))
r.Get("/", mhhttp.Index)
api.CreateAPIv1(conf, app)
app.Config.LeftDelim = ">>";
app.Config.RightDelim = "<<";
app.Start()
<-make(chan int)
exitCh<-1
} }
func smtp_listen() *net.TCPListener { func smtp_listen() *net.TCPListener {