You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
2.9 KiB
117 lines
2.9 KiB
package router |
|
|
|
// Copyright 2013 Julien Schmidt. All rights reserved. |
|
// Use of this source code is governed by a BSD-style license that can be found |
|
// in the LICENSE file. |
|
// https://github.com/julienschmidt/httprouter |
|
|
|
import ( |
|
"context" |
|
) |
|
|
|
// Handle is a function that can be registered to a route to handle HTTP |
|
// requests. Like http.HandlerFunc, but has a third parameter for the values of |
|
// wildcards (variables). |
|
type Handle func(ns, path string, ps Params) |
|
|
|
// Param is a single URL parameter, consisting of a key and a value. |
|
type Param struct { |
|
Key string |
|
Value string |
|
} |
|
|
|
// Params is a Param-slice, as returned by the router. |
|
// The slice is ordered, the first URL parameter is also the first slice value. |
|
// It is therefore safe to read values by the index. |
|
type Params []Param |
|
|
|
// ByName returns the value of the first Param which key matches the given name. |
|
// If no matching Param is found, an empty string is returned. |
|
func (ps Params) ByName(name string) string { |
|
for i := range ps { |
|
if ps[i].Key == name { |
|
return ps[i].Value |
|
} |
|
} |
|
return "" |
|
} |
|
|
|
type paramsKey struct{} |
|
|
|
// ParamsKey is the request context key under which URL params are stored. |
|
var ParamsKey = paramsKey{} |
|
|
|
// ParamsFromContext pulls the URL parameters from a request context, |
|
// or returns nil if none are present. |
|
func ParamsFromContext(ctx context.Context) Params { |
|
p, _ := ctx.Value(ParamsKey).(Params) |
|
return p |
|
} |
|
|
|
// Router is a http.Handler which can be used to dispatch requests to different |
|
// handler functions via configurable routes |
|
type Router struct { |
|
trees map[string]*node |
|
|
|
// Function to handle panics recovered from handlers. |
|
PanicHandler func(namespace, path string, rev any) |
|
} |
|
|
|
// New returns a new initialized Router. |
|
// Path auto-correction, including trailing slashes, is enabled by default. |
|
func New() *Router { |
|
return &Router{ |
|
// trees: make(map[string]*node), |
|
} |
|
} |
|
|
|
// Route registers a new request handle with the given path and method. |
|
func (r *Router) Route(namespace, path string, handle Handle) { |
|
if len(path) < 1 || path[0] != '/' { |
|
panic("path must begin with '/' in path '" + path + "'") |
|
} |
|
|
|
if r.trees == nil { |
|
r.trees = make(map[string]*node) |
|
} |
|
|
|
root := r.trees[namespace] |
|
if root == nil { |
|
root = new(node) |
|
r.trees[namespace] = root |
|
} |
|
|
|
root.addRoute(path, handle) |
|
} |
|
|
|
// Lookup allows the manual lookup of a namespace + path combo. |
|
func (r *Router) Lookup(namespace, path string) (Handle, Params) { |
|
if r.trees != nil { |
|
if root := r.trees[namespace]; root != nil { |
|
handle, params, _ := root.getValue(path) |
|
return handle, params |
|
} |
|
} |
|
return nil, nil |
|
} |
|
|
|
func (r *Router) recv(ns, path string) { |
|
if rcv := recover(); rcv != nil { |
|
r.PanicHandler(ns, path, rcv) |
|
} |
|
} |
|
|
|
// Handle router and execute handle. |
|
func (r *Router) Handle(ns, path string) (found bool) { |
|
if r.PanicHandler != nil { |
|
defer r.recv(ns, path) |
|
} |
|
|
|
if handle, ps := r.Lookup(ns, path); handle != nil { |
|
found = true |
|
handle(ns, path, ps) |
|
return |
|
} |
|
|
|
return false |
|
}
|
|
|