-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrouter.go
More file actions
128 lines (107 loc) · 3.15 KB
/
router.go
File metadata and controls
128 lines (107 loc) · 3.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// ABOUTME: WebSocket method router with middleware support.
// ABOUTME: Provides group-based routing similar to Gin.
package websocket
import (
"sync"
"github.com/bingo-project/websocket/jsonrpc"
)
// Router routes JSON-RPC methods to handlers with middleware.
type Router struct {
mu sync.RWMutex
middlewares []Middleware
handlers map[string]*handlerEntry
}
type handlerEntry struct {
handler Handler
middlewares []Middleware
compiled Handler // cached compiled handler chain
}
// NewRouter creates a new Router.
func NewRouter() *Router {
return &Router{
handlers: make(map[string]*handlerEntry),
}
}
// Use adds global middleware that applies to all handlers.
func (r *Router) Use(middlewares ...Middleware) *Router {
r.mu.Lock()
defer r.mu.Unlock()
r.middlewares = append(r.middlewares, middlewares...)
// Invalidate compiled handlers
for _, entry := range r.handlers {
entry.compiled = nil
}
return r
}
// Handle registers a handler for a method with optional middlewares.
// Middlewares are applied in order: global -> group -> method-specific.
func (r *Router) Handle(method string, handler Handler, middlewares ...Middleware) {
r.mu.Lock()
defer r.mu.Unlock()
r.handlers[method] = &handlerEntry{
handler: handler,
middlewares: middlewares,
}
}
// Dispatch routes a request to its handler.
func (r *Router) Dispatch(c *Context) *jsonrpc.Response {
r.mu.RLock()
entry, ok := r.handlers[c.Method]
if !ok {
r.mu.RUnlock()
return jsonrpc.NewErrorResponse(c.Request.ID,
NewError(404, "MethodNotFound", "Method not found: %s", c.Method))
}
// Compile handler chain if not cached
if entry.compiled == nil {
r.mu.RUnlock()
r.mu.Lock()
// Double-check after acquiring write lock
if entry.compiled == nil {
all := make([]Middleware, 0, len(r.middlewares)+len(entry.middlewares))
all = append(all, r.middlewares...)
all = append(all, entry.middlewares...)
entry.compiled = Chain(all...)(entry.handler)
}
r.mu.Unlock()
r.mu.RLock()
}
compiled := entry.compiled
r.mu.RUnlock()
return compiled(c)
}
// Methods returns all registered method names.
func (r *Router) Methods() []string {
r.mu.RLock()
defer r.mu.RUnlock()
methods := make([]string, 0, len(r.handlers))
for method := range r.handlers {
methods = append(methods, method)
}
return methods
}
// Group is a collection of handlers with shared middleware.
type Group struct {
router *Router
middlewares []Middleware
}
// Group creates a new handler group with additional middleware.
func (r *Router) Group(middlewares ...Middleware) *Group {
return &Group{
router: r,
middlewares: middlewares,
}
}
// Use adds middleware to this group.
func (g *Group) Use(middlewares ...Middleware) *Group {
g.middlewares = append(g.middlewares, middlewares...)
return g
}
// Handle registers a handler in this group.
func (g *Group) Handle(method string, handler Handler, middlewares ...Middleware) {
// Combine group middlewares with handler-specific middlewares
all := make([]Middleware, 0, len(g.middlewares)+len(middlewares))
all = append(all, g.middlewares...)
all = append(all, middlewares...)
g.router.Handle(method, handler, all...)
}