升级ICommand约束 && 增加日志记录

This commit is contained in:
白茶清欢 2021-04-18 21:55:41 +08:00
parent 47e35b35bd
commit 844da3f325
4 changed files with 221 additions and 36 deletions

View File

@ -35,5 +35,5 @@ type ICommand interface {
// Author : go_developer@163.com<张德满> // Author : go_developer@163.com<张德满>
// //
// Date : 7:21 下午 2021/3/27 // Date : 7:21 下午 2021/3/27
Execute(ctx *context.WSContext, data []byte) error Execute(ctx *context.WSContext, data []byte) (interface{}, error)
} }

View File

@ -35,10 +35,9 @@ import (
// //
// Date : 8:04 下午 2021/3/27 // Date : 8:04 下午 2021/3/27
type Server struct { type Server struct {
ginRouter *gin.Engine // GIN引擎 ginRouter *gin.Engine // GIN引擎
wsServer *melody.Melody // websocket引擎 wsServer *melody.Melody // websocket引擎
conf *config.WSServerConfig // 配置 conf *config.WSServerConfig // 配置
loggerInstance *zap.Logger // 日志实例
} }
var ( var (
@ -48,6 +47,8 @@ var (
wsServerTable map[int]map[string]*Server wsServerTable map[int]map[string]*Server
// commandTable 指令表 // commandTable 指令表
commandTable map[string]map[string]abstract.ICommand commandTable map[string]map[string]abstract.ICommand
// 日志实例表
loggerInstanceTable map[string]*zap.Logger
// 服务启停的信号 // 服务启停的信号
sigChan = make(chan int, 0) sigChan = make(chan int, 0)
) )
@ -82,6 +83,8 @@ func initServer(wsInstance abstract.IWebsocket) {
if _, exist := wsServerTable[wsInstance.GetServerPort()]; !exist { if _, exist := wsServerTable[wsInstance.GetServerPort()]; !exist {
wsServerTable[wsInstance.GetServerPort()] = make(map[string]*Server) wsServerTable[wsInstance.GetServerPort()] = make(map[string]*Server)
} }
// 初始化日志实例表
loggerInstanceTable = make(map[string]*zap.Logger)
if _, exist := wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()]; !exist { if _, exist := wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()]; !exist {
// 生成并存储 WS-Server // 生成并存储 WS-Server
wsSetConfigList := wsInstance.GetWSServerConfig() wsSetConfigList := wsInstance.GetWSServerConfig()
@ -115,15 +118,18 @@ func initServer(wsInstance abstract.IWebsocket) {
if logConf, err = logger.NewRotateLogConfig(s.conf.LogPath, s.conf.LogFile, logger.WithTimeIntervalType(s.conf.LogSplitInterval)); nil != err { if logConf, err = logger.NewRotateLogConfig(s.conf.LogPath, s.conf.LogFile, logger.WithTimeIntervalType(s.conf.LogSplitInterval)); nil != err {
panic(wsInstance.GetModuleFlag() + " 模块开启了日志记录,日志初始化失败, 失败原因 : " + err.Error()) panic(wsInstance.GetModuleFlag() + " 模块开启了日志记录,日志初始化失败, 失败原因 : " + err.Error())
} }
if s.loggerInstance, err = logger.NewLogger(s.conf.LogLevel, logConf, optionList...); nil != err { if loggerInstance, err := logger.NewLogger(s.conf.LogLevel, logConf, optionList...); nil != err {
panic(wsInstance.GetModuleFlag() + " 模块开启了日志记录,日志初始化失败, 失败原因 : " + err.Error()) panic(wsInstance.GetModuleFlag() + " 模块开启了日志记录,日志初始化失败, 失败原因 : " + err.Error())
} else {
loggerInstanceTable[wsInstance.GetModuleFlag()] = loggerInstance
} }
} }
if nil == s.loggerInstance && s.conf.LogConsole { if nil == loggerInstanceTable[wsInstance.GetModuleFlag()] && s.conf.LogConsole {
var err error
// 没有配置文件日志, 但是配置了控制台输出 // 没有配置文件日志, 但是配置了控制台输出
if s.loggerInstance, err = logger.NewConsoleLogger(s.conf.LogLevel); nil != err { if loggerInstance, err := logger.NewConsoleLogger(s.conf.LogLevel); nil != err {
panic(wsInstance.GetModuleFlag() + " 模块开启了控制台日志记录,日志初始化失败, 失败原因 : " + err.Error()) panic(wsInstance.GetModuleFlag() + " 模块开启了控制台日志记录,日志初始化失败, 失败原因 : " + err.Error())
} else {
loggerInstanceTable[wsInstance.GetModuleFlag()] = loggerInstance
} }
} }
wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()] = s wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()] = s
@ -137,33 +143,43 @@ func initServer(wsInstance abstract.IWebsocket) {
// 注册路由 // 注册路由
for _, path := range wsInstance.HandshakeURL() { for _, path := range wsInstance.HandshakeURL() {
routerGroup.GET(path, func(ctx *gin.Context) { routerGroup.GET(path, func(ctx *gin.Context) {
wsCtx := context.NewContext(ctx, wsInstance.GetModuleFlag(), nil)
parameter := map[string]interface{}{ parameter := map[string]interface{}{
"ws_context": context.NewContext(ctx, wsInstance.GetModuleFlag(), nil), "ws_context": wsCtx,
}
if err := wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].wsServer.HandleRequestWithKeys(ctx.Writer, ctx.Request, parameter); nil != err {
log(
loggerInstanceTable[wsInstance.GetModuleFlag()],
logFuncPanic,
"模块启动,注册路由,绑定数据失败",
getLoadDataList(wsCtx, zap.Error(err)),
)
} }
_ = wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].wsServer.HandleRequestWithKeys(ctx.Writer, ctx.Request, parameter)
}) })
} }
currentWSServer := getWsServer(wsInstance.GetServerPort(), wsInstance.GetModuleFlag())
// 注册回调函数 // 注册回调函数
// 1. 建立连接的函数 // 1. 建立连接的函数注册回调函数
wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].wsServer.HandleConnect(func(session *melody.Session) { // //
currentWSServer.wsServer.HandleConnect(func(session *melody.Session) {
ctxInterface, _ := session.Get("ws_context") ctxInterface, _ := session.Get("ws_context")
ctx := ctxInterface.(*context.WSContext) ctx := ctxInterface.(*context.WSContext)
ctx.Session = session ctx.Session = session
if err := wsInstance.Connect(ctx); nil == err { if err := wsInstance.Connect(ctx); nil == err {
if wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].conf.StoreConnection && nil != wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].conf.ConnectionManager { if currentWSServer.conf.StoreConnection && nil != currentWSServer.conf.ConnectionManager {
wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].conf.ConnectionManager.Store(ctx) currentWSServer.conf.ConnectionManager.Store(ctx)
} }
} }
}) })
// 2. 指令处理的函数 // 2. 指令处理的函数
wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].wsServer.HandleMessage(func(session *melody.Session, bytes []byte) { currentWSServer.wsServer.HandleMessage(func(session *melody.Session, bytes []byte) {
// TODO : 增加指令回调失败的callback // TODO : 增加指令回调失败的callback
ctxInterface, _ := session.Get("ws_context") ctxInterface, _ := session.Get("ws_context")
ctx := ctxInterface.(*context.WSContext) ctx := ctxInterface.(*context.WSContext)
_ = dispatchCommand(context.CloneContext(ctx), bytes) _ = dispatchCommand(context.CloneContext(ctx), bytes)
}) })
// 3, 关闭连接的处理函数 // 3, 关闭连接的处理函数
wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].wsServer.HandleClose(func(session *melody.Session, i int, s string) error { currentWSServer.wsServer.HandleClose(func(session *melody.Session, i int, s string) error {
ctxInterface, _ := session.Get("ws_context") ctxInterface, _ := session.Get("ws_context")
ctx := ctxInterface.(*context.WSContext) ctx := ctxInterface.(*context.WSContext)
defer func() { defer func() {
@ -175,31 +191,41 @@ func initServer(wsInstance abstract.IWebsocket) {
return wsInstance.Close(ctx, i, s) return wsInstance.Close(ctx, i, s)
}) })
// 4. 断开连接的处理函数 // 4. 断开连接的处理函数
wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].wsServer.HandleDisconnect(func(session *melody.Session) { currentWSServer.wsServer.HandleDisconnect(func(session *melody.Session) {
ctxInterface, _ := session.Get("ws_context") ctxInterface, _ := session.Get("ws_context")
ctx := ctxInterface.(*context.WSContext) ctx := ctxInterface.(*context.WSContext)
defer func() { defer func() {
if nil == wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].conf.ConnectionManager { if nil == currentWSServer.conf.ConnectionManager {
return return
} }
wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].conf.ConnectionManager.Del(ctx, "") currentWSServer.conf.ConnectionManager.Del(ctx, "")
}() }()
wsInstance.Disconnect(ctx) wsInstance.Disconnect(ctx)
}) })
// 注册指令 // 注册指令
for _, cmd := range wsInstance.GetCommandList() { for _, cmd := range wsInstance.GetCommandList() {
if nil != wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].loggerInstance { log(
wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].loggerInstance.Debug( getLoggerInstance(wsInstance.GetModuleFlag(), nil),
"长连接指令注册成功", logFuncInfo,
"长连接指令注册成功",
getLoadDataList(nil,
zap.String("module", wsInstance.GetModuleFlag()), zap.String("module", wsInstance.GetModuleFlag()),
zap.String("command", cmd.GetCommand()), zap.String("command", cmd.GetCommand()),
) ),
} )
commandTable[wsInstance.GetModuleFlag()][cmd.GetCommand()] = cmd commandTable[wsInstance.GetModuleFlag()][cmd.GetCommand()] = cmd
} }
go func() { go func() {
if err := ginRouterTable[wsInstance.GetServerPort()].Run(fmt.Sprintf(":%d", wsInstance.GetServerPort())); nil != err { if err := ginRouterTable[wsInstance.GetServerPort()].Run(fmt.Sprintf(":%d", wsInstance.GetServerPort())); nil != err {
panic(err) log(
getLoggerInstance(wsInstance.GetModuleFlag(), nil),
logFuncPanic,
"模块启动端口监听失败",
getLoadDataList(nil,
zap.String("module_flag", wsInstance.GetModuleFlag()),
zap.Error(err),
),
)
} }
}() }()
} }
@ -211,34 +237,81 @@ func initServer(wsInstance abstract.IWebsocket) {
// Date : 3:36 下午 2021/3/28 // Date : 3:36 下午 2021/3/28
func dispatchCommand(ctx *context.WSContext, data []byte) error { func dispatchCommand(ctx *context.WSContext, data []byte) error {
if _, exist := commandTable[ctx.Flag]; !exist { if _, exist := commandTable[ctx.Flag]; !exist {
log(
getLoggerInstance(ctx.Flag, nil),
logFuncFatal,
"长连接模块不存在",
getLoadDataList(ctx),
)
return errors.WithStack(errors.New("未注册【" + ctx.Flag + "】长连接模块")) return errors.WithStack(errors.New("未注册【" + ctx.Flag + "】长连接模块"))
} }
cmd := gjson.Get(string(data), "command").String()
var ( var (
exist bool exist bool
cmdInstance abstract.ICommand cmdInstance abstract.ICommand
cmdConfig *config.CommandConfig cmdConfig *config.CommandConfig
err error err error
result interface{}
optionList []config.SetCommandConfig
) )
cmd := gjson.Get(string(data), "command").String()
if cmdInstance, exist = commandTable[ctx.Flag][cmd]; !exist { if cmdInstance, exist = commandTable[ctx.Flag][cmd]; !exist {
log(
getLoggerInstance(ctx.Flag, nil),
logFuncFatal,
"指令未注册",
getLoadDataList(ctx),
)
return errors.WithStack(errors.New("【" + ctx.Flag + "】长连接模块未注册【" + cmd + "】指令")) return errors.WithStack(errors.New("【" + ctx.Flag + "】长连接模块未注册【" + cmd + "】指令"))
} }
optionList := cmdInstance.GetConfigOption()
if nil == optionList { if optionList = cmdInstance.GetConfigOption(); nil == optionList {
optionList = make([]config.SetCommandConfig, 0) optionList = make([]config.SetCommandConfig, 0)
} }
cmdConfig = config.NewCommandConfig(optionList...) cmdConfig = config.NewCommandConfig(optionList...)
if err = cmdInstance.Execute(ctx, data); nil != err { log(
getLoggerInstance(ctx.Flag, &cmdConfig.LogUpData),
logFuncInfo,
"上行原始数据记录",
getLoadDataList(ctx, zap.String("up_data", string(data))),
)
if result, err = cmdInstance.Execute(ctx, data); nil != err {
if cmdConfig.PushMessageWithError { if cmdConfig.PushMessageWithError {
_ = message.Response(ctx, map[string]interface{}{ if err := message.Response(ctx, map[string]interface{}{
"command": cmd, "command": cmd,
"message": err.Error(), "message": err.Error(),
"success": false, "success": false,
}) }); nil != err {
log(
getLoggerInstance(ctx.Flag, nil),
logFuncWarn,
"指令执行失败",
getLoadDataList(ctx, zap.Error(err)),
)
}
} }
return err return err
} }
if cmdConfig.ResponseData {
responseData := buildResponseData(ctx, cmd, result)
if err := ctx.Session.Write(responseData); nil != err {
log(
getLoggerInstance(ctx.Flag, nil),
logFuncWarn,
"指令响应结果失败",
getLoadDataList(ctx, zap.Error(err), zap.String("expect_response", string(responseData))),
)
return err
}
log(
getLoggerInstance(ctx.Flag, &cmdConfig.LogDownData),
logFuncInfo,
"指令响应结果记录",
getLoadDataList(ctx, zap.String("down_data", string(responseData))),
)
}
return nil return nil
} }

113
define.go Normal file
View File

@ -0,0 +1,113 @@
// Package websocket ...
//
// Description : 数据结构定义
//
// Author : go_developer@163.com<张德满>
//
// Date : 2021-04-18 7:53 下午
package websocket
import (
"encoding/json"
"time"
"github.com/go-developer/gopkg/util"
"github.com/go-developer/websocket/context"
"go.uber.org/zap"
)
// buildResponseData 构建响应数据
//
// Author : go_developer@163.com<张德满>
//
// Date : 8:23 下午 2021/4/18
func buildResponseData(wsCtx *context.WSContext, cmd string, data interface{}) []byte {
r := map[string]interface{}{
"connection_id": wsCtx.ConnectionID,
"trace_id": wsCtx.TraceID,
"command": cmd,
"data": data,
}
byteData, _ := json.Marshal(r)
return byteData
}
// getLoadDataList 获取需记录的数据列表
//
// Author : go_developer@163.com<张德满>
//
// Date : 8:00 下午 2021/4/18
func getLoadDataList(wsContext *context.WSContext, fieldList ...zap.Field) []zap.Field {
if nil == wsContext {
wsContext = &context.WSContext{}
}
list := []zap.Field{
zap.String("connection_id", wsContext.ConnectionID),
zap.String("trace_id", wsContext.TraceID),
zap.String("module_flag", wsContext.Flag),
zap.String("server_ip", util.GetHostIP()),
zap.Int64("timestamp", time.Now().UnixNano()),
}
list = append(list, fieldList...)
return list
}
const (
logFuncDebug = "debug"
logFuncInfo = "info"
logFuncWarn = "warn"
logFuncError = "error"
logFuncDPanic = "dpanic"
logFuncPanic = "panic"
logFuncFatal = "fatal"
)
// getWsServer 获取WS-Server实例
//
// Author : go_developer@163.com<张德满>
//
// Date : 8:54 下午 2021/4/18
func getWsServer(port int, flag string) *Server {
return wsServerTable[port][flag]
}
// getLoggerInstance 获取日志实例
//
// Author : go_developer@163.com<张德满>
//
// Date : 8:48 下午 2021/4/18
func getLoggerInstance(moduleFlag string, cmdAllow *bool) *zap.Logger {
if nil != cmdAllow && !*cmdAllow {
return nil
}
return loggerInstanceTable[moduleFlag]
}
// log 记录日志
//
// Author : go_developer@163.com<张德满>
//
// Date : 8:29 下午 2021/4/18
func log(loggerInstance *zap.Logger, f string, message string, fieldList []zap.Field) {
if nil == loggerInstance {
return
}
switch f {
case "info":
loggerInstance.Info(message, fieldList...)
case "warn":
loggerInstance.Warn(message, fieldList...)
case "error":
loggerInstance.Error(message, fieldList...)
case "dpanic":
loggerInstance.DPanic(message, fieldList...)
case "panic":
loggerInstance.Panic(message, fieldList...)
case "fatal":
loggerInstance.Fatal(message, fieldList...)
case "debug":
fallthrough
default:
loggerInstance.Debug(message, fieldList...)
}
}

View File

@ -79,7 +79,6 @@ func (e exampleCommand) GetConfigOption() []config.SetCommandConfig {
return []config.SetCommandConfig{config.ClosePushCommandErrorMessage()} return []config.SetCommandConfig{config.ClosePushCommandErrorMessage()}
} }
func (e exampleCommand) Execute(ctx *context.WSContext, data []byte) error { func (e exampleCommand) Execute(ctx *context.WSContext, data []byte) (interface{}, error) {
message.Response(ctx, map[string]interface{}{"ping": "pong"}) return map[string]interface{}{"ping": "pong"}, nil
return nil
} }