From c045b456b4f15722ad9767ff8f795892e8c64e44 Mon Sep 17 00:00:00 2001 From: Azareal Date: Thu, 13 Apr 2017 10:26:40 +0100 Subject: [PATCH] Gosora now uses the generated router. There's still a fair bit of work to be done on this, I might turn the switch into a proper parser at some point, as there are a few inefficiencies in it's design. Improved the router generator facilities. The router generator now supports route groups. --- build.bat | 7 ++++ gen_router.go | 74 +++++++++++++++++++++++++++----------- general_test.go | 5 +-- main.go | 17 ++++----- router_gen/build.bat | 9 +++++ router_gen/main.go | 85 ++++++++++++++++++++++++++++++++++---------- router_gen/routes.go | 22 ++++++++---- router_gen/run.bat | 10 ++++++ routes.go | 5 +-- 9 files changed, 172 insertions(+), 62 deletions(-) create mode 100644 router_gen/build.bat create mode 100644 router_gen/run.bat diff --git a/build.bat b/build.bat index 27d28e3f..896cd3e2 100644 --- a/build.bat +++ b/build.bat @@ -19,5 +19,12 @@ if %errorlevel% neq 0 ( pause exit /b %errorlevel% ) + +echo Building the router generator +go build ./router_gen +if %errorlevel% neq 0 ( + pause + exit /b %errorlevel% +) echo Gosora was successfully built pause \ No newline at end of file diff --git a/gen_router.go b/gen_router.go index 9981a17b..6d9dabd7 100644 --- a/gen_router.go +++ b/gen_router.go @@ -2,7 +2,9 @@ /* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */ package main +//import "fmt" import "sync" +import "strings" import "net/http" type GenRouter struct { @@ -11,18 +13,14 @@ type GenRouter struct { old_routes map[string]func(http.ResponseWriter, *http.Request) // Temporary Fallback } -func NewGenRouter() *GenRouter { - fs_u := http.FileServer(http.Dir("./uploads")) +func NewGenRouter(uploads http.Handler) *GenRouter { return &GenRouter{ - UploadHandler: http.StripPrefix("/uploads/",fs_u).ServeHTTP, + UploadHandler: http.StripPrefix("/uploads/",uploads).ServeHTTP, old_routes: make(map[string]func(http.ResponseWriter, *http.Request)), } } -func (router *GenRouter) Handle(pattern string, handle http.Handler) { - router.Lock() - router.old_routes[pattern] = handle.ServeHTTP - router.Unlock() +func (router *GenRouter) Handle(_ string, _ http.Handler) { } func (router *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request)) { @@ -32,37 +30,71 @@ func (router *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWri } func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { + //if req.URL.Path == "/" { + // default_route(w,req) + // return + //} if req.URL.Path[0] != '/' { w.WriteHeader(405) w.Write([]byte("")) return } - var extra_data string - /*if req.URL.Path[len(req.URL.Path) - 1] != '/' { + var prefix, extra_data string + prefix = req.URL.Path[0:strings.IndexByte(req.URL.Path[1:],'/') + 1] + if req.URL.Path[len(req.URL.Path) - 1] != '/' { extra_data = req.URL.Path[strings.LastIndexByte(req.URL.Path,'/') + 1:] req.URL.Path = req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/') + 1] - }*/ - switch(req.URL.Path) { - case "/static/": route_static(w,req/*, req.URL.Path + extra_data*/) - case "/overview/": route_overview(w,req/**/) - case "/pages/": route_custom_page(w,req/*, &extra_data*/) - case "/topics/": route_topics(w,req/*, &groups, &forums*/) - case "/forums/": route_forums(w,req/*, &forums*/) - case "/uploads/": router.UploadHandler(w,req) + } + //fmt.Println("prefix:",prefix) + //fmt.Println("req.URL.Path:",req.URL.Path) + //fmt.Println("extra_data:",extra_data) + switch(prefix) { + case "/static": + req.URL.Path += extra_data + route_static(w,req) + return + case "/overview": + route_overview(w,req) + return + case "/pages": + route_custom_page(w,req) + return + case "/forums": + route_forums(w,req) + return + case "/topics": + switch(req.URL.Path) { + case "/topics/": + route_topics(w,req) + return + case "/topics/create/": + route_topic_create(w,req, extra_data) + return + } + case "/uploads": + if extra_data == "" { + NotFound(w,req) + return + } + req.URL.Path += extra_data + router.UploadHandler(w,req) + return + case "": + default_route(w,req) + return //default: NotFound(w,req) } // A fallback for the routes which haven't been converted to the new router yet router.RLock() handle, ok := router.old_routes[req.URL.Path] + router.RUnlock() + if ok { - router.RUnlock() - req.URL.Path = req.URL.Path + extra_data + req.URL.Path += extra_data handle(w,req) return } - - router.RUnlock() NotFound(w,req) } diff --git a/general_test.go b/general_test.go index 28a6b7dc..29c92ebd 100644 --- a/general_test.go +++ b/general_test.go @@ -688,7 +688,8 @@ func BenchmarkQueriesSerial(b *testing.B) { }) } -func addEmptyRoutesToMux(routes []string, serveMux *http.ServeMux) { +// Commented until I add logic for profiling the router generator, I'm not sure what the best way of doing that is +/*func addEmptyRoutesToMux(routes []string, serveMux *http.ServeMux) { for _, route := range routes { serveMux.HandleFunc(route, func(_ http.ResponseWriter,_ *http.Request){}) } @@ -1012,7 +1013,7 @@ func BenchmarkCustomRouterSerial(b *testing.B) { router.ServeHTTP(w,req) } }) -} +}*/ func BenchmarkParserSerial(b *testing.B) { b.ReportAllocs() diff --git a/main.go b/main.go index 370b2409..e45c6b21 100644 --- a/main.go +++ b/main.go @@ -186,15 +186,12 @@ func main(){ init_plugins() - router := NewRouter() - router.HandleFunc("/static/", route_static)// - fs_u := http.FileServer(http.Dir("./uploads")) - router.Handle("/uploads/", http.StripPrefix("/uploads/",fs_u))// - - router.HandleFunc("/overview/", route_overview)// - router.HandleFunc("/topics/create/", route_topic_create) - router.HandleFunc("/topics/", route_topics)// - router.HandleFunc("/forums/", route_forums)// + router := NewGenRouter(http.FileServer(http.Dir("./uploads"))) + ///router.HandleFunc("/static/", route_static) + ///router.HandleFunc("/overview/", route_overview) + ///router.HandleFunc("/topics/create/", route_topic_create) + ///router.HandleFunc("/topics/", route_topics) + ///router.HandleFunc("/forums/", route_forums) router.HandleFunc("/forum/", route_forum) router.HandleFunc("/topic/create/submit/", route_create_topic) router.HandleFunc("/topic/", route_topic_id) @@ -271,7 +268,7 @@ func main(){ router.HandleFunc("/api/", route_api) //router.HandleFunc("/exit/", route_exit) - router.HandleFunc("/", default_route) + ///router.HandleFunc("/", default_route) defer db.Close() //if profiling { diff --git a/router_gen/build.bat b/router_gen/build.bat new file mode 100644 index 00000000..3e185c54 --- /dev/null +++ b/router_gen/build.bat @@ -0,0 +1,9 @@ +@echo off +echo Building the router generator +go build +if %errorlevel% neq 0 ( + pause + exit /b %errorlevel% +) +echo The router generator was successfully built +pause \ No newline at end of file diff --git a/router_gen/main.go b/router_gen/main.go index d26d1ff8..4090f331 100644 --- a/router_gen/main.go +++ b/router_gen/main.go @@ -19,16 +19,52 @@ func main() { var fdata string = "// Code generated by. DO NOT EDIT.\n/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */\n" for _, route := range route_list { - out += "\n\t\tcase \"" + route.Path + "\": " + route.Name+ "(w,req/*" + var end int + if route.Path[len(route.Path)-1] == '/' { + end = len(route.Path) - 1 + } else { + end = len(route.Path) - 1 + } + out += "\n\t\tcase \"" + route.Path[0:end] + "\":" + if route.Before != "" { + out += "\n\t\t\t" + route.Before + } + out += "\n\t\t\t" + route.Name + "(w,req" for _, item := range route.Vars { out += ", " + item } - out += "*/)" + out += ")\n\t\t\treturn" + } + + for _, group := range route_groups { + var end int + if group.Path[len(group.Path)-1] == '/' { + end = len(group.Path) - 1 + } else { + end = len(group.Path) - 1 + } + out += ` + case "` + group.Path[0:end] + `": + switch(req.URL.Path) {` + for _, route := range group.Routes { + out += "\n\t\t\t\tcase \"" + route.Path + "\":" + if route.Before != "" { + out += "\n\t\t\t\t\t" + route.Before + } + out += "\n\t\t\t\t\t" + route.Name + "(w,req" + for _, item := range route.Vars { + out += ", " + item + } + out += ")\n\t\t\t\t\treturn" + } + out += "\n\t\t\t}" } fdata += `package main +//import "fmt" import "sync" +import "strings" import "net/http" type GenRouter struct { @@ -37,18 +73,14 @@ type GenRouter struct { old_routes map[string]func(http.ResponseWriter, *http.Request) // Temporary Fallback } -func NewGenRouter() *GenRouter { - fs_u := http.FileServer(http.Dir("./uploads")) +func NewGenRouter(uploads http.Handler) *GenRouter { return &GenRouter{ - UploadHandler: http.StripPrefix("/uploads/",fs_u).ServeHTTP, + UploadHandler: http.StripPrefix("/uploads/",uploads).ServeHTTP, old_routes: make(map[string]func(http.ResponseWriter, *http.Request)), } } -func (router *GenRouter) Handle(pattern string, handle http.Handler) { - router.Lock() - router.old_routes[pattern] = handle.ServeHTTP - router.Unlock() +func (router *GenRouter) Handle(_ string, _ http.Handler) { } func (router *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request)) { @@ -58,33 +90,50 @@ func (router *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWri } func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { + //if req.URL.Path == "/" { + // default_route(w,req) + // return + //} if req.URL.Path[0] != '/' { w.WriteHeader(405) w.Write([]byte("")) return } - var extra_data string - /*if req.URL.Path[len(req.URL.Path) - 1] != '/' { + var prefix, extra_data string + prefix = req.URL.Path[0:strings.IndexByte(req.URL.Path[1:],'/') + 1] + if req.URL.Path[len(req.URL.Path) - 1] != '/' { extra_data = req.URL.Path[strings.LastIndexByte(req.URL.Path,'/') + 1:] req.URL.Path = req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/') + 1] - }*/ - switch(req.URL.Path) {` + out + ` - case "/uploads/": router.UploadHandler(w,req) + } + //fmt.Println("prefix:",prefix) + //fmt.Println("req.URL.Path:",req.URL.Path) + //fmt.Println("extra_data:",extra_data) + switch(prefix) {` + out + ` + case "/uploads": + if extra_data == "" { + NotFound(w,req) + return + } + req.URL.Path += extra_data + router.UploadHandler(w,req) + return + case "": + default_route(w,req) + return //default: NotFound(w,req) } // A fallback for the routes which haven't been converted to the new router yet router.RLock() handle, ok := router.old_routes[req.URL.Path] + router.RUnlock() + if ok { - router.RUnlock() - req.URL.Path = req.URL.Path + extra_data + req.URL.Path += extra_data handle(w,req) return } - - router.RUnlock() NotFound(w,req) } ` diff --git a/router_gen/routes.go b/router_gen/routes.go index 45dc0992..fe5489c9 100644 --- a/router_gen/routes.go +++ b/router_gen/routes.go @@ -3,6 +3,7 @@ package main type Route struct { Name string Path string + Before string Vars []string } @@ -11,8 +12,8 @@ type RouteGroup struct { Routes []Route } -func addRoute(fname string, path string, vars ...string) { - route_list = append(route_list,Route{fname,path,vars}) +func addRoute(fname string, path string, before string, vars ...string) { + route_list = append(route_list,Route{fname,path,before,vars}) } func addRouteGroup(path string, routes ...Route) { @@ -20,9 +21,16 @@ func addRouteGroup(path string, routes ...Route) { } func routes() { - addRoute("route_static","/static/","req.URL.Path + extra_data") - addRoute("route_overview","/overview/") - addRoute("route_custom_page","/pages/","&extra_data") - addRoute("route_topics","/topics/","&groups","&forums") - addRoute("route_forums","/forums/","&forums") + //addRoute("default_route","","") + addRoute("route_static","/static/","req.URL.Path += extra_data") + addRoute("route_overview","/overview/","") + addRoute("route_custom_page","/pages/",""/*,"&extra_data"*/) + addRoute("route_forums","/forums/",""/*,"&forums"*/) + + //addRoute("route_topic_create","/topics/create/","","extra_data") + //addRoute("route_topics","/topics/",""/*,"&groups","&forums"*/) + addRouteGroup("/topics/", + Route{"route_topics","/topics/","",[]string{}}, + Route{"route_topic_create","/topics/create/","",[]string{"extra_data"}}, + ) } diff --git a/router_gen/run.bat b/router_gen/run.bat new file mode 100644 index 00000000..a0e97282 --- /dev/null +++ b/router_gen/run.bat @@ -0,0 +1,10 @@ +@echo off +echo Building the router generator +go build +if %errorlevel% neq 0 ( + pause + exit /b %errorlevel% +) +echo The router generator was successfully built +router_gen.exe +pause \ No newline at end of file diff --git a/routes.go b/routes.go index 35227bf9..fa9951a5 100644 --- a/routes.go +++ b/routes.go @@ -25,9 +25,7 @@ var nList []string // GET functions func route_static(w http.ResponseWriter, r *http.Request){ - //name := r.URL.Path[len("/static/"):] //log.Print("Outputting static file '" + r.URL.Path + "'") - file, ok := static_files[r.URL.Path] if !ok { w.WriteHeader(http.StatusNotFound) @@ -542,10 +540,9 @@ func route_profile(w http.ResponseWriter, r *http.Request){ } } -func route_topic_create(w http.ResponseWriter, r *http.Request){ +func route_topic_create(w http.ResponseWriter, r *http.Request, sfid string){ var fid int var err error - sfid := r.URL.Path[len("/topics/create/"):] if sfid != "" { fid, err = strconv.Atoi(sfid) if err != nil {