diff options
author | tjpcc <tjp@ctrl-c.club> | 2023-02-02 17:11:27 -0700 |
---|---|---|
committer | tjpcc <tjp@ctrl-c.club> | 2023-02-02 17:11:27 -0700 |
commit | 18d69173b4e23a2edd8c07c35f7a5b927587e6d7 (patch) | |
tree | 32b5bd4996607a21c536d9b3ed54f5b57b598022 | |
parent | ac024567e880f0da59557f0051018f4ac932c6ad (diff) |
Mount() adds a subrouter under a prefix pattern.
...though I'm already eyeing a better approach.
-rw-r--r-- | router.go | 50 |
1 files changed, 50 insertions, 0 deletions
@@ -2,6 +2,9 @@ package gus import ( "context" + "crypto/tls" + "net/url" + "strings" "tildegit.org/tjp/gus/internal" ) @@ -42,6 +45,16 @@ func (r Router) Handler(ctx context.Context, request *Request) *Response { return nil } + // as we may be a sub-router, check for existing stashed params + // and combine with that map if found. + priorParams := RouteParams(ctx) + for k, v := range priorParams { + if k == subrouterPathKey { + continue + } + params[k] = v + } + return handler(context.WithValue(ctx, routeParamsKey, params), request) } @@ -54,6 +67,26 @@ func (r Router) Match(request *Request) (Handler, map[string]string) { return *handler, params } +// Mount attaches a sub-router to handle path suffixes after an initial prefix pattern. +// +// The prefix pattern may include segment :wildcards, but no *remainder segment. The +// mounted sub-router should have patterns which only include the portion of the path +// after whatever was matched by the prefix pattern. +func (r Router) Mount(prefix string, subrouter *Router) { + prefix = strings.TrimSuffix(prefix, "/") + r.Route(prefix+"/*"+subrouterPathKey, func(ctx context.Context, request *Request) *Response { + r := cloneRequest(request) + r.Path = "/" + RouteParams(ctx)[subrouterPathKey] + return subrouter.Handler(ctx, r) + }) + + // TODO: better approach. the above works but it's a little hacky + // - add a method to PathTree that returns all the registered patterns + // and their associated handlers + // - have Mount pull those out of the subrouter, prepend the prefix to + // all its patterns, and re-add them to the parent router. +} + // RouteParams gathers captured path parameters from the request context. // // If the context doesn't contain a parameter map, it returns nil. @@ -66,6 +99,23 @@ func RouteParams(ctx context.Context) map[string]string { return nil } +const subrouterPathKey = "subrouter_path" + type routeParamsKeyType struct{} var routeParamsKey = routeParamsKeyType{} + +func cloneRequest(start *Request) *Request { + end := &Request{} + *end = *start + + end.URL = &url.URL{} + *end.URL = *start.URL + + if start.TLSState != nil { + end.TLSState = &tls.ConnectionState{} + *end.TLSState = *start.TLSState + } + + return end +} |