package routing import ( "errors" "net/http" "sync" "git.markbailey.dev/cerbervs/ptpp/app/controller" "git.markbailey.dev/cerbervs/ptpp/app/handler" "git.markbailey.dev/cerbervs/ptpp/app/session" "git.markbailey.dev/cerbervs/ptpp/lib/database" werror "git.markbailey.dev/cerbervs/ptpp/lib/error" "git.markbailey.dev/cerbervs/ptpp/lib/logger" "git.markbailey.dev/cerbervs/ptpp/lib/middleware" "git.markbailey.dev/cerbervs/ptpp/util" ) type IRouter interface { RegisterRoutes() http.Handler } type Route struct { Controller controller.IController Path string Name string } type Router struct { Mux *http.ServeMux Middleware *[]middleware.Func BasePath string SubRouters []*Router Routes []Route } var ( rtr *Router rtrOnce sync.Once mux *http.ServeMux muxOnce sync.Once fsOnce sync.Once sess session.IManager ) func (r *Router) HandleAllRequestMethods(route Route, fullPath string) { ctx := controller.ControllerCtx{RouterCtx: rtr} c := route.Controller.Init(sess, database.ChooseDB(), logger.NewCompositeLogger(), ctx) r.Mux.Handle("GET "+fullPath, handler.HandlerFunc(c.Get)) r.Mux.Handle("OPTIONS "+fullPath, handler.HandlerFunc(c.Options)) r.Mux.Handle("TRACE "+fullPath, handler.HandlerFunc(c.Trace)) r.Mux.Handle("PUT "+fullPath, handler.HandlerFunc(c.Put)) r.Mux.Handle("DELETE "+fullPath, handler.HandlerFunc(c.Delete)) r.Mux.Handle("POST "+fullPath, handler.HandlerFunc(c.Post)) r.Mux.Handle("PATCH "+fullPath, handler.HandlerFunc(c.Patch)) r.Mux.Handle("CONNECT "+fullPath, handler.HandlerFunc(c.Connect)) } func (r *Router) RegisterRoutes() http.Handler { rtrOnce.Do(func() { rtr = r }) muxOnce.Do(func() { mux = http.NewServeMux(); r.Mux = mux }) fsOnce.Do(func() { r.RegisterFs() }) if r.Mux == nil { r.Mux = http.NewServeMux() } for _, route := range r.Routes { r.HandleAllRequestMethods(route, r.BasePath+route.Path) } for _, subRouter := range r.SubRouters { r.Mux.Handle( "GET "+r.BasePath+subRouter.BasePath, http.StripPrefix(subRouter.BasePath, subRouter.RegisterRoutes()), ) } if r.Middleware != nil { mw := middleware.Compose(*r.Middleware) mctx := middleware.MiddlewareCtx{RouterCtx: rtr} return mw(mux, mctx) } return mux } func (r *Router) RegisterFs() { fs := http.FileServer(http.Dir(util.GetFullyQualifiedPath("/public"))) r.Mux.Handle("GET "+r.BasePath+"public/", http.StripPrefix("/public/", fs)) } type RouteMapping struct { Path string Name string } func (r *Router) GetFlatRouteList() []RouteMapping { routes := []RouteMapping{} for _, route := range r.Routes { routes = append(routes, RouteMapping{Path: r.BasePath + route.Path, Name: route.Name}) } for _, subRouter := range r.SubRouters { routes = append(routes, subRouter.GetFlatRouteList()...) } return routes } func (r *Router) GetRouteByName(name string) (string, error) { for _, route := range r.GetFlatRouteList() { if route.Name == name { return route.Path, nil } } return "", werror.Wrap(errors.New(name+" does not exist"), "Route not found") } func init() { var err error sess, err = session.NewManager("memory", "ptpp", 3600) go sess.GC() if err != nil { panic(werror.Wrap(err, "Error creating session manager")) } }