From 10cc443b3af307111af92ec850d8a3f1f277355c Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Tue, 12 Sep 2023 12:29:14 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20router=20=E5=8C=85=E6=96=B0=E5=A2=9E=20?= =?UTF-8?q?Multistage=20=E5=A4=9A=E7=BA=A7=E5=88=86=E7=B1=BB=E8=B7=AF?= =?UTF-8?q?=E7=94=B1=E5=99=A8=EF=BC=8C=E7=94=A8=E4=BA=8E=E6=9B=BF=E4=BB=A3?= =?UTF-8?q?=E5=8E=9F=E6=9C=89=E7=9A=84=201~3=20=E7=BA=A7=E8=B7=AF=E7=94=B1?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/router/level_1_router.go | 6 ++ server/router/level_2_router.go | 6 ++ server/router/level_3_router.go | 7 ++ server/router/multistage.go | 116 +++++++++++++++++++++++ server/router/multistage_example_test.go | 51 ++++++++++ server/router/multistage_test.go | 35 +++++++ 6 files changed, 221 insertions(+) create mode 100644 server/router/multistage.go create mode 100644 server/router/multistage_example_test.go create mode 100644 server/router/multistage_test.go diff --git a/server/router/level_1_router.go b/server/router/level_1_router.go index 35ffc81..f49932f 100644 --- a/server/router/level_1_router.go +++ b/server/router/level_1_router.go @@ -5,6 +5,8 @@ import ( "reflect" ) +// NewLevel1Router 创建支持一级分类的路由器 +// - Deprecated: 从 Minotaur 0.1.7 开始,由于该路由器设计不合理,局限性大,已弃用。建议使用 Multistage 进行代替。 func NewLevel1Router[Route comparable, Handle any]() *Level1Router[Route, Handle] { return &Level1Router[Route, Handle]{ routes: map[Route]Handle{}, @@ -16,6 +18,8 @@ type Level1Router[Route comparable, Handle any] struct { routes map[Route]Handle } +// Route 创建路由 +// - Deprecated: 从 Minotaur 0.1.7 开始,由于该路由器设计不合理,局限性大,已弃用。建议使用 Multistage 进行代替。 func (slf *Level1Router[Route, Handle]) Route(route Route, handleFunc Handle) { if reflect.TypeOf(handleFunc).Kind() != reflect.Func { panic(fmt.Errorf("route[%v] registration failed, handle must be a function type", route)) @@ -27,6 +31,8 @@ func (slf *Level1Router[Route, Handle]) Route(route Route, handleFunc Handle) { slf.routes[route] = handleFunc } +// Match 匹配路由 +// - Deprecated: 从 Minotaur 0.1.7 开始,由于该路由器设计不合理,局限性大,已弃用。建议使用 Multistage 进行代替。 func (slf *Level1Router[Route, Handle]) Match(route Route) Handle { return slf.routes[route] } diff --git a/server/router/level_2_router.go b/server/router/level_2_router.go index ca74034..4fffd13 100644 --- a/server/router/level_2_router.go +++ b/server/router/level_2_router.go @@ -5,6 +5,8 @@ import ( "reflect" ) +// NewLevel2Router 创建支持二级分类的路由器 +// - Deprecated: 从 Minotaur 0.1.7 开始,由于该路由器设计不合理,局限性大,已弃用。建议使用 Multistage 进行代替。 func NewLevel2Router[Route comparable, Handle any]() *Level2Router[Route, Handle] { return &Level2Router[Route, Handle]{ routes: map[Route]map[Route]Handle{}, @@ -16,6 +18,8 @@ type Level2Router[Route comparable, Handle any] struct { routes map[Route]map[Route]Handle } +// Route 创建路由 +// - Deprecated: 从 Minotaur 0.1.7 开始,由于该路由器设计不合理,局限性大,已弃用。建议使用 Multistage 进行代替。 func (slf *Level2Router[Route, Handle]) Route(topRoute Route, route Route, handleFunc Handle) { if reflect.TypeOf(handleFunc).Kind() != reflect.Func { panic(fmt.Errorf("route[%v] registration failed, handle must be a function type", route)) @@ -33,6 +37,8 @@ func (slf *Level2Router[Route, Handle]) Route(topRoute Route, route Route, handl routes[route] = handleFunc } +// Match 匹配路由 +// - Deprecated: 从 Minotaur 0.1.7 开始,由于该路由器设计不合理,局限性大,已弃用。建议使用 Multistage 进行代替。 func (slf *Level2Router[Route, Handle]) Match(topRoute Route, route Route) Handle { return slf.routes[topRoute][route] } diff --git a/server/router/level_3_router.go b/server/router/level_3_router.go index 9762427..ad435ef 100644 --- a/server/router/level_3_router.go +++ b/server/router/level_3_router.go @@ -5,6 +5,8 @@ import ( "reflect" ) +// NewLevel3Router 创建支持三级分类的路由器 +// - Deprecated: 从 Minotaur 0.1.7 开始,由于该路由器设计不合理,局限性大,已弃用。建议使用 Multistage 进行代替。 func NewLevel3Router[Route comparable, Handle any]() *Level3Router[Route, Handle] { return &Level3Router[Route, Handle]{ routes: map[Route]map[Route]map[Route]Handle{}, @@ -12,10 +14,13 @@ func NewLevel3Router[Route comparable, Handle any]() *Level3Router[Route, Handle } // Level3Router 支持三级分类的路由器 +// - Deprecated: 从 Minotaur 0.1.7 开始,由于该路由器设计不合理,局限性大,已弃用。建议使用 Multistage 进行代替。 type Level3Router[Route comparable, Handle any] struct { routes map[Route]map[Route]map[Route]Handle } +// Route 创建路由 +// - Deprecated: 从 Minotaur 0.1.7 开始,由于该路由器设计不合理,局限性大,已弃用。建议使用 Multistage 进行代替。 func (slf *Level3Router[Route, Handle]) Route(topRoute Route, level2Route Route, route Route, handleFunc Handle) { if reflect.TypeOf(handleFunc).Kind() != reflect.Func { panic(fmt.Errorf("route[%v] registration failed, handle must be a function type", route)) @@ -37,6 +42,8 @@ func (slf *Level3Router[Route, Handle]) Route(topRoute Route, level2Route Route, level2Routes[route] = handleFunc } +// Match 匹配路由 +// - Deprecated: 从 Minotaur 0.1.7 开始,由于该路由器设计不合理,局限性大,已弃用。建议使用 Multistage 进行代替。 func (slf *Level3Router[Route, Handle]) Match(topRoute Route, level2Route Route, route Route) Handle { return slf.routes[topRoute][level2Route][route] } diff --git a/server/router/multistage.go b/server/router/multistage.go new file mode 100644 index 0000000..b28cf14 --- /dev/null +++ b/server/router/multistage.go @@ -0,0 +1,116 @@ +package router + +import ( + "fmt" + "github.com/kercylan98/minotaur/utils/log" + "reflect" +) + +// NewMultistage 创建一个支持多级分类的路由器 +func NewMultistage[HandleFunc any]() *Multistage[HandleFunc] { + r := &Multistage[HandleFunc]{ + routes: make(map[any]HandleFunc), + subs: make(map[any]*Multistage[HandleFunc]), + } + return r +} + +// MultistageBind 多级分类路由绑定函数 +type MultistageBind[HandleFunc any] func(HandleFunc) + +// Bind 将处理函数绑定到预设的路由中 +func (slf MultistageBind[HandleFunc]) Bind(handleFunc HandleFunc) { + slf(handleFunc) +} + +// Multistage 支持多级分类的路由器 +type Multistage[HandleFunc any] struct { + routes map[any]HandleFunc + subs map[any]*Multistage[HandleFunc] + tag any +} + +// Register 注册路由是结合 Sub 和 Route 的快捷方式,用于一次性注册多级路由 +// - 该函数将返回一个注册函数,可通过调用其将路由绑定到特定处理函数,例如:router.Register("a", "b").Bind(onExec()) +func (slf *Multistage[HandleFunc]) Register(routes ...any) MultistageBind[HandleFunc] { + return func(handleFunc HandleFunc) { + router := slf + for i, route := range routes { + if i == len(routes)-1 { + router.Route(route, handleFunc) + } else { + router = router.Sub(route) + } + } + } +} + +// Route 为特定路由绑定处理函数,被绑定的处理函数将可以通过 Match 函数进行匹配 +func (slf *Multistage[HandleFunc]) Route(route any, handleFunc HandleFunc) { + if reflect.TypeOf(handleFunc).Kind() != reflect.Func { + panic(fmt.Errorf("route[%v] registration failed, handle must be a function type", route)) + } + + _, exist := slf.routes[route] + if exist { + panic(fmt.Errorf("the route[%v] has already been registered, duplicate registration is not allowed", route)) + } + + _, exist = slf.subs[route] + if exist { + panic(fmt.Errorf("the route[%v] has already been registered, duplicate registration is not allowed", route)) + } + + slf.routes[route] = handleFunc + if slf.tag == nil { + log.Info("Router", log.String("Type", "Multistage"), log.String("Route", fmt.Sprintf("%v", route))) + } else { + log.Info("Router", log.String("Type", "Multistage"), log.String("Route", fmt.Sprintf("%v > %v", slf.tag, route))) + } +} + +// Match 匹配已绑定处理函数的路由,返回处理函数 +// - 如果未找到将会返回空指针 +func (slf *Multistage[HandleFunc]) Match(routes ...any) HandleFunc { + if len(routes) == 0 { + panic(fmt.Errorf("the route cannot be empty")) + } + var handleFunc HandleFunc + var exist bool + var router *Multistage[HandleFunc] + for i, route := range routes { + handleFunc, exist = slf.routes[route] + if exist { + return handleFunc + } + router, exist = slf.subs[route] + if !exist { + return handleFunc + } + if i == len(routes)-1 { + return handleFunc + } + return router.Match(routes[i+1:]...) + } + return handleFunc +} + +// Sub 获取子路由器 +func (slf *Multistage[HandleFunc]) Sub(route any) *Multistage[HandleFunc] { + _, exist := slf.routes[route] + if exist { + panic(fmt.Errorf("the route[%v] has already been registered, cannot be used as a sub-router", route)) + } + + router, exist := slf.subs[route] + if !exist { + router = NewMultistage[HandleFunc]() + if slf.tag == nil { + router.tag = fmt.Sprintf("%v", route) + } else { + router.tag = fmt.Sprintf("%v > %v", slf.tag, route) + } + slf.subs[route] = router + } + return router +} diff --git a/server/router/multistage_example_test.go b/server/router/multistage_example_test.go new file mode 100644 index 0000000..9ffe9ef --- /dev/null +++ b/server/router/multistage_example_test.go @@ -0,0 +1,51 @@ +package router_test + +import "github.com/kercylan98/minotaur/server/router" + +func ExampleNewMultistage() { + router.NewMultistage[func()]() + + // Output: +} + +func ExampleMultistage_Register() { + r := router.NewMultistage[func()]() + + r.Register("System", "Network", "Ping")(func() { + // ... + }) + + // Output: +} + +func ExampleMultistage_Sub() { + r := router.NewMultistage[func()]() + + r.Sub("System").Route("Heartbeat", func() { + // ... + }) + + // Output: +} + +func ExampleMultistage_Route() { + r := router.NewMultistage[func()]() + + r.Route("ServerTime", func() { + // ... + }) + + // Output: +} + +func ExampleMultistage_Match() { + r := router.NewMultistage[func()]() + + r.Route("ServerTime", func() {}) + r.Register("System", "Network", "Ping").Bind(func() {}) + + r.Match("ServerTime")() + r.Match("System", "Network", "Ping")() + + // Output: +} diff --git a/server/router/multistage_test.go b/server/router/multistage_test.go new file mode 100644 index 0000000..1c3fd72 --- /dev/null +++ b/server/router/multistage_test.go @@ -0,0 +1,35 @@ +package router_test + +import ( + "fmt" + "github.com/kercylan98/minotaur/server/router" + "testing" +) + +func TestMultistage_Match(t *testing.T) { + r := router.NewMultistage[func()]() + + r.Sub("System").Route("Heartbeat", func() { + fmt.Println("Heartbeat") + }) + + r.Route("ServerTime", func() { + fmt.Println("ServerTime") + }) + + r.Register("System", "Network", "Ping")(func() { + fmt.Println("Ping") + }) + + r.Register("System", "Network", "Echo").Bind(onEcho) + + r.Match("System", "Heartbeat")() + r.Match("ServerTime")() + r.Match("System", "Network", "Ping")() + r.Match("System", "Network", "Echo")() + fmt.Println(r.Match("None") == nil) +} + +func onEcho() { + fmt.Println("Echo") +}