From 0489ee3ef4f5a97f8b82bf73a21e3799946e7f62 Mon Sep 17 00:00:00 2001 From: boyce Date: Sun, 28 Apr 2024 11:13:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9Egin=E6=A8=A1=E5=9D=97&?= =?UTF-8?q?=E4=BC=98=E5=8C=96pb=E5=A4=84=E7=90=86=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- network/processor/pbrawprocessor.go | 18 +-- sysmodule/ginmodule/GinModule.go | 189 ++++++++++++++++++++++++++++ sysmodule/ginmodule/logger.go | 79 ++++++++++++ 3 files changed, 277 insertions(+), 9 deletions(-) create mode 100644 sysmodule/ginmodule/GinModule.go create mode 100644 sysmodule/ginmodule/logger.go diff --git a/network/processor/pbrawprocessor.go b/network/processor/pbrawprocessor.go index bb12508..c6b8fe3 100644 --- a/network/processor/pbrawprocessor.go +++ b/network/processor/pbrawprocessor.go @@ -10,9 +10,9 @@ type RawMessageInfo struct { msgHandler RawMessageHandler } -type RawMessageHandler func(clientId uint64,packType uint16,msg []byte) -type RawConnectHandler func(clientId uint64) -type UnknownRawMessageHandler func(clientId uint64,msg []byte) +type RawMessageHandler func(clientId string,packType uint16,msg []byte) +type RawConnectHandler func(clientId string) +type UnknownRawMessageHandler func(clientId string,msg []byte) const RawMsgTypeSize = 2 type PBRawProcessor struct { @@ -38,14 +38,14 @@ func (pbRawProcessor *PBRawProcessor) SetByteOrder(littleEndian bool) { } // must goroutine safe -func (pbRawProcessor *PBRawProcessor ) MsgRoute(clientId uint64, msg interface{}) error{ +func (pbRawProcessor *PBRawProcessor ) MsgRoute(clientId string, msg interface{}) error{ pPackInfo := msg.(*PBRawPackInfo) pbRawProcessor.msgHandler(clientId,pPackInfo.typ,pPackInfo.rawMsg) return nil } // must goroutine safe -func (pbRawProcessor *PBRawProcessor ) Unmarshal(clientId uint64,data []byte) (interface{}, error) { +func (pbRawProcessor *PBRawProcessor ) Unmarshal(clientId string,data []byte) (interface{}, error) { var msgType uint16 if pbRawProcessor.LittleEndian == true { msgType = binary.LittleEndian.Uint16(data[:2]) @@ -57,7 +57,7 @@ func (pbRawProcessor *PBRawProcessor ) Unmarshal(clientId uint64,data []byte) (i } // must goroutine safe -func (pbRawProcessor *PBRawProcessor ) Marshal(clientId uint64,msg interface{}) ([]byte, error){ +func (pbRawProcessor *PBRawProcessor ) Marshal(clientId string,msg interface{}) ([]byte, error){ pMsg := msg.(*PBRawPackInfo) buff := make([]byte, 2, len(pMsg.rawMsg)+RawMsgTypeSize) @@ -80,7 +80,7 @@ func (pbRawProcessor *PBRawProcessor) MakeRawMsg(msgType uint16,msg []byte,pbRaw pbRawPackInfo.rawMsg = msg } -func (pbRawProcessor *PBRawProcessor) UnknownMsgRoute(clientId uint64,msg interface{}){ +func (pbRawProcessor *PBRawProcessor) UnknownMsgRoute(clientId string,msg interface{}){ if pbRawProcessor.unknownMessageHandler == nil { return } @@ -88,11 +88,11 @@ func (pbRawProcessor *PBRawProcessor) UnknownMsgRoute(clientId uint64,msg interf } // connect event -func (pbRawProcessor *PBRawProcessor) ConnectedRoute(clientId uint64){ +func (pbRawProcessor *PBRawProcessor) ConnectedRoute(clientId string){ pbRawProcessor.connectHandler(clientId) } -func (pbRawProcessor *PBRawProcessor) DisConnectedRoute(clientId uint64){ +func (pbRawProcessor *PBRawProcessor) DisConnectedRoute(clientId string){ pbRawProcessor.disconnectHandler(clientId) } diff --git a/sysmodule/ginmodule/GinModule.go b/sysmodule/ginmodule/GinModule.go new file mode 100644 index 0000000..7071328 --- /dev/null +++ b/sysmodule/ginmodule/GinModule.go @@ -0,0 +1,189 @@ +package ginmodule + +import ( + "context" + "datacenter/common/processor" + "github.com/duanhf2012/origin/v2/event" + "github.com/duanhf2012/origin/v2/log" + "github.com/duanhf2012/origin/v2/service" + "github.com/gin-gonic/gin" + "log/slog" + "net/http" + "strings" +) + +type GinModule struct { + service.Module + + *GinConf + *gin.Engine + srv *http.Server + + processor []processor.IGinProcessor +} + +type GinConf struct { + Addr string +} + +const Sys_Event_Gin_Event event.EventType = -11 + +func (gm *GinModule) Init(conf *GinConf, engine *gin.Engine) { + gm.GinConf = conf + gm.Engine = engine +} + +func (gm *GinModule) SetupDataProcessor(processor ...processor.IGinProcessor) { + gm.processor = processor +} + +func (gm *GinModule) AppendDataProcessor(processor ...processor.IGinProcessor) { + gm.processor = append(gm.processor, processor...) +} + +func (gm *GinModule) OnInit() error { + if gm.Engine == nil { + gm.Engine = gin.Default() + } + + gm.srv = &http.Server{ + Addr: gm.Addr, + Handler: gm.Engine, + } + + gm.Engine.Use(Logger()) + gm.Engine.Use(gin.Recovery()) + gm.GetEventProcessor().RegEventReceiverFunc(Sys_Event_Gin_Event, gm.GetEventHandler(), gm.eventHandler) + return nil +} + +func (gm *GinModule) eventHandler(ev event.IEvent) { + ginEvent := ev.(*GinEvent) + for _, handler := range ginEvent.handlersChain { + handler(ginEvent.c) + } + + ginEvent.chanWait <- struct{}{} +} + +func (gm *GinModule) Start() { + log.Info("http start listen", slog.Any("addr", gm.Addr)) + go func() { + err := gm.srv.ListenAndServe() + if err != nil { + log.Error("ListenAndServe error", slog.Any("error", err.Error())) + } + }() +} + +func (gm *GinModule) StartTLS(certFile, keyFile string) { + log.Info("http start listen", slog.Any("addr", gm.Addr)) + go func() { + err := gm.srv.ListenAndServeTLS(certFile, keyFile) + if err != nil { + log.Fatal("ListenAndServeTLS error", slog.Any("error", err.Error())) + } + }() +} + +func (gm *GinModule) Stop(ctx context.Context) { + if err := gm.srv.Shutdown(ctx); err != nil { + log.SError("Server Shutdown", slog.Any("error", err)) + } +} + +type GinEvent struct { + handlersChain gin.HandlersChain + chanWait chan struct{} + c *gin.Context +} + +func (ge *GinEvent) GetEventType() event.EventType { + return Sys_Event_Gin_Event +} + +func (gm *GinModule) handleMethod(httpMethod, relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes { + return gm.Engine.Handle(httpMethod, relativePath, func(c *gin.Context) { + for _, p := range gm.processor { + _, err := p.Process(c) + if err != nil { + return + } + } + + var ev GinEvent + chanWait := make(chan struct{}) + ev.chanWait = chanWait + ev.handlersChain = handlers + ev.c = c + gm.NotifyEvent(&ev) + + <-chanWait + }) +} + +func (gm *GinModule) SafeGET(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes { + return gm.handleMethod(http.MethodGet, relativePath, handlers...) +} + +func (gm *GinModule) SafePOST(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes { + return gm.handleMethod(http.MethodPost, relativePath, handlers...) +} + +func (gm *GinModule) SafeDELETE(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes { + return gm.handleMethod(http.MethodDelete, relativePath, handlers...) +} + +func (gm *GinModule) SafePATCH(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes { + return gm.handleMethod(http.MethodPatch, relativePath, handlers...) +} + +func (gm *GinModule) SafePut(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes { + return gm.handleMethod(http.MethodPut, relativePath, handlers...) +} + +func GetIPWithProxyHeaders(c *gin.Context) string { + // 尝试从 X-Real-IP 头部获取真实 IP + ip := c.GetHeader("X-Real-IP") + + // 如果 X-Real-IP 头部不存在,则尝试从 X-Forwarded-For 头部获取 + if ip == "" { + ip = c.GetHeader("X-Forwarded-For") + } + + // 如果两者都不存在,则使用默认的 ClientIP 方法获取 IP + if ip == "" { + ip = c.ClientIP() + } + + return ip +} + +func GetIPWithValidatedProxyHeaders(c *gin.Context) string { + // 获取代理头部 + proxyHeaders := c.Request.Header.Get("X-Real-IP,X-Forwarded-For") + + // 分割代理头部,取第一个 IP 作为真实 IP + ips := strings.Split(proxyHeaders, ",") + ip := strings.TrimSpace(ips[0]) + + // 如果 IP 格式合法,则使用获取到的 IP,否则使用默认的 ClientIP 方法获取 + if isValidIP(ip) { + return ip + } else { + ip = c.ClientIP() + return ip + } +} + +// isValidIP 判断 IP 格式是否合法 +func isValidIP(ip string) bool { + // 此处添加自定义的 IP 格式验证逻辑 + // 例如,使用正则表达式验证 IP 格式 + // ... + if ip == "" { + return false + } + + return true +} diff --git a/sysmodule/ginmodule/logger.go b/sysmodule/ginmodule/logger.go new file mode 100644 index 0000000..23ce830 --- /dev/null +++ b/sysmodule/ginmodule/logger.go @@ -0,0 +1,79 @@ +package ginmodule + +import ( + "fmt" + "github.com/duanhf2012/origin/log" + "github.com/gin-gonic/gin" + "time" +) + +// Logger 是一个自定义的日志中间件 +func Logger() gin.HandlerFunc { + + return func(c *gin.Context) { + // 处理请求前记录日志 + // 开始时间 + startTime := time.Now() + // 调用该请求的剩余处理程序 + c.Next() + // 结束时间 + endTime := time.Now() + // 执行时间 + latencyTime := endTime.Sub(startTime) + + // 请求IP + clientIP := c.ClientIP() + // remoteIP := c.RemoteIP() + + // 请求方式 + reqMethod := c.Request.Method + // 请求路由 + reqUri := c.Request.RequestURI + // 请求协议 + reqProto := c.Request.Proto + // 请求来源 + repReferer := c.Request.Referer() + // 请求UA + reqUA := c.Request.UserAgent() + + // 请求响应内容长度 + resLength := c.Writer.Size() + if resLength < 0 { + resLength = 0 + } + // 响应状态码 + statusCode := c.Writer.Status() + + log.SDebug(fmt.Sprintf( + "%s | %3d | %s %10s | \033[44;37m%-6s\033[0m %s %s | %10v | \"%s\" \"%s\"", + colorForStatus(statusCode), + statusCode, + colorForStatus(0), + clientIP, + // remoteIP, + reqMethod, + reqUri, + reqProto, + latencyTime, + reqUA, + repReferer, + )) + + } +} + +// colorForStatus 根据 HTTP 状态码返回 ANSI 颜色代码 +func colorForStatus(code int) string { + switch { + case code >= 200 && code < 300: + return "\033[42;1;37m" // green + case code >= 300 && code < 400: + return "\033[34m" // blue + case code >= 400 && code < 500: + return "\033[33m" // yellow + case code == 0: + return "\033[0m" // cancel + default: + return "\033[31m" // red + } +}