20 Star 164 Fork 26

qiqi / orange

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
route.go 8.19 KB
一键复制 编辑 原始数据 按行查看 历史
package app
import (
"gitee.com/zhucheer/orange/internal"
"net/http"
"strings"
"sync"
)
const (
skind kind = iota // static
pkind // param
akind // any
)
type (
RouterGroup struct {
prefix string
middlewares []MiddleWare
}
Router struct {
tree *node
maxParam *int
middlewareMap map[string][]MiddleWare
lock sync.RWMutex
}
node struct {
kind kind
label byte
prefix string
parent *node
children children
ppath string
pnames []string
methodHandler *methodHandler
}
kind uint8
children []*node
methodHandler struct {
connect HandlerFunc
delete HandlerFunc
get HandlerFunc
head HandlerFunc
options HandlerFunc
patch HandlerFunc
post HandlerFunc
put HandlerFunc
trace HandlerFunc
grpc HandlerFunc
any HandlerFunc
}
customHttpHandler struct {
patten string
handler http.Handler
}
)
var routers = &Router{
tree: &node{
methodHandler: new(methodHandler),
},
middlewareMap: make(map[string][]MiddleWare),
maxParam: new(int),
}
// 自定义httpHandler
var httpHandlerList []customHttpHandler
// 静态资源目录
var assetsHandlerList []customHttpHandler
func NewRouter(prefix string, middlewares ...MiddleWare) *RouterGroup {
middlewares = reverseMiddleWare(middlewares)
return &RouterGroup{
prefix: prefix,
middlewares: middlewares,
}
}
func NewHttpHandler(patten string, handler http.Handler) {
httpHandlerList = append(httpHandlerList, customHttpHandler{patten, handler})
}
func NewAssetsHandler(patten string, filePath string, autoindex FileServerType) {
patten = "/" + strings.Trim(patten, "/") + "/"
if autoindex == AutoIndex {
assetsHandlerList = append(assetsHandlerList, customHttpHandler{
patten,
http.StripPrefix(patten, http.FileServer(http.Dir(filePath))),
})
} else {
assetsHandler := noDirListingHandler(http.StripPrefix(patten, http.FileServer(http.Dir(filePath))), patten, filePath)
assetsHandlerList = append(assetsHandlerList, customHttpHandler{patten, assetsHandler})
}
}
// GroupRouter 子群组路由
func (r *RouterGroup) GroupRouter(prefix string, middlewares ...MiddleWare) *RouterGroup {
prefix = r.prefix + prefix
middlewaresNew := append(middlewares, r.middlewares...)
return &RouterGroup{
prefix: prefix,
middlewares: middlewaresNew,
}
}
// Assets 注册静态资源目录
func (r *RouterGroup) ASSETS(patten string, fielPath string, autoindex FileServerType) {
patten = strings.TrimRight(r.prefix+patten, "/")
NewAssetsHandler(patten, fielPath, autoindex)
}
// GET 注册 get 请求
func (r *RouterGroup) GET(patten string, handler func(ctx *Context) error) {
r.appRoute("GET", patten, handler)
}
// POST 注册 post 请求
func (r *RouterGroup) POST(patten string, handler func(ctx *Context) error) {
r.appRoute("POST", patten, handler)
}
// PUT 注册 put 请求
func (r *RouterGroup) PUT(patten string, handler func(ctx *Context) error) {
r.appRoute("PUT", patten, handler)
}
// PATCH 注册 patch 请求
func (r *RouterGroup) PATCH(patten string, handler func(ctx *Context) error) {
r.appRoute(http.MethodPatch, patten, handler)
}
// OPTION 注册 option 请求
func (r *RouterGroup) OPTION(patten string, handler func(ctx *Context) error) {
r.appRoute("OPTION", patten, handler)
}
// DELETE 注册 delete 请求
func (r *RouterGroup) DELETE(patten string, handler func(ctx *Context) error) {
r.appRoute("DELETE", patten, handler)
}
//GRPC 注册 grpc 请求,只有grpc客户端才能调用
func (r *RouterGroup) GRPC(patten string, handler func(ctx *Context) error) {
r.appRoute(methodGRPC, patten, handler)
}
// ALL 兼容所有请求
func (r *RouterGroup) ALL(patten string, handler func(ctx *Context) error) {
r.appRoute("ALL", patten, handler)
}
// addRoute 添加路由信息
func (r *RouterGroup) appRoute(method string, patten string, h HandlerFunc) {
patten = strings.TrimRight(r.prefix+patten, "/")
// Validate patten
if patten == "" {
patten = "/"
}
if patten[0] != '/' {
patten = "/" + patten
}
internal.ConsoleRouter(method, patten)
pnames := []string{} // Param names
ppath := patten // Pristine path
for i, l := 0, len(patten); i < l; i++ {
if patten[i] == ':' {
j := i + 1
r.insert(method, patten[:i], nil, skind, "", nil, nil)
for ; i < l && patten[i] != '/'; i++ {
}
pnames = append(pnames, patten[j:i])
patten = patten[:j] + patten[i:]
i, l = j, len(patten)
if i == l {
r.insert(method, patten[:i], h, pkind, ppath, pnames, r.middlewares)
return
}
r.insert(method, patten[:i], nil, pkind, "", nil, nil)
} else if patten[i] == '*' {
r.insert(method, patten[:i], nil, skind, "", nil, nil)
pnames = append(pnames, "*")
r.insert(method, patten[:i+1], h, akind, ppath, pnames, r.middlewares)
return
}
}
r.insert(method, patten, h, skind, ppath, pnames, r.middlewares)
}
func (r *RouterGroup) appendMiddleware(ppath string, m []MiddleWare) {
if ppath == "" || len(m) == 0 {
return
}
routers.lock.Lock()
defer routers.lock.Unlock()
routers.middlewareMap[ppath] = m
}
func (r *RouterGroup) insert(method, patten string, h HandlerFunc, t kind, ppath string, pnames []string, m []MiddleWare) {
//save middleware
r.appendMiddleware(ppath, m)
// Adjust max param
l := len(pnames)
if *routers.maxParam < l {
*routers.maxParam = l
}
cn := routers.tree // Current node as root
if cn == nil {
panic("orange: invalid method")
}
search := patten
for {
sl := len(search)
pl := len(cn.prefix)
l := 0
// LCP
max := pl
if sl < max {
max = sl
}
for ; l < max && search[l] == cn.prefix[l]; l++ {
}
if l == 0 {
// At root node
cn.label = search[0]
cn.prefix = search
if h != nil {
cn.kind = t
cn.addHandlerAndMiddleware(method, h)
cn.ppath = ppath
cn.pnames = pnames
}
} else if l < pl {
// Split node
n := newNode(cn.kind, cn.prefix[l:], cn, cn.children, cn.methodHandler, cn.ppath, cn.pnames)
// Reset parent node
cn.kind = skind
cn.label = cn.prefix[0]
cn.prefix = cn.prefix[:l]
cn.children = nil
cn.methodHandler = new(methodHandler)
cn.ppath = ""
cn.pnames = nil
cn.addChild(n)
if l == sl {
// At parent node
cn.kind = t
cn.addHandlerAndMiddleware(method, h)
cn.ppath = ppath
cn.pnames = pnames
} else {
// Create child node
n = newNode(t, search[l:], cn, nil, new(methodHandler), ppath, pnames)
n.addHandlerAndMiddleware(method, h)
cn.addChild(n)
}
} else if l < sl {
search = search[l:]
c := cn.findChildWithLabel(search[0])
if c != nil {
cn = c
continue
}
// Create child node
n := newNode(t, search, cn, nil, new(methodHandler), ppath, pnames)
n.addHandlerAndMiddleware(method, h)
cn.addChild(n)
} else {
// Node already exists
if h != nil {
cn.addHandlerAndMiddleware(method, h)
cn.ppath = ppath
if len(cn.pnames) == 0 {
cn.pnames = pnames
}
}
}
return
}
}
func (n *node) findChildWithLabel(l byte) *node {
for _, c := range n.children {
if c.label == l {
return c
}
}
return nil
}
func (n *node) addChild(c *node) {
n.children = append(n.children, c)
}
func (n *node) addHandlerAndMiddleware(method string, h HandlerFunc) {
switch method {
case methodGRPC:
n.methodHandler.grpc = h
case http.MethodConnect:
n.methodHandler.connect = h
case http.MethodDelete:
n.methodHandler.delete = h
case http.MethodGet:
n.methodHandler.get = h
case http.MethodHead:
n.methodHandler.head = h
case http.MethodOptions:
n.methodHandler.options = h
case http.MethodPatch:
n.methodHandler.patch = h
case http.MethodPost:
n.methodHandler.post = h
case http.MethodPut:
n.methodHandler.put = h
case http.MethodTrace:
n.methodHandler.trace = h
case "ALL":
n.methodHandler.any = h
}
}
func newNode(t kind, pre string, p *node, c children, mh *methodHandler, ppath string, pnames []string) *node {
return &node{
kind: t,
label: pre[0],
prefix: pre,
parent: p,
children: c,
ppath: ppath,
pnames: pnames,
methodHandler: mh,
}
}
func getPath(r *http.Request) string {
path := r.URL.RawPath
if path == "" {
path = r.URL.Path
}
return path
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/zhucheer/orange.git
git@gitee.com:zhucheer/orange.git
zhucheer
orange
orange
v0.5.1

搜索帮助

344bd9b3 5694891 D2dac590 5694891