Clean up routing

This commit is contained in:
Ian Kent 2014-04-27 21:13:35 +01:00
parent fa8e9d1b21
commit 92ff3714ad
4 changed files with 111 additions and 86 deletions

View file

@ -5,12 +5,11 @@ import (
"encoding/json"
"net/http"
"net/smtp"
"regexp"
"strconv"
"github.com/ian-kent/MailHog/mailhog/data"
"github.com/ian-kent/MailHog/mailhog/config"
"github.com/ian-kent/MailHog/mailhog/storage"
"github.com/ian-kent/MailHog/mailhog/http/handler"
"github.com/ian-kent/MailHog/mailhog/http/router"
)
type APIv1 struct {
@ -33,18 +32,20 @@ func CreateAPIv1(exitCh chan int, conf *config.Config, server *http.Server) *API
server: server,
}
server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/api/v1/messages/?$"), apiv1.messages)
server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"DELETE"},regexp.MustCompile("^/api/v1/messages/?$"), apiv1.delete_all)
server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/api/v1/messages/([0-9a-f]+)/?$"), apiv1.message)
server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"DELETE"},regexp.MustCompile("^/api/v1/messages/([0-9a-f]+)/?$"), apiv1.delete_one)
server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/api/v1/messages/([0-9a-f]+)/download/?$"), apiv1.download)
server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/api/v1/messages/([0-9a-f]+)/mime/part/(\\d+)/download/?$"), apiv1.download_part)
server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"POST"},regexp.MustCompile("^/api/v1/messages/([0-9a-f]+)/release/?$"), apiv1.release_one)
r := server.Handler.(*router.Router)
r.Get("^/api/v1/messages/?$", apiv1.messages)
r.Delete("^/api/v1/messages/?$", apiv1.delete_all)
r.Get("^/api/v1/messages/([0-9a-f]+)/?$", apiv1.message)
r.Delete("^/api/v1/messages/([0-9a-f]+)/?$", apiv1.delete_one)
r.Get("^/api/v1/messages/([0-9a-f]+)/download/?$", apiv1.download)
r.Get("^/api/v1/messages/([0-9a-f]+)/mime/part/(\\d+)/download/?$", apiv1.download_part)
r.Post("^/api/v1/messages/([0-9a-f]+)/release/?$", apiv1.release_one)
return apiv1
}
func (apiv1 *APIv1) messages(w http.ResponseWriter, r *http.Request, route *handler.Route) {
func (apiv1 *APIv1) messages(w http.ResponseWriter, r *http.Request, route *router.Route) {
log.Println("[APIv1] GET /api/v1/messages")
// TODO start, limit
@ -64,7 +65,7 @@ func (apiv1 *APIv1) messages(w http.ResponseWriter, r *http.Request, route *hand
}
}
func (apiv1 *APIv1) message(w http.ResponseWriter, r *http.Request, route *handler.Route) {
func (apiv1 *APIv1) message(w http.ResponseWriter, r *http.Request, route *router.Route) {
match := route.Pattern.FindStringSubmatch(r.URL.Path)
id := match[1]
@ -86,7 +87,7 @@ func (apiv1 *APIv1) message(w http.ResponseWriter, r *http.Request, route *handl
}
}
func (apiv1 *APIv1) download(w http.ResponseWriter, r *http.Request, route *handler.Route) {
func (apiv1 *APIv1) download(w http.ResponseWriter, r *http.Request, route *router.Route) {
match := route.Pattern.FindStringSubmatch(r.URL.Path)
id := match[1]
log.Printf("[APIv1] GET /api/v1/messages/%s/download\n", id)
@ -116,7 +117,7 @@ func (apiv1 *APIv1) download(w http.ResponseWriter, r *http.Request, route *hand
}
}
func (apiv1 *APIv1) download_part(w http.ResponseWriter, r *http.Request, route *handler.Route) {
func (apiv1 *APIv1) download_part(w http.ResponseWriter, r *http.Request, route *router.Route) {
match := route.Pattern.FindStringSubmatch(r.URL.Path)
id := match[1]
part, _ := strconv.Atoi(match[2])
@ -148,7 +149,7 @@ func (apiv1 *APIv1) download_part(w http.ResponseWriter, r *http.Request, route
}
}
func (apiv1 *APIv1) delete_all(w http.ResponseWriter, r *http.Request, route *handler.Route) {
func (apiv1 *APIv1) delete_all(w http.ResponseWriter, r *http.Request, route *router.Route) {
log.Println("[APIv1] POST /api/v1/messages")
w.Header().Set("Content-Type", "text/json")
@ -162,7 +163,7 @@ func (apiv1 *APIv1) delete_all(w http.ResponseWriter, r *http.Request, route *ha
}
}
func (apiv1 *APIv1) release_one(w http.ResponseWriter, r *http.Request, route *handler.Route) {
func (apiv1 *APIv1) release_one(w http.ResponseWriter, r *http.Request, route *router.Route) {
match := route.Pattern.FindStringSubmatch(r.URL.Path)
id := match[1]
log.Printf("[APIv1] POST /api/v1/messages/%s/release\n", id)
@ -208,7 +209,7 @@ func (apiv1 *APIv1) release_one(w http.ResponseWriter, r *http.Request, route *h
log.Printf("Message released successfully")
}
func (apiv1 *APIv1) delete_one(w http.ResponseWriter, r *http.Request, route *handler.Route) {
func (apiv1 *APIv1) delete_one(w http.ResponseWriter, r *http.Request, route *router.Route) {
match := route.Pattern.FindStringSubmatch(r.URL.Path)
id := match[1]
log.Printf("[APIv1] POST /api/v1/messages/%s/delete\n", id)

View file

@ -1,55 +0,0 @@
package handler;
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 RegexpHandler struct {
routes []*Route
}
func (h *RegexpHandler) 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 *RegexpHandler) 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 *RegexpHandler) 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

@ -0,0 +1,79 @@
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,12 +1,11 @@
package http
import (
"regexp"
"net/http"
"strings"
"github.com/ian-kent/MailHog/mailhog/config"
"github.com/ian-kent/MailHog/mailhog/http/api"
"github.com/ian-kent/MailHog/mailhog/http/handler"
"github.com/ian-kent/MailHog/mailhog/http/router"
)
var exitChannel chan int
@ -14,37 +13,37 @@ var cfg *config.Config
// TODO clean this mess up
func web_exit(w http.ResponseWriter, r *http.Request, route *handler.Route) {
func web_exit(w http.ResponseWriter, r *http.Request, route *router.Route) {
web_headers(w)
w.Write([]byte("Exiting MailHog!"))
exitChannel <- 1
}
func web_index(w http.ResponseWriter, r *http.Request, route *handler.Route) {
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_jscontroller(w http.ResponseWriter, r *http.Request, route *handler.Route) {
func web_jscontroller(w http.ResponseWriter, r *http.Request, route *router.Route) {
w.Header().Set("Content-Type", "text/javascript")
data, _ := cfg.Assets("assets/js/controllers.js")
w.Write(data)
}
func web_imgcontroller(w http.ResponseWriter, r *http.Request, route *handler.Route) {
func web_imgcontroller(w http.ResponseWriter, r *http.Request, route *router.Route) {
w.Header().Set("Content-Type", "image/png")
data, _ := cfg.Assets("assets/images/hog.png")
w.Write(data)
}
func web_img_github(w http.ResponseWriter, r *http.Request, route *handler.Route) {
func web_img_github(w http.ResponseWriter, r *http.Request, route *router.Route) {
w.Header().Set("Content-Type", "image/png")
data, _ := cfg.Assets("assets/images/github.png")
w.Write(data)
}
func web_img_ajaxloader(w http.ResponseWriter, r *http.Request, route *handler.Route) {
func web_img_ajaxloader(w http.ResponseWriter, r *http.Request, route *router.Route) {
w.Header().Set("Content-Type", "image/gif")
data, _ := cfg.Assets("assets/images/ajax-loader.gif")
w.Write(data)
@ -67,17 +66,18 @@ func Start(exitCh chan int, conf *config.Config) {
exitChannel = exitCh
cfg = conf
r := &router.Router{}
server := &http.Server{
Addr: conf.HTTPBindAddr,
Handler: &handler.RegexpHandler{},
Handler: r,
}
server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/exit/?$"), web_exit)
server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/js/controllers.js$"), web_jscontroller)
server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/images/hog.png$"), web_imgcontroller)
server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/images/github.png$"), web_img_github)
server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/images/ajax-loader.gif$"), web_img_ajaxloader)
server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/$"), web_index)
r.Get("^/exit/?$", web_exit)
r.Get("^/js/controllers.js$", web_jscontroller)
r.Get("^/images/hog.png$", web_imgcontroller)
r.Get("^/images/github.png$", web_img_github)
r.Get("^/images/ajax-loader.gif$", web_img_ajaxloader)
r.Get("^/$", web_index)
api.CreateAPIv1(exitCh, conf, server)