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

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
}