feat: server.Server 新增 HttpServer 函数,用于替代 HttpRouter
This commit is contained in:
parent
93c5f3695f
commit
b87df072fc
|
@ -0,0 +1,19 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
// NewHttpHandleWrapper 创建一个新的 http 处理程序包装器
|
||||||
|
// - 默认使用 server.HttpContext 作为上下文,如果需要依赖其作为新的上下文,可以通过 NewHttpContext 创建
|
||||||
|
func NewHttpHandleWrapper[Context any](srv *Server, packer ContextPacker[Context]) *Http[Context] {
|
||||||
|
return &Http[Context]{
|
||||||
|
HttpRouter: &HttpRouter[Context]{
|
||||||
|
srv: srv,
|
||||||
|
group: srv.ginServer,
|
||||||
|
packer: packer,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Http 基于 gin.Engine 包装的 http 服务器
|
||||||
|
type Http[Context any] struct {
|
||||||
|
srv *Server
|
||||||
|
*HttpRouter[Context]
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewHttpContext 基于 gin.Context 创建一个新的 HttpContext
|
||||||
|
func NewHttpContext(ctx *gin.Context) *HttpContext {
|
||||||
|
hc := &HttpContext{
|
||||||
|
ctx: ctx,
|
||||||
|
}
|
||||||
|
return hc
|
||||||
|
}
|
||||||
|
|
||||||
|
// HttpContext 基于 gin.Context 的 http 请求上下文
|
||||||
|
type HttpContext struct {
|
||||||
|
ctx *gin.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gin 获取 gin.Context
|
||||||
|
func (slf *HttpContext) Gin() *gin.Context {
|
||||||
|
return slf.ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadTo 读取请求数据到指定结构体,如果失败则返回错误
|
||||||
|
func (slf *HttpContext) ReadTo(dest any) error {
|
||||||
|
var ctx = slf.Gin()
|
||||||
|
if ctx == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := ctx.ShouldBind(dest); err != nil {
|
||||||
|
if uri := ctx.ShouldBindUri(dest); uri == nil {
|
||||||
|
return uri
|
||||||
|
} else if query := ctx.ShouldBindQuery(dest); query == nil {
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,145 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HandlerFunc[Context any] func(ctx Context)
|
||||||
|
type ContextPacker[Context any] func(ctx *gin.Context) Context
|
||||||
|
|
||||||
|
type HttpRouter[Context any] struct {
|
||||||
|
srv *Server
|
||||||
|
group gin.IRouter
|
||||||
|
packer ContextPacker[Context]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (slf *HttpRouter[Context]) handlesConvert(handlers []HandlerFunc[Context]) []gin.HandlerFunc {
|
||||||
|
var handles []gin.HandlerFunc
|
||||||
|
for i := 0; i < len(handlers); i++ {
|
||||||
|
handler := handlers[i]
|
||||||
|
handles = append(handles, func(ctx *gin.Context) {
|
||||||
|
slf.srv.messageCounter.Add(1)
|
||||||
|
defer func() {
|
||||||
|
slf.srv.messageCounter.Add(-1)
|
||||||
|
}()
|
||||||
|
hc := slf.packer(ctx)
|
||||||
|
handler(hc)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return handles
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle 使用给定的路径和方法注册新的请求句柄和中间件
|
||||||
|
// - 最后一个处理程序应该是真正的处理程序,其他处理程序应该是可以而且应该在不同路由之间共享的中间件。
|
||||||
|
func (slf *HttpRouter[Context]) Handle(httpMethod, relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context] {
|
||||||
|
handles := slf.handlesConvert(handlers)
|
||||||
|
slf.group.Handle(httpMethod, relativePath, handles...)
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST 是 Handle("POST", path, handlers) 的快捷方式
|
||||||
|
func (slf *HttpRouter[Context]) POST(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context] {
|
||||||
|
return slf.Handle(http.MethodPost, relativePath, handlers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET 是 Handle("GET", path, handlers) 的快捷方式
|
||||||
|
func (slf *HttpRouter[Context]) GET(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context] {
|
||||||
|
return slf.Handle(http.MethodGet, relativePath, handlers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE 是 Handle("DELETE", path, handlers) 的快捷方式
|
||||||
|
func (slf *HttpRouter[Context]) DELETE(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context] {
|
||||||
|
return slf.Handle(http.MethodDelete, relativePath, handlers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PATCH 是 Handle("PATCH", path, handlers) 的快捷方式
|
||||||
|
func (slf *HttpRouter[Context]) PATCH(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context] {
|
||||||
|
return slf.Handle(http.MethodPatch, relativePath, handlers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT 是 Handle("PUT", path, handlers) 的快捷方式
|
||||||
|
func (slf *HttpRouter[Context]) PUT(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context] {
|
||||||
|
return slf.Handle(http.MethodPut, relativePath, handlers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OPTIONS 是 Handle("OPTIONS", path, handlers) 的快捷方式
|
||||||
|
func (slf *HttpRouter[Context]) OPTIONS(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context] {
|
||||||
|
return slf.Handle(http.MethodOptions, relativePath, handlers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HEAD 是 Handle("HEAD", path, handlers) 的快捷方式
|
||||||
|
func (slf *HttpRouter[Context]) HEAD(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context] {
|
||||||
|
return slf.Handle(http.MethodHead, relativePath, handlers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CONNECT 是 Handle("CONNECT", path, handlers) 的快捷方式
|
||||||
|
func (slf *HttpRouter[Context]) CONNECT(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context] {
|
||||||
|
return slf.Handle(http.MethodConnect, relativePath, handlers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TRACE 是 Handle("TRACE", path, handlers) 的快捷方式
|
||||||
|
func (slf *HttpRouter[Context]) TRACE(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context] {
|
||||||
|
return slf.Handle(http.MethodTrace, relativePath, handlers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any 注册一个匹配所有 HTTP 方法的路由
|
||||||
|
// - GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE, CONNECT, TRACE.
|
||||||
|
func (slf *HttpRouter[Context]) Any(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context] {
|
||||||
|
for _, m := range []string{
|
||||||
|
http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodHead,
|
||||||
|
http.MethodOptions, http.MethodDelete, http.MethodConnect, http.MethodTrace} {
|
||||||
|
slf.Handle(m, relativePath, handlers...)
|
||||||
|
}
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match 注册一个匹配指定 HTTP 方法的路由
|
||||||
|
// - GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE, CONNECT, TRACE.
|
||||||
|
func (slf *HttpRouter[Context]) Match(methods []string, relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context] {
|
||||||
|
for _, m := range methods {
|
||||||
|
slf.Handle(m, relativePath, handlers...)
|
||||||
|
}
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// StaticFile 注册单个路由以便为本地文件系统的单个文件提供服务。
|
||||||
|
// - 例如: StaticFile("favicon.ico", "./resources/favicon.ico")
|
||||||
|
func (slf *HttpRouter[Context]) StaticFile(relativePath, filepath string) *HttpRouter[Context] {
|
||||||
|
slf.group.StaticFile(relativePath, filepath)
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// StaticFileFS 与 `StaticFile` 类似,但可以使用自定义的 `http.FileSystem` 代替。
|
||||||
|
// - 例如: StaticFileFS("favicon.ico", "./resources/favicon.ico", Dir{".", false})
|
||||||
|
// - 由于依赖于 gin.Engine 默认情况下使用:gin.Dir
|
||||||
|
func (slf *HttpRouter[Context]) StaticFileFS(relativePath, filepath string, fs http.FileSystem) *HttpRouter[Context] {
|
||||||
|
slf.group.StaticFileFS(relativePath, filepath, fs)
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static 提供来自给定文件系统根目录的文件。
|
||||||
|
// - 例如: Static("/static", "/var/www")
|
||||||
|
func (slf *HttpRouter[Context]) Static(relativePath, root string) *HttpRouter[Context] {
|
||||||
|
slf.group.StaticFS(relativePath, gin.Dir(root, false))
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// StaticFS 与 `Static` 类似,但可以使用自定义的 `http.FileSystem` 代替。
|
||||||
|
// - 例如: StaticFS("/static", Dir{"/var/www", false})
|
||||||
|
// - 由于依赖于 gin.Engine 默认情况下使用:gin.Dir
|
||||||
|
func (slf *HttpRouter[Context]) StaticFS(relativePath string, fs http.FileSystem) *HttpRouter[Context] {
|
||||||
|
slf.group.StaticFS(relativePath, fs)
|
||||||
|
return slf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group 创建一个新的路由组。您应该添加所有具有共同中间件的路由。
|
||||||
|
// - 例如: v1 := slf.Group("/v1")
|
||||||
|
func (slf *HttpRouter[Context]) Group(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context] {
|
||||||
|
group := slf.group.Group(relativePath, slf.handlesConvert(handlers)...)
|
||||||
|
return &HttpRouter[Context]{
|
||||||
|
srv: slf.srv,
|
||||||
|
group: group,
|
||||||
|
packer: slf.packer,
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,9 +7,22 @@ import (
|
||||||
|
|
||||||
type HttpWrapperHandleFunc[CTX any] func(ctx CTX)
|
type HttpWrapperHandleFunc[CTX any] func(ctx CTX)
|
||||||
|
|
||||||
|
// NewHttpWrapper 创建 http 包装器
|
||||||
|
//
|
||||||
|
// Deprecated: 从 Minotaur 0.0.29 开始,由于该函数基于 *Server.HttpRouter 函数设计,已弃用。
|
||||||
|
// 如果需要单纯的对 *gin.Engine 进行包装,可以使用 NewGinWrapper 函数进行包装。该函数已不在建议对 server.Server 使用。
|
||||||
|
// 如果需要对 Server.HttpServer 进行包装,可以使用 NewHttpHandleWrapper 函数进行包装。
|
||||||
func NewHttpWrapper[CTX any](server *Server, pack func(ctx *gin.Context) CTX) *HttpWrapper[CTX] {
|
func NewHttpWrapper[CTX any](server *Server, pack func(ctx *gin.Context) CTX) *HttpWrapper[CTX] {
|
||||||
return &HttpWrapper[CTX]{
|
return &HttpWrapper[CTX]{
|
||||||
server: server.HttpRouter().(*gin.Engine),
|
server: server.ginServer,
|
||||||
|
packHandle: pack,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGinWrapper 创建 gin 包装器,用于对 NewHttpWrapper 函数的替代
|
||||||
|
func NewGinWrapper[CTX any](server *gin.Engine, pack func(ctx *gin.Context) CTX) *HttpWrapper[CTX] {
|
||||||
|
return &HttpWrapper[CTX]{
|
||||||
|
server: server,
|
||||||
packHandle: pack,
|
packHandle: pack,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -497,6 +497,9 @@ func (slf *Server) GRPCServer() *grpc.Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
// HttpRouter 当网络类型为 NetworkHttp 时将被允许获取路由器进行路由注册,否则将会发生 panic
|
// HttpRouter 当网络类型为 NetworkHttp 时将被允许获取路由器进行路由注册,否则将会发生 panic
|
||||||
|
// - 通过该函数注册的路由将无法在服务器关闭时正常等待请求结束
|
||||||
|
//
|
||||||
|
// Deprecated: 从 Minotaur 0.0.29 开始,由于设计原因已弃用,该函数将直接返回 *gin.Server 对象,导致无法正常的对请求结束时进行处理
|
||||||
func (slf *Server) HttpRouter() gin.IRouter {
|
func (slf *Server) HttpRouter() gin.IRouter {
|
||||||
if slf.ginServer == nil {
|
if slf.ginServer == nil {
|
||||||
panic(ErrNetworkOnlySupportHttp)
|
panic(ErrNetworkOnlySupportHttp)
|
||||||
|
@ -504,6 +507,23 @@ func (slf *Server) HttpRouter() gin.IRouter {
|
||||||
return slf.ginServer
|
return slf.ginServer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HttpServer 替代 HttpRouter 的函数,返回一个 *Http[*HttpContext] 对象
|
||||||
|
// - 通过该函数注册的路由将在服务器关闭时正常等待请求结束
|
||||||
|
// - 如果需要自行包装 Context 对象,可以使用 NewHttpHandleWrapper 方法
|
||||||
|
func (slf *Server) HttpServer() *Http[*HttpContext] {
|
||||||
|
if slf.ginServer == nil {
|
||||||
|
panic(ErrNetworkOnlySupportHttp)
|
||||||
|
}
|
||||||
|
return NewHttpHandleWrapper(slf, func(ctx *gin.Context) *HttpContext {
|
||||||
|
return NewHttpContext(ctx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMessageCount 获取当前服务器中消息的数量
|
||||||
|
func (slf *Server) GetMessageCount() int64 {
|
||||||
|
return slf.messageCounter.Load()
|
||||||
|
}
|
||||||
|
|
||||||
// ShuntChannelFreed 释放分流通道
|
// ShuntChannelFreed 释放分流通道
|
||||||
func (slf *Server) ShuntChannelFreed(channelGuid int64) {
|
func (slf *Server) ShuntChannelFreed(channelGuid int64) {
|
||||||
if slf.shuntChannels == nil {
|
if slf.shuntChannels == nil {
|
||||||
|
@ -648,7 +668,7 @@ func (slf *Server) dispatchMessage(msg *Message) {
|
||||||
PushSystemMessage(slf, func() {
|
PushSystemMessage(slf, func() {
|
||||||
callback(err)
|
callback(err)
|
||||||
}, "AsyncCallback")
|
}, "AsyncCallback")
|
||||||
} else {
|
} else if err != nil {
|
||||||
log.Error("Server", log.String("MessageType", messageNames[msg.t]), log.Any("error", err), log.String("stack", string(debug.Stack())))
|
log.Error("Server", log.String("MessageType", messageNames[msg.t]), log.Any("error", err), log.String("stack", string(debug.Stack())))
|
||||||
}
|
}
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
Loading…
Reference in New Issue