diff --git a/admin/admin.go b/admin/admin.go index f4db749..046ce0f 100644 --- a/admin/admin.go +++ b/admin/admin.go @@ -6,12 +6,6 @@ import ( "git.pyer.club/kingecg/gohttpd/server" ) -type Route struct { - Method string - Path string - Handle http.HandlerFunc -} - func about(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("About Page")) @@ -22,10 +16,10 @@ func setConfig(w http.ResponseWriter, r *http.Request) { } -var AdminRoutes = []Route{ +var AdminRoutes = []server.Route{ // Admin Routes - {"GET", "/about", about}, - {"Post", "/config", setConfig}, + {Method: "GET", Path: "/about", Handle: about}, + {Method: "Post", Path: "/config", Handle: setConfig}, } var AdminServerMux *server.RestMux diff --git a/server/server.go b/server/server.go index cff0285..51eef4f 100644 --- a/server/server.go +++ b/server/server.go @@ -3,18 +3,82 @@ package server import ( "context" "net/http" + "sort" "strings" - - "github.com/samber/lo" ) type RequestCtxKey string +type Route struct { + Method string + Path string + Handle http.HandlerFunc + Handler http.Handler + matcher *UrlParamMatcher +} + +func (route *Route) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if route.Handler != nil { + route.Handler.ServeHTTP(w, r) + } else { + route.Handle(w, r) + } +} + +func (route *Route) Match(r *http.Request) bool { + if route.Method != "" && route.Method != r.Method { + return false + } + + if route.matcher != nil { + params, matched := MatchUrlParam(r.URL.Path, route.matcher) + if matched { + ctx := r.Context() + data := ctx.Value(RequestCtxKey("data")).(map[string]interface{}) + for _, p := range route.matcher.Params { + data[p] = params[p] + } + return true + } + return false + } + if route.Path == "" { + return true + } + return strings.HasPrefix(r.URL.Path, route.Path) +} + +type Routes []*Route + +func (rs Routes) Less(i, j int) bool { + iPaths := strings.Split(rs[i].Path, "/") + jPaths := strings.Split(rs[j].Path, "/") + if len(iPaths) > len(jPaths) { + return true + } + if len(iPaths) < len(jPaths) { + return false + } + for k := 0; k < len(iPaths); k++ { + if iPaths[k] != jPaths[k] { + return iPaths[k] < jPaths[k] + } + } + return false +} + +func (rs Routes) Len() int { + return len(rs) +} + +func (rs Routes) Swap(i, j int) { + rs[i], rs[j] = rs[j], rs[i] +} + // 可以嵌套的Rest http server mux type RestMux struct { Path string - imux *http.ServeMux - rmuxPaths []string + routes Routes middlewares []Middleware } @@ -37,27 +101,39 @@ func (mux *RestMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { } } - _, has := lo.Find(mux.rmuxPaths, func(s string) bool { - return strings.HasPrefix(newRequest.URL.Path, s) - }) - if has { - mux.imux.ServeHTTP(w, newRequest) - return + // _, has := lo.Find(mux.rmuxPaths, func(s string) bool { + // return strings.HasPrefix(newRequest.URL.Path, s) + // }) + // if has { + // mux.imux.ServeHTTP(w, newRequest) + // return + // } + + // 根据r 从routes中找到匹配的路由 + for _, route := range mux.routes { + if route.Match(newRequest) { + route.ServeHTTP(w, newRequest) + return + } } + // newRequest.URL.Path = "/" + strings.ToLower(newRequest.Method) + newRequest.URL.Path + // newRequest.RequestURI = "/" + strings.ToLower(newRequest.Method) + newRequest.RequestURI + // h, _ := mux.imux.Handler(newRequest) - newRequest.URL.Path = "/" + strings.ToLower(newRequest.Method) + newRequest.URL.Path - newRequest.RequestURI = "/" + strings.ToLower(newRequest.Method) + newRequest.RequestURI - h, _ := mux.imux.Handler(newRequest) - - h.ServeHTTP(w, newRequest) + // h.ServeHTTP(w, newRequest) + http.NotFound(w, r) } func (mux *RestMux) HandleFunc(method string, path string, f func(http.ResponseWriter, *http.Request)) { - m := path - if !strings.HasPrefix(path, "/") { - m = "/" + path + r := &Route{ + Method: method, + Path: path, + Handle: f, + Handler: nil, } - mux.imux.HandleFunc("/"+strings.ToLower(method)+m, f) + *r.matcher = ParseUrl(path) + mux.routes = append(mux.routes, r) + sort.Sort(mux.routes) } func (mux *RestMux) Get(path string, f func(http.ResponseWriter, *http.Request)) { @@ -90,14 +166,26 @@ func (mux *RestMux) HandleMux(nmux *RestMux) { if !strings.HasSuffix(p, "/") { p = p + "/" } - mux.imux.Handle(p, http.StripPrefix(nmux.Path, nmux)) - mux.rmuxPaths = append(mux.rmuxPaths, nmux.Path) + // mux.imux.Handle(p, http.StripPrefix(nmux.Path, nmux)) + // mux.rmuxPaths = append(mux.rmuxPaths, nmux.Path) + r := &Route{ + Method: "", + Path: p, + Handle: nil, + Handler: nmux, + } + r.matcher = &UrlParamMatcher{ + Params: []string{}, + Reg: nil, + } + sort.Sort(mux.routes) } func NewRestMux(path string) *RestMux { - return &RestMux{ - Path: path, - imux: http.NewServeMux(), - rmuxPaths: make([]string, 0), + ret := &RestMux{ + Path: path, + routes: Routes{}, + middlewares: []Middleware{}, } + return ret }