package nf import ( "net/http" "strings" ) type router struct { roots map[string]*node handlers map[string][]HandlerFunc } // roots key eg, roots['GET'] roots['POST'] // handlers key eg, handlers['GET-/p/:lang/doc'], handlers['POST-/p/book'] func newRouter() *router { return &router{ roots: make(map[string]*node), handlers: make(map[string][]HandlerFunc), } } // Only one * is allowed func parsePattern(pattern string) []string { vs := strings.Split(pattern, "/") parts := make([]string, 0) for _, item := range vs { if item != "" { parts = append(parts, item) if item[0] == '*' { break } } } return parts } func (r *router) addRoute(method string, pattern string, handlers ...HandlerFunc) { parts := parsePattern(pattern) key := method + "-" + pattern _, ok := r.roots[method] if !ok { r.roots[method] = &node{} } r.roots[method].insert(pattern, parts, 0) r.handlers[key] = handlers } func (r *router) getRoute(method string, path string) (*node, map[string]string) { searchParts := parsePattern(path) params := make(map[string]string) root, ok := r.roots[method] if !ok { return nil, nil } n := root.search(searchParts, 0) if n != nil { parts := parsePattern(n.pattern) for index, part := range parts { if part[0] == ':' { params[part[1:]] = searchParts[index] } if part[0] == '*' && len(part) > 1 { params[part[1:]] = strings.Join(searchParts[index:], "/") break } } return n, params } return nil, nil } func (r *router) handle(c *Ctx) error { n, params := r.getRoute(c.Method, c.Path) if n != nil { c.Params = params key := c.Method + "-" + n.pattern for _, handler := range r.handlers[key] { err := handler(c) if err != nil { return err } } } else { c.Status(http.StatusNotFound) return c.SendString("Not Found") } return nil }