diff --git a/mailhog/http/api/v1.go b/mailhog/http/api/v1.go new file mode 100644 index 0000000..b579d78 --- /dev/null +++ b/mailhog/http/api/v1.go @@ -0,0 +1,58 @@ +package api + +import ( + "log" + "encoding/json" + "net/http" + "regexp" + "github.com/ian-kent/MailHog/mailhog" + "github.com/ian-kent/MailHog/mailhog/storage" + "github.com/ian-kent/MailHog/mailhog/http/handler" +) + +type APIv1 struct { + config *mailhog.Config + exitChannel chan int + server *http.Server +} + +func CreateAPIv1(exitCh chan int, conf *mailhog.Config, server *http.Server) *APIv1 { + log.Println("Creating API v1") + apiv1 := &APIv1{ + config: conf, + exitChannel: exitCh, + server: server, + } + + server.Handler.(*handler.RegexpHandler).HandleFunc(regexp.MustCompile("^/api/v1/messages$"), apiv1.messages) + server.Handler.(*handler.RegexpHandler).HandleFunc(regexp.MustCompile("^/api/v1/messages/delete$"), apiv1.delete_all) + server.Handler.(*handler.RegexpHandler).HandleFunc(regexp.MustCompile("^/api/v1/messages/([0-9a-f]+)/delete$"), apiv1.delete_one) + + return apiv1 +} + +func (apiv1 *APIv1) messages(w http.ResponseWriter, r *http.Request, route *handler.Route) { + log.Println("[APIv1] GET /api/v1/messages") + + // TODO start, limit + messages, _ := storage.List(apiv1.config, 0, 1000) + bytes, _ := json.Marshal(messages) + w.Header().Set("Content-Type", "text/json") + w.Write(bytes) +} + +func (apiv1 *APIv1) delete_all(w http.ResponseWriter, r *http.Request, route *handler.Route) { + log.Println("[APIv1] POST /api/v1/messages/delete") + + w.Header().Set("Content-Type", "text/json") + storage.DeleteAll(apiv1.config) +} + +func (apiv1 *APIv1) delete_one(w http.ResponseWriter, r *http.Request, route *handler.Route) { + match := route.Pattern.FindStringSubmatch(r.URL.Path) + id := match[1] + log.Printf("[APIv1] POST /api/v1/messages/%s/delete\n", id) + + w.Header().Set("Content-Type", "text/json") + storage.DeleteOne(apiv1.config, id) +} diff --git a/mailhog/http/handler/regexp.go b/mailhog/http/handler/regexp.go new file mode 100644 index 0000000..5e9d7a5 --- /dev/null +++ b/mailhog/http/handler/regexp.go @@ -0,0 +1,43 @@ +package handler; + +import ( + "regexp" + "net/http" +) + +// http://stackoverflow.com/questions/6564558/wildcards-in-the-pattern-for-http-handlefunc + +type Route struct { + 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 RegexpHandler struct { + routes []*Route +} + +func (h *RegexpHandler) Handler(pattern *regexp.Regexp, handler HandlerFunc) { + h.routes = append(h.routes, &Route{pattern, handler}) +} + +func (h *RegexpHandler) HandleFunc(pattern *regexp.Regexp, handler func(http.ResponseWriter, *http.Request, *Route)) { + h.routes = append(h.routes, &Route{pattern, HandlerFunc(handler)}) +} + +func (h *RegexpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + for _, route := range h.routes { + if route.Pattern.MatchString(r.URL.Path) { + route.Handler.ServeHTTP(w, r, route) + return + } + } + // no pattern matched; send 404 response + http.NotFound(w, r) +} diff --git a/mailhog/http/server.go b/mailhog/http/server.go index d8cf27d..4eb6684 100644 --- a/mailhog/http/server.go +++ b/mailhog/http/server.go @@ -1,36 +1,36 @@ package http import ( - "encoding/json" - "net/http" "regexp" + "net/http" "github.com/ian-kent/MailHog/mailhog" "github.com/ian-kent/MailHog/mailhog/templates" - "github.com/ian-kent/MailHog/mailhog/storage" "github.com/ian-kent/MailHog/mailhog/templates/images" "github.com/ian-kent/MailHog/mailhog/templates/js" + "github.com/ian-kent/MailHog/mailhog/http/api" + "github.com/ian-kent/MailHog/mailhog/http/handler" ) var exitChannel chan int var config *mailhog.Config -func web_exit(w http.ResponseWriter, r *http.Request) { +func web_exit(w http.ResponseWriter, r *http.Request, route *handler.Route) { web_headers(w) w.Write([]byte("Exiting MailHog!")) exitChannel <- 1 } -func web_index(w http.ResponseWriter, r *http.Request) { +func web_index(w http.ResponseWriter, r *http.Request, route *handler.Route) { web_headers(w) w.Write([]byte(web_render(templates.Index()))) } -func web_jscontroller(w http.ResponseWriter, r *http.Request) { +func web_jscontroller(w http.ResponseWriter, r *http.Request, route *handler.Route) { w.Header().Set("Content-Type", "text/javascript") w.Write([]byte(js.Controllers())) } -func web_imgcontroller(w http.ResponseWriter, r *http.Request) { +func web_imgcontroller(w http.ResponseWriter, r *http.Request, route *handler.Route) { w.Header().Set("Content-Type", "image/png") w.Write(images.Hog()) } @@ -43,40 +43,21 @@ func web_headers(w http.ResponseWriter) { w.Header().Set("Content-Type", "text/html") } -func api_messages(w http.ResponseWriter, r *http.Request) { - re, _ := regexp.Compile("/api/v1/messages/([0-9a-f]+)/delete") - match := re.FindStringSubmatch(r.URL.Path) - if len(match) > 0 { - api_delete_one(w, r, match[1]) - return - } - - // TODO start, limit - messages, _ := storage.List(config, 0, 1000) - bytes, _ := json.Marshal(messages) - w.Header().Set("Content-Type", "text/json") - w.Write(bytes) -} - -func api_delete_all(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "text/json") - storage.DeleteAll(config) -} - -func api_delete_one(w http.ResponseWriter, r *http.Request, id string) { - w.Header().Set("Content-Type", "text/json") - storage.DeleteOne(config, id) -} - func Start(exitCh chan int, conf *mailhog.Config) { exitChannel = exitCh config = conf - http.HandleFunc("/exit", web_exit) - http.HandleFunc("/js/controllers.js", web_jscontroller) - http.HandleFunc("/images/hog.png", web_imgcontroller) - http.HandleFunc("/", web_index) - http.HandleFunc("/api/v1/messages/", api_messages) - http.HandleFunc("/api/v1/messages/delete", api_delete_all) - http.ListenAndServe(conf.HTTPBindAddr, nil) + server := &http.Server{ + Addr: conf.HTTPBindAddr, + Handler: &handler.RegexpHandler{}, + } + + server.Handler.(*handler.RegexpHandler).HandleFunc(regexp.MustCompile("^/exit$"), web_exit) + server.Handler.(*handler.RegexpHandler).HandleFunc(regexp.MustCompile("^/js/controllers.js$"), web_jscontroller) + server.Handler.(*handler.RegexpHandler).HandleFunc(regexp.MustCompile("^/images/hog.png$"), web_imgcontroller) + server.Handler.(*handler.RegexpHandler).HandleFunc(regexp.MustCompile("^/$"), web_index) + + api.CreateAPIv1(exitCh, conf, server) + + server.ListenAndServe() }