refl: add hono Context
This commit is contained in:
+94
-83
@@ -3,78 +3,95 @@ module hono
|
||||
import net.urllib
|
||||
import net.http
|
||||
|
||||
struct Router {
|
||||
// Context 路由器
|
||||
struct ContextRouter {
|
||||
mut:
|
||||
handlers struct {
|
||||
mut:
|
||||
get []IRequestHandler
|
||||
post []IRequestHandler
|
||||
put []IRequestHandler
|
||||
delete []IRequestHandler
|
||||
patch []IRequestHandler
|
||||
head []IRequestHandler
|
||||
options []IRequestHandler
|
||||
get []IHandler
|
||||
post []IHandler
|
||||
put []IHandler
|
||||
delete []IHandler
|
||||
patch []IHandler
|
||||
head []IHandler
|
||||
options []IHandler
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Hono {
|
||||
mut:
|
||||
server http.Server = http.Server{}
|
||||
router Router = Router{}
|
||||
routes map[string] Hono = {}
|
||||
base_path string
|
||||
pub mut:
|
||||
hybrid_router HybridRouter
|
||||
trie_router TrieRouter
|
||||
middlewares []Middleware
|
||||
context_router ContextRouter = ContextRouter{}
|
||||
context_hybrid_router ContextHybridRouter
|
||||
context_trie_router ContextTrieRouter
|
||||
context_middlewares []ContextMiddleware
|
||||
}
|
||||
|
||||
pub fn (mut app Hono) get(path string, handler fn (Request) http.Response) {
|
||||
h := RequestHandler{
|
||||
// Context 中间件类型
|
||||
type ContextMiddleware = fn (mut c Context, next fn (mut Context) http.Response) http.Response
|
||||
|
||||
// Context 接口方法
|
||||
pub fn (mut app Hono) get(path string, handler fn (mut Context) http.Response) {
|
||||
h := ContextHandler{
|
||||
path: path
|
||||
handler: handler
|
||||
}
|
||||
app.hybrid_router.add_route('GET', h, '')
|
||||
app.trie_router.add_route('GET', path, h)
|
||||
app.context_hybrid_router.add_route('GET', h, '')
|
||||
app.context_trie_router.add_route('GET', path, h)
|
||||
app.context_router.handlers.get << h
|
||||
}
|
||||
|
||||
pub fn (mut app Hono) post(path string, handler fn (Request) http.Response) {
|
||||
h := RequestHandler{
|
||||
pub fn (mut app Hono) post(path string, handler fn (mut Context) http.Response) {
|
||||
h := ContextHandler{
|
||||
path: path
|
||||
handler: handler
|
||||
}
|
||||
app.hybrid_router.add_route('POST', h, '')
|
||||
app.trie_router.add_route('POST', path, h)
|
||||
app.context_hybrid_router.add_route('POST', h, '')
|
||||
app.context_trie_router.add_route('POST', path, h)
|
||||
app.context_router.handlers.post << h
|
||||
}
|
||||
|
||||
pub fn (mut app Hono) put(path string, handler fn (Request) http.Response) {
|
||||
handlers := RequestHandler{path, handler}
|
||||
app.router.handlers.put << handlers
|
||||
app.hybrid_router.add_route('PUT', handlers, app.base_path)
|
||||
pub fn (mut app Hono) put(path string, handler fn (mut Context) http.Response) {
|
||||
h := ContextHandler{path, handler}
|
||||
app.context_router.handlers.put << h
|
||||
app.context_hybrid_router.add_route('PUT', h, app.base_path)
|
||||
app.context_trie_router.add_route('PUT', path, h)
|
||||
}
|
||||
|
||||
pub fn (mut app Hono) delete(path string, handler fn (Request) http.Response) {
|
||||
handlers := RequestHandler{path, handler}
|
||||
app.router.handlers.delete << handlers
|
||||
app.hybrid_router.add_route('DELETE', handlers, app.base_path)
|
||||
pub fn (mut app Hono) delete(path string, handler fn (mut Context) http.Response) {
|
||||
h := ContextHandler{path, handler}
|
||||
app.context_router.handlers.delete << h
|
||||
app.context_hybrid_router.add_route('DELETE', h, app.base_path)
|
||||
app.context_trie_router.add_route('DELETE', path, h)
|
||||
}
|
||||
|
||||
pub fn (mut app Hono) patch(path string, handler fn (Request) http.Response) {
|
||||
handlers := RequestHandler{path, handler}
|
||||
app.router.handlers.patch << handlers
|
||||
app.hybrid_router.add_route('PATCH', handlers, app.base_path)
|
||||
pub fn (mut app Hono) patch(path string, handler fn (mut Context) http.Response) {
|
||||
h := ContextHandler{path, handler}
|
||||
app.context_router.handlers.patch << h
|
||||
app.context_hybrid_router.add_route('PATCH', h, app.base_path)
|
||||
app.context_trie_router.add_route('PATCH', path, h)
|
||||
}
|
||||
|
||||
pub fn (mut app Hono) head(path string, handler fn (Request) http.Response) {
|
||||
handlers := RequestHandler{path, handler}
|
||||
app.router.handlers.head << handlers
|
||||
app.hybrid_router.add_route('HEAD', handlers, app.base_path)
|
||||
pub fn (mut app Hono) head(path string, handler fn (mut Context) http.Response) {
|
||||
h := ContextHandler{path, handler}
|
||||
app.context_router.handlers.head << h
|
||||
app.context_hybrid_router.add_route('HEAD', h, app.base_path)
|
||||
app.context_trie_router.add_route('HEAD', path, h)
|
||||
}
|
||||
|
||||
pub fn (mut app Hono) options(path string, handler fn (Request) http.Response) {
|
||||
handlers := RequestHandler{path, handler}
|
||||
app.router.handlers.options << handlers
|
||||
app.hybrid_router.add_route('OPTIONS', handlers, app.base_path)
|
||||
pub fn (mut app Hono) options(path string, handler fn (mut Context) http.Response) {
|
||||
h := ContextHandler{path, handler}
|
||||
app.context_router.handlers.options << h
|
||||
app.context_hybrid_router.add_route('OPTIONS', h, app.base_path)
|
||||
app.context_trie_router.add_route('OPTIONS', path, h)
|
||||
}
|
||||
|
||||
// Context 中间件
|
||||
pub fn (mut app Hono) use(mw ContextMiddleware) {
|
||||
app.context_middlewares << mw
|
||||
}
|
||||
|
||||
struct ServerHanler {
|
||||
@@ -88,12 +105,6 @@ fn server_hanler_new(app Hono) ServerHanler {
|
||||
}
|
||||
}
|
||||
|
||||
type Middleware = fn (mut req Request, next fn (mut Request) http.Response) http.Response
|
||||
|
||||
pub fn (mut app Hono) use(mw Middleware) {
|
||||
app.middlewares << mw
|
||||
}
|
||||
|
||||
fn (mut s ServerHanler) handle(req http.Request) http.Response {
|
||||
mut res := http.Response{
|
||||
status_code: 404
|
||||
@@ -104,7 +115,9 @@ fn (mut s ServerHanler) handle(req http.Request) http.Response {
|
||||
path: '/'
|
||||
}
|
||||
}
|
||||
if route_match := s.app.hybrid_router.match_route(req.method.str(), url.path) {
|
||||
|
||||
// 尝试 Context 路由
|
||||
if route_match := s.app.context_hybrid_router.match_route(req.method.str(), url.path) {
|
||||
// 解析 query
|
||||
raw_query := url.query().to_map()
|
||||
mut query_map := map[string]string{}
|
||||
@@ -117,29 +130,25 @@ fn (mut s ServerHanler) handle(req http.Request) http.Response {
|
||||
param_map := route_match.params.clone()
|
||||
// body
|
||||
body := req.data
|
||||
// 构造 hono.Request
|
||||
mut hreq := Request{
|
||||
url: url.path
|
||||
param: param_map
|
||||
query: query_map
|
||||
body: body
|
||||
}
|
||||
// 构造 Context
|
||||
mut ctx := Context.new(req, param_map, query_map, body)
|
||||
// 洋葱模型递归执行中间件
|
||||
return s.exec_middlewares(0, mut hreq, fn [route_match] (req Request) http.Response {
|
||||
return route_match.handler.handle(req)
|
||||
return s.exec_context_middlewares(0, mut ctx, fn [route_match] (mut c Context) http.Response {
|
||||
return route_match.handler.handle(mut c)
|
||||
})
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
fn (mut s ServerHanler) exec_middlewares(idx int, mut req Request, handler fn (Request) http.Response) http.Response {
|
||||
if idx < s.app.middlewares.len {
|
||||
mw := s.app.middlewares[idx]
|
||||
return mw(mut req, fn [mut s, idx, handler] (mut r Request) http.Response {
|
||||
return s.exec_middlewares(idx+1, mut r, handler)
|
||||
// Context 版本的中间件执行函数
|
||||
fn (mut s ServerHanler) exec_context_middlewares(idx int, mut ctx Context, handler fn (mut Context) http.Response) http.Response {
|
||||
if idx < s.app.context_middlewares.len {
|
||||
mw := s.app.context_middlewares[idx]
|
||||
return mw(mut ctx, fn [mut s, idx, handler] (mut c Context) http.Response {
|
||||
return s.exec_context_middlewares(idx+1, mut c, handler)
|
||||
})
|
||||
} else {
|
||||
return handler(req)
|
||||
return handler(mut ctx)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,27 +162,27 @@ pub fn (mut app Hono) route(prefix string, mut subapp Hono) {
|
||||
// 简化路由合并,直接添加所有处理器
|
||||
app.routes[prefix] = subapp
|
||||
|
||||
// 将子应用的路由添加到主应用
|
||||
for handler in subapp.router.handlers.get {
|
||||
app.router.handlers.get << handler
|
||||
// 合并 Context 路由
|
||||
for handler in subapp.context_router.handlers.get {
|
||||
app.context_router.handlers.get << handler
|
||||
}
|
||||
for handler in subapp.router.handlers.post {
|
||||
app.router.handlers.post << handler
|
||||
for handler in subapp.context_router.handlers.post {
|
||||
app.context_router.handlers.post << handler
|
||||
}
|
||||
for handler in subapp.router.handlers.put {
|
||||
app.router.handlers.put << handler
|
||||
for handler in subapp.context_router.handlers.put {
|
||||
app.context_router.handlers.put << handler
|
||||
}
|
||||
for handler in subapp.router.handlers.delete {
|
||||
app.router.handlers.delete << handler
|
||||
for handler in subapp.context_router.handlers.delete {
|
||||
app.context_router.handlers.delete << handler
|
||||
}
|
||||
for handler in subapp.router.handlers.patch {
|
||||
app.router.handlers.patch << handler
|
||||
for handler in subapp.context_router.handlers.patch {
|
||||
app.context_router.handlers.patch << handler
|
||||
}
|
||||
for handler in subapp.router.handlers.head {
|
||||
app.router.handlers.head << handler
|
||||
for handler in subapp.context_router.handlers.head {
|
||||
app.context_router.handlers.head << handler
|
||||
}
|
||||
for handler in subapp.router.handlers.options {
|
||||
app.router.handlers.options << handler
|
||||
for handler in subapp.context_router.handlers.options {
|
||||
app.context_router.handlers.options << handler
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,23 +190,25 @@ pub fn (mut app Hono) set_base_path(base_path string) {
|
||||
app.base_path = base_path
|
||||
}
|
||||
|
||||
// 路由统计信息
|
||||
pub fn (app Hono) get_router_stats() (int, int, int, int) {
|
||||
static_paths, dynamic_paths := app.hybrid_router.get_all_routes()
|
||||
cache_size, cache_capacity := app.hybrid_router.get_cache_stats()
|
||||
static_paths, dynamic_paths := app.context_hybrid_router.get_all_routes()
|
||||
cache_size, cache_capacity := app.context_hybrid_router.get_cache_stats()
|
||||
return static_paths.len, dynamic_paths.len, cache_size, cache_capacity
|
||||
}
|
||||
|
||||
// 清理缓存
|
||||
pub fn (mut app Hono) clear_cache() {
|
||||
app.hybrid_router.clear_cache()
|
||||
app.context_hybrid_router.clear_cache()
|
||||
}
|
||||
|
||||
pub fn new_hono() Hono {
|
||||
return Hono{
|
||||
server: http.Server{}
|
||||
router: Router{}
|
||||
routes: map[string]Hono{}
|
||||
base_path: ''
|
||||
hybrid_router: new_hybrid_router()
|
||||
trie_router: new_trie_router()
|
||||
context_router: ContextRouter{}
|
||||
context_hybrid_router: ContextHybridRouter.new()
|
||||
context_trie_router: ContextTrieRouter.new()
|
||||
}
|
||||
}
|
||||
|
||||
+119
-46
@@ -1,65 +1,138 @@
|
||||
module hono
|
||||
|
||||
// 简化的LRU缓存实现
|
||||
pub struct LRUCache {
|
||||
mut:
|
||||
capacity int
|
||||
cache map[string]RouteMatch
|
||||
keys []string // 维护访问顺序
|
||||
// Context LRU 缓存节点
|
||||
@[heap]
|
||||
struct ContextLRUCacheNode {
|
||||
pub mut:
|
||||
key string
|
||||
value ContextRouteMatch
|
||||
prev &ContextLRUCacheNode = unsafe { nil }
|
||||
next &ContextLRUCacheNode = unsafe { nil }
|
||||
}
|
||||
|
||||
// Context LRU 缓存
|
||||
pub struct ContextLRUCache {
|
||||
mut:
|
||||
capacity int
|
||||
size int
|
||||
cache map[string]&ContextLRUCacheNode
|
||||
head &ContextLRUCacheNode = unsafe { nil }
|
||||
tail &ContextLRUCacheNode = unsafe { nil }
|
||||
}
|
||||
|
||||
|
||||
pub fn new_lru_cache(capacity int) LRUCache {
|
||||
return LRUCache{
|
||||
// ContextLRUCache 构造函数
|
||||
pub fn ContextLRUCache.new(capacity int) ContextLRUCache {
|
||||
return ContextLRUCache{
|
||||
capacity: capacity
|
||||
cache: map[string]RouteMatch{}
|
||||
keys: []string{}
|
||||
size: 0
|
||||
cache: map[string]&ContextLRUCacheNode{}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut cache LRUCache) get(key string) ?RouteMatch {
|
||||
if key in cache.cache {
|
||||
// 移动到列表末尾(最近使用)
|
||||
idx := cache.keys.index(key)
|
||||
if idx != -1 {
|
||||
cache.keys.delete(idx)
|
||||
}
|
||||
cache.keys << key
|
||||
return cache.cache[key]
|
||||
// 获取缓存值
|
||||
pub fn (mut cache ContextLRUCache) get(key string) ?ContextRouteMatch {
|
||||
if mut node := cache.cache[key] {
|
||||
cache.move_to_front(mut node)
|
||||
return node.value
|
||||
}
|
||||
return none
|
||||
}
|
||||
|
||||
pub fn (mut cache LRUCache) put(key string, value RouteMatch) {
|
||||
if key in cache.cache {
|
||||
// 更新现有项
|
||||
cache.cache[key] = value
|
||||
// 移动到列表末尾
|
||||
idx := cache.keys.index(key)
|
||||
if idx != -1 {
|
||||
cache.keys.delete(idx)
|
||||
}
|
||||
cache.keys << key
|
||||
} else {
|
||||
// 添加新项
|
||||
cache.cache[key] = value
|
||||
cache.keys << key
|
||||
|
||||
// 如果超出容量,删除最久未使用的项
|
||||
if cache.cache.len > cache.capacity {
|
||||
oldest_key := cache.keys[0]
|
||||
cache.cache.delete(oldest_key)
|
||||
cache.keys.delete(0)
|
||||
}
|
||||
// 设置缓存值
|
||||
pub fn (mut cache ContextLRUCache) put(key string, value ContextRouteMatch) {
|
||||
if mut node := cache.cache[key] {
|
||||
node.value = value
|
||||
cache.move_to_front(mut node)
|
||||
return
|
||||
}
|
||||
|
||||
if cache.size >= cache.capacity {
|
||||
cache.remove_tail()
|
||||
}
|
||||
|
||||
mut new_node := &ContextLRUCacheNode{
|
||||
key: key
|
||||
value: value
|
||||
}
|
||||
|
||||
cache.cache[key] = new_node
|
||||
cache.add_to_front(mut new_node)
|
||||
cache.size++
|
||||
}
|
||||
|
||||
// 移动到链表头部
|
||||
fn (mut cache ContextLRUCache) move_to_front(mut node ContextLRUCacheNode) {
|
||||
if node == cache.head {
|
||||
return
|
||||
}
|
||||
|
||||
// 从当前位置移除
|
||||
if node.prev != unsafe { nil } {
|
||||
mut prev := node.prev
|
||||
prev.next = node.next
|
||||
}
|
||||
if node.next != unsafe { nil } {
|
||||
mut next := node.next
|
||||
next.prev = node.prev
|
||||
}
|
||||
|
||||
// 如果是尾节点
|
||||
if node == cache.tail {
|
||||
cache.tail = node.prev
|
||||
}
|
||||
|
||||
cache.add_to_front(mut node)
|
||||
}
|
||||
|
||||
// 添加到链表头部
|
||||
fn (mut cache ContextLRUCache) add_to_front(mut node ContextLRUCacheNode) {
|
||||
node.next = cache.head
|
||||
node.prev = unsafe { nil }
|
||||
|
||||
if cache.head != unsafe { nil } {
|
||||
mut head := cache.head
|
||||
head.prev = node
|
||||
}
|
||||
|
||||
cache.head = node
|
||||
|
||||
if cache.tail == unsafe { nil } {
|
||||
cache.tail = node
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut cache LRUCache) clear() {
|
||||
cache.cache.clear()
|
||||
cache.keys.clear()
|
||||
// 移除链表尾部
|
||||
fn (mut cache ContextLRUCache) remove_tail() {
|
||||
if cache.tail == unsafe { nil } {
|
||||
return
|
||||
}
|
||||
|
||||
key := cache.tail.key
|
||||
cache.cache.delete(key)
|
||||
|
||||
if cache.head == cache.tail {
|
||||
cache.head = unsafe { nil }
|
||||
cache.tail = unsafe { nil }
|
||||
} else {
|
||||
cache.tail = cache.tail.prev
|
||||
if cache.tail != unsafe { nil } {
|
||||
mut tail := cache.tail
|
||||
tail.next = unsafe { nil }
|
||||
}
|
||||
}
|
||||
|
||||
cache.size--
|
||||
}
|
||||
|
||||
pub fn (cache LRUCache) size() int {
|
||||
return cache.cache.len
|
||||
// 获取缓存统计信息
|
||||
pub fn (cache ContextLRUCache) get_stats() (int, int) {
|
||||
return cache.size, cache.capacity
|
||||
}
|
||||
|
||||
// 清理缓存
|
||||
pub fn (mut cache ContextLRUCache) clear() {
|
||||
cache.cache.clear()
|
||||
cache.head = unsafe { nil }
|
||||
cache.tail = unsafe { nil }
|
||||
cache.size = 0
|
||||
}
|
||||
+77
-16
@@ -2,31 +2,92 @@ module hono
|
||||
|
||||
import net.http
|
||||
|
||||
pub struct Request {
|
||||
// Context 结构体,类似 Hono.js 的实现
|
||||
pub struct Context {
|
||||
pub:
|
||||
url string
|
||||
param map[string]string
|
||||
query map[string]string
|
||||
body string
|
||||
req http.Request
|
||||
params map[string]string
|
||||
query map[string]string
|
||||
url string
|
||||
pub mut:
|
||||
status_code int = 200
|
||||
headers map[string]string
|
||||
body string
|
||||
}
|
||||
|
||||
// 接口定义,允许异构的泛型处理器
|
||||
pub interface IRequestHandler {
|
||||
// Context 构造函数
|
||||
pub fn Context.new(req http.Request, params map[string]string, query map[string]string, body string) Context {
|
||||
return Context{
|
||||
req: req
|
||||
params: params
|
||||
query: query
|
||||
body: body
|
||||
url: req.url
|
||||
headers: map[string]string{}
|
||||
}
|
||||
}
|
||||
|
||||
// Context 的便捷方法 - 直接返回 http.Response
|
||||
pub fn (mut c Context) json(data string) http.Response {
|
||||
mut headers := http.new_header()
|
||||
headers.add_custom('Content-Type', 'application/json; charset=utf-8') or { }
|
||||
for key, value in c.headers {
|
||||
headers.add_custom(key, value) or { continue }
|
||||
}
|
||||
return http.Response{
|
||||
status_code: c.status_code
|
||||
header: headers
|
||||
body: data
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut c Context) text(data string) http.Response {
|
||||
mut headers := http.new_header()
|
||||
headers.add_custom('Content-Type', 'text/plain; charset=utf-8') or { }
|
||||
for key, value in c.headers {
|
||||
headers.add_custom(key, value) or { continue }
|
||||
}
|
||||
return http.Response{
|
||||
status_code: c.status_code
|
||||
header: headers
|
||||
body: data
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut c Context) html(data string) http.Response {
|
||||
mut headers := http.new_header()
|
||||
headers.add_custom('Content-Type', 'text/html; charset=utf-8') or { }
|
||||
for key, value in c.headers {
|
||||
headers.add_custom(key, value) or { continue }
|
||||
}
|
||||
return http.Response{
|
||||
status_code: c.status_code
|
||||
header: headers
|
||||
body: data
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut c Context) status(code int) {
|
||||
c.status_code = code
|
||||
}
|
||||
|
||||
// 处理器接口,使用 Context
|
||||
pub interface IHandler {
|
||||
path string
|
||||
handle(req Request) http.Response
|
||||
handle(mut c Context) http.Response
|
||||
}
|
||||
|
||||
// 泛型处理器类型
|
||||
pub type Handler = fn (Request) http.Response
|
||||
// 泛型处理器类型,使用 Context
|
||||
pub type ContextHandlerFn = fn (mut Context) http.Response
|
||||
|
||||
// 泛型请求处理器结构体
|
||||
pub struct RequestHandler {
|
||||
// Context 处理器结构体
|
||||
pub struct ContextHandler {
|
||||
pub:
|
||||
path string
|
||||
handler fn (Request) http.Response = unsafe { nil }
|
||||
handler fn (mut Context) http.Response = unsafe { nil }
|
||||
}
|
||||
|
||||
// 实现 IRequestHandler 接口
|
||||
pub fn (rh RequestHandler) handle(req Request) http.Response {
|
||||
return rh.handler(req)
|
||||
// 实现 IHandler 接口
|
||||
pub fn (ch ContextHandler) handle(mut c Context) http.Response {
|
||||
return ch.handler(mut c)
|
||||
}
|
||||
|
||||
+95
-85
@@ -10,39 +10,40 @@ enum RouteType {
|
||||
wildcard
|
||||
}
|
||||
|
||||
// 路由节点
|
||||
struct RouteNode {
|
||||
// Context 路由节点
|
||||
struct ContextRouteNode {
|
||||
mut:
|
||||
path string
|
||||
handler IRequestHandler
|
||||
handler IHandler
|
||||
route_type RouteType
|
||||
children map[string]&RouteNode
|
||||
children map[string]&ContextRouteNode
|
||||
param_name string
|
||||
base_path string
|
||||
}
|
||||
|
||||
// 路由匹配结果
|
||||
pub struct RouteMatch {
|
||||
// Context 路由匹配结果
|
||||
pub struct ContextRouteMatch {
|
||||
pub:
|
||||
handler IRequestHandler
|
||||
handler IHandler
|
||||
params map[string]string
|
||||
path string
|
||||
base_path string
|
||||
}
|
||||
|
||||
// 混合路由器
|
||||
pub struct HybridRouter {
|
||||
// Context 混合路由器
|
||||
pub struct ContextHybridRouter {
|
||||
mut:
|
||||
static_routes map[string]IRequestHandler
|
||||
dynamic_routes []IRequestHandler
|
||||
cache LRUCache
|
||||
static_routes map[string]IHandler
|
||||
dynamic_routes []IHandler
|
||||
cache ContextLRUCache
|
||||
}
|
||||
|
||||
pub fn new_hybrid_router() HybridRouter {
|
||||
return HybridRouter{
|
||||
static_routes: map[string]IRequestHandler{}
|
||||
dynamic_routes: []IRequestHandler{}
|
||||
cache: new_lru_cache(1000) // 缓存1000个路由匹配结果
|
||||
// ContextHybridRouter 构造函数
|
||||
pub fn ContextHybridRouter.new() ContextHybridRouter {
|
||||
return ContextHybridRouter{
|
||||
static_routes: map[string]IHandler{}
|
||||
dynamic_routes: []IHandler{}
|
||||
cache: ContextLRUCache.new(1000)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,56 +57,65 @@ fn is_dynamic_path(path string) bool {
|
||||
return path.contains(':') || path.contains('*') || path.contains('?') || path.contains('+')
|
||||
}
|
||||
|
||||
// 优化的正则匹配函数
|
||||
fn (mut router HybridRouter) match_path_with_regex(real_path string, reg_path string) (bool, regex.RE, []string) {
|
||||
start := time.now()
|
||||
|
||||
// Context 版本的正则匹配函数
|
||||
fn (mut router ContextHybridRouter) match_path_with_regex(real_path string, reg_path string) (bool, regex.RE, []string) {
|
||||
// 处理多个星号 **
|
||||
mut one_more_star_reg := regex.regex_opt(r'\*{2,}') or { return false, regex.RE{}, []string{} }
|
||||
repl_on_e_more_star_fn := fn (re regex.RE, in_txt string, start int, end int) string {
|
||||
return r'[^#\?]*' // 匹配任意字符(包括斜杠)
|
||||
if reg_path.contains('**') {
|
||||
// 将 ** 替换为 .*
|
||||
replaced_path := reg_path.replace('**', '.*')
|
||||
mut reg := regex.regex_opt(replaced_path) or { return false, regex.RE{}, []string{} }
|
||||
return reg.matches_string(real_path), reg, []string{}
|
||||
}
|
||||
|
||||
// 转义特殊字符
|
||||
mut replaced_reg_path := reg_path.replace('?', r'\?')
|
||||
replaced_reg_path = replaced_reg_path.replace('+', r'\+')
|
||||
replaced_reg_path = replaced_reg_path.replace('.', r'\.')
|
||||
replaced_reg_path = replaced_reg_path.replace('(', r'\(')
|
||||
replaced_reg_path = replaced_reg_path.replace(')', r'\)')
|
||||
replaced_reg_path = replaced_reg_path.replace('[', r'\[')
|
||||
replaced_reg_path = replaced_reg_path.replace(']', r'\]')
|
||||
replaced_reg_path = replaced_reg_path.replace('{', r'\{')
|
||||
replaced_reg_path = replaced_reg_path.replace('}', r'\}')
|
||||
replaced_reg_path = replaced_reg_path.replace('^', r'\^')
|
||||
replaced_reg_path = replaced_reg_path.replace('$', r'\$')
|
||||
replaced_reg_path = replaced_reg_path.replace('|', r'\|')
|
||||
// 处理单个星号 *
|
||||
if reg_path.contains('*') {
|
||||
// 将 * 替换为 [^/]*
|
||||
replaced_path := reg_path.replace('*', '[^/]*')
|
||||
mut reg := regex.regex_opt(replaced_path) or { return false, regex.RE{}, []string{} }
|
||||
return reg.matches_string(real_path), reg, []string{}
|
||||
}
|
||||
|
||||
// 处理多个星号
|
||||
mut replaced_path := one_more_star_reg.replace_by_fn(replaced_reg_path, repl_on_e_more_star_fn)
|
||||
replaced_path = replaced_path.replace('*', r'[^/#\?]+') // 单个星号匹配单个路径段
|
||||
|
||||
// 提取参数名并替换为命名捕获组
|
||||
mut param_names := []string{}
|
||||
mut pamam_reg := regex.regex_opt(r':[a-zA-Z_][a-zA-Z0-9_]*') or { return false, regex.RE{}, []string{} }
|
||||
replaced_path = pamam_reg.replace_by_fn(replaced_path, fn [mut param_names] (re regex.RE, in_txt string, start int, end int) string {
|
||||
param_name := in_txt[start+1..end]
|
||||
param_names << param_name
|
||||
return '(?P<' + param_name + '>[^/]+)'
|
||||
})
|
||||
|
||||
// 添加结束锚点
|
||||
replaced_path = replaced_path + '$'
|
||||
// 处理参数 :param
|
||||
if reg_path.contains(':') {
|
||||
mut replaced_path := reg_path
|
||||
mut param_names := []string{}
|
||||
|
||||
// 编译正则表达式
|
||||
mut reg := regex.regex_opt(replaced_path) or { return false, regex.RE{}, []string{} }
|
||||
// 转义特殊字符
|
||||
replaced_path = replaced_path.replace('?', r'\?')
|
||||
replaced_path = replaced_path.replace('+', r'\+')
|
||||
replaced_path = replaced_path.replace('.', r'\.')
|
||||
replaced_path = replaced_path.replace('(', r'\(')
|
||||
replaced_path = replaced_path.replace(')', r'\)')
|
||||
replaced_path = replaced_path.replace('[', r'\[')
|
||||
replaced_path = replaced_path.replace(']', r'\]')
|
||||
replaced_path = replaced_path.replace('{', r'\{')
|
||||
replaced_path = replaced_path.replace('}', r'\}')
|
||||
replaced_path = replaced_path.replace('^', r'\^')
|
||||
replaced_path = replaced_path.replace('$', r'\$')
|
||||
replaced_path = replaced_path.replace('|', r'\|')
|
||||
|
||||
// 提取参数名并替换为命名捕获组
|
||||
mut pamam_reg := regex.regex_opt(r':[a-zA-Z_][a-zA-Z0-9_]*') or { return false, regex.RE{}, []string{} }
|
||||
replaced_path = pamam_reg.replace_by_fn(replaced_path, fn [mut param_names] (re regex.RE, in_txt string, start int, end int) string {
|
||||
param_name := in_txt[start+1..end]
|
||||
param_names << param_name
|
||||
return '(?P<' + param_name + '>[^/]+)'
|
||||
})
|
||||
|
||||
// 添加结束锚点
|
||||
replaced_path = '^' + replaced_path + '$'
|
||||
|
||||
// 编译正则表达式
|
||||
mut reg := regex.regex_opt(replaced_path) or { return false, regex.RE{}, []string{} }
|
||||
|
||||
return reg.matches_string(real_path), reg, param_names
|
||||
}
|
||||
|
||||
end := time.now()
|
||||
|
||||
return reg.matches_string(real_path), reg, param_names
|
||||
return false, regex.RE{}, []string{}
|
||||
}
|
||||
|
||||
// 添加路由
|
||||
pub fn (mut router HybridRouter) add_route(method string, handler IRequestHandler, base_path string) {
|
||||
// 添加 Context 路由
|
||||
pub fn (mut router ContextHybridRouter) add_route(method string, handler IHandler, base_path string) {
|
||||
full_path := handler.path
|
||||
if is_static_path(full_path) {
|
||||
router.static_routes['${method}:${full_path}'] = handler
|
||||
@@ -114,8 +124,8 @@ pub fn (mut router HybridRouter) add_route(method string, handler IRequestHandle
|
||||
}
|
||||
}
|
||||
|
||||
// 快速静态路径匹配
|
||||
fn (router HybridRouter) match_static_route(method string, path string) ?IRequestHandler {
|
||||
// Context 版本的静态路径匹配
|
||||
fn (router ContextHybridRouter) match_static_route(method string, path string) ?IHandler {
|
||||
key := '${method}:${path}'
|
||||
if key in router.static_routes {
|
||||
return router.static_routes[key]
|
||||
@@ -123,29 +133,29 @@ fn (router HybridRouter) match_static_route(method string, path string) ?IReques
|
||||
return none
|
||||
}
|
||||
|
||||
// 优化的动态路径匹配
|
||||
fn (mut router HybridRouter) match_dynamic_route(method string, path string) ?RouteMatch {
|
||||
// Context 版本的动态路径匹配
|
||||
fn (mut router ContextHybridRouter) match_dynamic_route(method string, path string) ?ContextRouteMatch {
|
||||
// 先检查缓存
|
||||
cache_key := '${method}:${path}'
|
||||
if cached := router.cache.get(cache_key) {
|
||||
return cached
|
||||
}
|
||||
|
||||
for handler in router.dynamic_routes {
|
||||
match_result, replaced_path_reg, param_names := router.match_path_with_regex(path, handler.path)
|
||||
if match_result {
|
||||
mut param_map := map[string]string{}
|
||||
start, end := replaced_path_reg.match_string(path)
|
||||
if start >= 0 && end > start {
|
||||
// 从原始路由路径中提取参数名
|
||||
mut pamam_reg := regex.regex_opt(r':\w+') or { panic(err) }
|
||||
all_params := pamam_reg.find_all_str(handler.path)
|
||||
for param in all_params {
|
||||
param_name := param[1..]
|
||||
group := replaced_path_reg.get_group_by_name(path, param_name)
|
||||
param_map[param_name] = group
|
||||
}
|
||||
|
||||
// 从原始路由路径中提取参数名
|
||||
mut pamam_reg := regex.regex_opt(r':\w+') or { panic(err) }
|
||||
all_params := pamam_reg.find_all_str(handler.path)
|
||||
for param in all_params {
|
||||
param_name := param[1..]
|
||||
group := replaced_path_reg.get_group_by_name(path, param_name)
|
||||
param_map[param_name] = group
|
||||
}
|
||||
route_match := RouteMatch{
|
||||
|
||||
route_match := ContextRouteMatch{
|
||||
handler: handler
|
||||
params: param_map
|
||||
path: handler.path
|
||||
@@ -158,11 +168,11 @@ fn (mut router HybridRouter) match_dynamic_route(method string, path string) ?Ro
|
||||
return none
|
||||
}
|
||||
|
||||
// 主匹配函数
|
||||
pub fn (mut router HybridRouter) match_route(method string, path string) ?RouteMatch {
|
||||
// Context 版本的主匹配函数
|
||||
pub fn (mut router ContextHybridRouter) match_route(method string, path string) ?ContextRouteMatch {
|
||||
// 1. 先尝试静态路径匹配(最快)
|
||||
if static_handler := router.match_static_route(method, path) {
|
||||
return RouteMatch{
|
||||
return ContextRouteMatch{
|
||||
handler: static_handler
|
||||
params: map[string]string{}
|
||||
path: path
|
||||
@@ -174,8 +184,8 @@ pub fn (mut router HybridRouter) match_route(method string, path string) ?RouteM
|
||||
return router.match_dynamic_route(method, path)
|
||||
}
|
||||
|
||||
// 获取所有路由(用于调试)
|
||||
pub fn (router HybridRouter) get_all_routes() ([]string, []string) {
|
||||
// Context 版本的获取所有路由
|
||||
pub fn (router ContextHybridRouter) get_all_routes() ([]string, []string) {
|
||||
mut static_paths := []string{}
|
||||
mut dynamic_paths := []string{}
|
||||
|
||||
@@ -190,14 +200,14 @@ pub fn (router HybridRouter) get_all_routes() ([]string, []string) {
|
||||
return static_paths, dynamic_paths
|
||||
}
|
||||
|
||||
// 获取缓存统计信息
|
||||
pub fn (router ContextHybridRouter) get_cache_stats() (int, int) {
|
||||
return router.cache.get_stats()
|
||||
}
|
||||
|
||||
// 清理缓存
|
||||
pub fn (mut router HybridRouter) clear_cache() {
|
||||
pub fn (mut router ContextHybridRouter) clear_cache() {
|
||||
router.cache.clear()
|
||||
}
|
||||
|
||||
// 获取缓存统计信息
|
||||
pub fn (router HybridRouter) get_cache_stats() (int, int) {
|
||||
return router.cache.size(), router.cache.capacity
|
||||
}
|
||||
|
||||
|
||||
+109
-125
@@ -1,8 +1,5 @@
|
||||
module hono
|
||||
|
||||
import regex
|
||||
import net.http
|
||||
|
||||
// Trie 路由节点类型
|
||||
enum TrieNodeType {
|
||||
static
|
||||
@@ -10,167 +7,154 @@ enum TrieNodeType {
|
||||
wildcard
|
||||
}
|
||||
|
||||
// Trie 路由节点
|
||||
struct TrieNode {
|
||||
mut:
|
||||
// Context Trie 路由节点
|
||||
@[heap]
|
||||
pub struct ContextTrieNode {
|
||||
pub mut:
|
||||
segment string
|
||||
type TrieNodeType
|
||||
node_type TrieNodeType
|
||||
param_name string
|
||||
children map[string]&TrieNode
|
||||
param_child &TrieNode
|
||||
wildcard_child &TrieNode
|
||||
handler ?IRequestHandler
|
||||
handler ?ContextHandler
|
||||
children map[string]&ContextTrieNode
|
||||
param_child &ContextTrieNode = unsafe { nil }
|
||||
wildcard_child &ContextTrieNode = unsafe { nil }
|
||||
}
|
||||
|
||||
pub fn new_trie_node(segment string, node_type TrieNodeType, param_name string) &TrieNode {
|
||||
return &TrieNode{
|
||||
// ContextTrieNode 构造函数
|
||||
pub fn ContextTrieNode.new(segment string, node_type TrieNodeType, param_name string) &ContextTrieNode {
|
||||
return &ContextTrieNode{
|
||||
segment: segment
|
||||
type: node_type
|
||||
node_type: node_type
|
||||
param_name: param_name
|
||||
children: map[string]&TrieNode{}
|
||||
param_child: unsafe { nil }
|
||||
wildcard_child: unsafe { nil }
|
||||
children: map[string]&ContextTrieNode{}
|
||||
}
|
||||
}
|
||||
|
||||
// Trie 路由树
|
||||
pub struct TrieRouter {
|
||||
// Context Trie 路由器
|
||||
pub struct ContextTrieRouter {
|
||||
mut:
|
||||
method_trees map[string]&TrieNode // method分流
|
||||
regex_routes []RegexRoute
|
||||
cache LRUCache
|
||||
method_trees map[string]&ContextTrieNode
|
||||
cache ContextLRUCache
|
||||
}
|
||||
|
||||
struct RegexRoute {
|
||||
method string
|
||||
pattern string
|
||||
handler IRequestHandler
|
||||
reg regex.RE
|
||||
param_names []string
|
||||
}
|
||||
|
||||
pub fn new_trie_router() TrieRouter {
|
||||
return TrieRouter{
|
||||
method_trees: map[string]&TrieNode{}
|
||||
regex_routes: []RegexRoute{}
|
||||
cache: new_lru_cache(1000)
|
||||
// ContextTrieRouter 构造函数
|
||||
pub fn ContextTrieRouter.new() ContextTrieRouter {
|
||||
return ContextTrieRouter{
|
||||
method_trees: map[string]&ContextTrieNode{}
|
||||
cache: ContextLRUCache.new(1000)
|
||||
}
|
||||
}
|
||||
|
||||
// 注册路由
|
||||
pub fn (mut tr TrieRouter) add_route(method string, path string, handler IRequestHandler) {
|
||||
if path.contains('(') && path.contains(')') {
|
||||
// 正则路由
|
||||
mut param_names := []string{}
|
||||
mut pamam_reg := regex.regex_opt(r':([a-zA-Z_][a-zA-Z0-9_]*)') or { return }
|
||||
mut replaced_path := pamam_reg.replace_by_fn(path, fn [mut param_names] (re regex.RE, in_txt string, start int, end int) string {
|
||||
param_name := in_txt[start+1..end]
|
||||
param_names << param_name
|
||||
return '(?P<' + param_name + '>[^/]+)'
|
||||
})
|
||||
reg := regex.regex_opt(replaced_path + r'$') or { return }
|
||||
tr.regex_routes << RegexRoute{
|
||||
method: method
|
||||
pattern: path
|
||||
handler: handler
|
||||
reg: reg
|
||||
param_names: param_names
|
||||
}
|
||||
return
|
||||
}
|
||||
// Trie 路由 method分流
|
||||
// 添加路由到 Trie 树
|
||||
pub fn (mut tr ContextTrieRouter) add_route(method string, path string, handler ContextHandler) {
|
||||
if method !in tr.method_trees {
|
||||
tr.method_trees[method] = new_trie_node('', TrieNodeType.static, '')
|
||||
tr.method_trees[method] = ContextTrieNode.new('', TrieNodeType.static, '')
|
||||
}
|
||||
mut node := tr.method_trees[method] or { return }
|
||||
segments := path.trim('/').split('/')
|
||||
for seg in segments {
|
||||
|
||||
segments := path.split('/').filter(it != '')
|
||||
mut current := tr.method_trees[method]
|
||||
|
||||
for i, seg in segments {
|
||||
if seg.starts_with(':') {
|
||||
if node.param_child == unsafe { nil } {
|
||||
node.param_child = new_trie_node(seg, TrieNodeType.param, seg[1..])
|
||||
// 参数节点
|
||||
if current.param_child == unsafe { nil } {
|
||||
current.param_child = ContextTrieNode.new(seg, TrieNodeType.param, seg[1..])
|
||||
}
|
||||
node = node.param_child
|
||||
} else if seg.starts_with('*') {
|
||||
if node.wildcard_child == unsafe { nil } {
|
||||
node.wildcard_child = new_trie_node(seg, TrieNodeType.wildcard, seg[1..])
|
||||
current = current.param_child
|
||||
} else if seg == '*' {
|
||||
// 通配符节点
|
||||
if current.wildcard_child == unsafe { nil } {
|
||||
current.wildcard_child = ContextTrieNode.new(seg, TrieNodeType.wildcard, seg[1..])
|
||||
}
|
||||
node = node.wildcard_child
|
||||
break // 通配符为最后一段
|
||||
current = current.wildcard_child
|
||||
} else {
|
||||
if seg !in node.children {
|
||||
node.children[seg] = new_trie_node(seg, TrieNodeType.static, '')
|
||||
// 静态节点
|
||||
if seg !in current.children {
|
||||
current.children[seg] = ContextTrieNode.new(seg, TrieNodeType.static, '')
|
||||
}
|
||||
node = node.children[seg] or { return }
|
||||
current = current.children[seg]
|
||||
}
|
||||
|
||||
// 在最后一个节点设置处理器
|
||||
if i == segments.len - 1 {
|
||||
current.handler = handler
|
||||
}
|
||||
}
|
||||
node.handler = handler
|
||||
}
|
||||
|
||||
// 匹配路由
|
||||
pub fn (mut tr TrieRouter) match_route(method string, path string) ?RouteMatch {
|
||||
cache_key := '${method}:${path}'
|
||||
if cached := tr.cache.get(cache_key) {
|
||||
// 在 Trie 树中匹配路由
|
||||
pub fn (mut tr ContextTrieRouter) match_route(method string, path string) ?ContextRouteMatch {
|
||||
// 先检查缓存
|
||||
if cached := tr.cache.get(path) {
|
||||
return cached
|
||||
}
|
||||
// 1. Trie 路由树 method分流
|
||||
if method in tr.method_trees {
|
||||
mut params := map[string]string{}
|
||||
if handler := tr.match_trie(tr.method_trees[method] or { return none }, path, mut params) {
|
||||
route_match := RouteMatch{
|
||||
handler: handler
|
||||
params: params
|
||||
path: path
|
||||
base_path: ''
|
||||
}
|
||||
tr.cache.put(cache_key, route_match)
|
||||
return route_match
|
||||
|
||||
if method !in tr.method_trees {
|
||||
return none
|
||||
}
|
||||
|
||||
segments := path.split('/').filter(it != '')
|
||||
mut current := tr.method_trees[method]
|
||||
mut params := map[string]string{}
|
||||
|
||||
for seg in segments {
|
||||
// 先尝试静态匹配
|
||||
if seg in current.children {
|
||||
current = current.children[seg]
|
||||
} else if current.param_child != unsafe { nil } {
|
||||
// 参数匹配
|
||||
params[current.param_child.param_name] = seg
|
||||
current = current.param_child
|
||||
} else if current.wildcard_child != unsafe { nil } {
|
||||
// 通配符匹配
|
||||
current = current.wildcard_child
|
||||
break
|
||||
} else {
|
||||
return none
|
||||
}
|
||||
}
|
||||
// 2. 正则路由
|
||||
for reg_route in tr.regex_routes {
|
||||
if reg_route.method != method { continue }
|
||||
if reg_route.reg.matches_string(path) {
|
||||
mut param_map := map[string]string{}
|
||||
for param_name in reg_route.param_names {
|
||||
param_map[param_name] = reg_route.reg.get_group_by_name(path, param_name)
|
||||
}
|
||||
route_match := RouteMatch{
|
||||
handler: reg_route.handler
|
||||
params: param_map
|
||||
path: reg_route.pattern
|
||||
base_path: ''
|
||||
}
|
||||
tr.cache.put(cache_key, route_match)
|
||||
return route_match
|
||||
|
||||
if handler := current.handler {
|
||||
result := ContextRouteMatch{
|
||||
handler: handler
|
||||
params: params
|
||||
}
|
||||
tr.cache.put(path, result)
|
||||
return result
|
||||
}
|
||||
|
||||
return none
|
||||
}
|
||||
|
||||
// Trie 路由树查找(递归实现,消除mut node赋值问题)
|
||||
fn (tr TrieRouter) match_trie_internal(node &TrieNode, segments []string, idx int, mut params map[string]string) ?IRequestHandler {
|
||||
if idx == segments.len {
|
||||
return node.handler or { return none }
|
||||
// 获取所有路由
|
||||
pub fn (tr ContextTrieRouter) get_all_routes() []string {
|
||||
mut routes := []string{}
|
||||
|
||||
for _, root in tr.method_trees {
|
||||
tr.collect_routes(root, '', mut routes)
|
||||
}
|
||||
seg := segments[idx]
|
||||
// 优先静态节点
|
||||
if seg in node.children {
|
||||
return tr.match_trie_internal(node.children[seg] or { return none }, segments, idx+1, mut params)
|
||||
|
||||
return routes
|
||||
}
|
||||
|
||||
// 递归收集路由
|
||||
fn (tr ContextTrieRouter) collect_routes(node &ContextTrieNode, current_path string, mut routes []string) {
|
||||
if node.handler != none {
|
||||
routes << current_path
|
||||
}
|
||||
// 其次参数节点
|
||||
|
||||
// 收集静态子节点
|
||||
for segment, child in node.children {
|
||||
tr.collect_routes(child, current_path + '/' + segment, mut routes)
|
||||
}
|
||||
|
||||
// 收集参数子节点
|
||||
if node.param_child != unsafe { nil } {
|
||||
params[node.param_child.param_name] = seg
|
||||
return tr.match_trie_internal(node.param_child, segments, idx+1, mut params)
|
||||
tr.collect_routes(node.param_child, current_path + '/:' + node.param_child.param_name, mut routes)
|
||||
}
|
||||
// 最后通配符节点
|
||||
|
||||
// 收集通配符子节点
|
||||
if node.wildcard_child != unsafe { nil } {
|
||||
params[node.wildcard_child.param_name] = segments[idx..].join('/')
|
||||
return node.wildcard_child.handler or { return none }
|
||||
tr.collect_routes(node.wildcard_child, current_path + '/*', mut routes)
|
||||
}
|
||||
return none
|
||||
}
|
||||
|
||||
fn (tr TrieRouter) match_trie(root &TrieNode, path string, mut params map[string]string) ?IRequestHandler {
|
||||
segments := path.trim('/').split('/')
|
||||
return tr.match_trie_internal(root, segments, 0, mut params)
|
||||
}
|
||||
Reference in New Issue
Block a user