升级server逻辑, 多模块监听同一个端口,除了共享GIN实例外,其他均按照模块进行隔离
This commit is contained in:
parent
63be630c68
commit
4177c01939
271
construct.go
271
construct.go
@ -9,7 +9,6 @@ package websocket
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/go-developer/gopkg/logger"
|
"github.com/go-developer/gopkg/logger"
|
||||||
|
|
||||||
@ -25,8 +24,6 @@ import (
|
|||||||
|
|
||||||
"gopkg.in/olahol/melody.v1"
|
"gopkg.in/olahol/melody.v1"
|
||||||
|
|
||||||
"github.com/go-developer/gopkg/easylock"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-developer/websocket/abstract"
|
"github.com/go-developer/websocket/abstract"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -46,7 +43,9 @@ type Server struct {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// ginRouterTable 表
|
// ginRouterTable 表
|
||||||
ginRouterTable map[int]*Server
|
ginRouterTable map[int]*gin.Engine
|
||||||
|
// wsServerTable 表
|
||||||
|
wsServerTable map[int]map[string]*Server
|
||||||
// commandTable 指令表
|
// commandTable 指令表
|
||||||
commandTable map[string]map[string]abstract.ICommand
|
commandTable map[string]map[string]abstract.ICommand
|
||||||
// 服务启停的信号
|
// 服务启停的信号
|
||||||
@ -62,141 +61,149 @@ func NewWebsocketServe(wsInstanceList ...abstract.IWebsocket) error {
|
|||||||
if len(wsInstanceList) == 0 {
|
if len(wsInstanceList) == 0 {
|
||||||
return errors.WithStack(errors.New("register websocket server list is empty"))
|
return errors.WithStack(errors.New("register websocket server list is empty"))
|
||||||
}
|
}
|
||||||
lock := easylock.NewLock()
|
ginRouterTable = make(map[int]*gin.Engine)
|
||||||
ginRouterTable = make(map[int]*Server)
|
wsServerTable = make(map[int]map[string]*Server)
|
||||||
commandTable = make(map[string]map[string]abstract.ICommand)
|
commandTable = make(map[string]map[string]abstract.ICommand)
|
||||||
wg := &sync.WaitGroup{}
|
|
||||||
wg.Add(len(wsInstanceList))
|
|
||||||
for _, wsInstance := range wsInstanceList {
|
for _, wsInstance := range wsInstanceList {
|
||||||
go func(wsInstance abstract.IWebsocket) {
|
initServer(wsInstance)
|
||||||
defer wg.Done()
|
|
||||||
// 初始化ws server
|
|
||||||
_ = lock.Lock()
|
|
||||||
if _, exist := ginRouterTable[wsInstance.GetServerPort()]; !exist {
|
|
||||||
wsSetConfigList := wsInstance.GetWSServerConfig()
|
|
||||||
if nil == wsSetConfigList {
|
|
||||||
wsSetConfigList = make([]config.SetWSServerConfig, 0)
|
|
||||||
}
|
|
||||||
s := &Server{
|
|
||||||
ginRouter: gin.Default(),
|
|
||||||
wsServer: melody.New(),
|
|
||||||
conf: config.NewWSServerConfig(wsSetConfigList...),
|
|
||||||
}
|
|
||||||
if s.conf.LogEnable {
|
|
||||||
// 开启了日志,初始化日志
|
|
||||||
if len(s.conf.LogPath) == 0 {
|
|
||||||
panic(wsInstance.GetModuleFlag() + " 模块开启了日志记录,但是没有配置日志路径")
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
logConf *logger.RotateLogConfig
|
|
||||||
)
|
|
||||||
optionList := make([]logger.SetLoggerOptionFunc, 0)
|
|
||||||
if s.conf.LogConsole {
|
|
||||||
optionList = append(optionList, logger.WithConsoleOutput())
|
|
||||||
}
|
|
||||||
if s.conf.LogConsole {
|
|
||||||
optionList = append(optionList, logger.WithConsoleOutput())
|
|
||||||
}
|
|
||||||
if len(s.conf.LogFile) == 0 {
|
|
||||||
s.conf.LogFile = wsInstance.GetModuleFlag() + ".log"
|
|
||||||
}
|
|
||||||
if logConf, err = logger.NewRotateLogConfig(s.conf.LogPath, s.conf.LogFile, logger.WithTimeIntervalType(s.conf.LogSplitInterval)); nil != err {
|
|
||||||
panic(wsInstance.GetModuleFlag() + " 模块开启了日志记录,日志初始化失败, 失败原因 : " + err.Error())
|
|
||||||
}
|
|
||||||
if s.loggerInstance, err = logger.NewLogger(s.conf.LogLevel, logConf, optionList...); nil != err {
|
|
||||||
panic(wsInstance.GetModuleFlag() + " 模块开启了日志记录,日志初始化失败, 失败原因 : " + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if nil == s.loggerInstance && s.conf.LogConsole {
|
|
||||||
var err error
|
|
||||||
// 没有配置文件日志, 但是配置了控制台输出
|
|
||||||
if s.loggerInstance, err = logger.NewConsoleLogger(s.conf.LogLevel); nil != err {
|
|
||||||
panic(wsInstance.GetModuleFlag() + " 模块开启了控制台日志记录,日志初始化失败, 失败原因 : " + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ginRouterTable[wsInstance.GetServerPort()] = s
|
|
||||||
}
|
|
||||||
if _, exist := commandTable[wsInstance.GetModuleFlag()]; !exist {
|
|
||||||
commandTable[wsInstance.GetModuleFlag()] = make(map[string]abstract.ICommand)
|
|
||||||
}
|
|
||||||
_ = lock.Unlock()
|
|
||||||
routerGroup := ginRouterTable[wsInstance.GetServerPort()].ginRouter.Group(wsInstance.GetModuleFlag())
|
|
||||||
// 注册路由
|
|
||||||
for _, path := range wsInstance.HandshakeURL() {
|
|
||||||
routerGroup.GET(path, func(ctx *gin.Context) {
|
|
||||||
parameter := map[string]interface{}{
|
|
||||||
"ws_context": context.NewContext(ctx, wsInstance.GetModuleFlag(), nil),
|
|
||||||
}
|
|
||||||
_ = ginRouterTable[wsInstance.GetServerPort()].wsServer.HandleRequestWithKeys(ctx.Writer, ctx.Request, parameter)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// 注册回调函数
|
|
||||||
// 1. 建立连接的函数
|
|
||||||
ginRouterTable[wsInstance.GetServerPort()].wsServer.HandleConnect(func(session *melody.Session) {
|
|
||||||
ctxInterface, _ := session.Get("ws_context")
|
|
||||||
ctx := ctxInterface.(*context.WSContext)
|
|
||||||
ctx.Session = session
|
|
||||||
if err := wsInstance.Connect(ctx); nil == err {
|
|
||||||
if ginRouterTable[wsInstance.GetServerPort()].conf.StoreConnection && nil != ginRouterTable[wsInstance.GetServerPort()].conf.ConnectionManager {
|
|
||||||
ginRouterTable[wsInstance.GetServerPort()].conf.ConnectionManager.Store(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// 2. 指令处理的函数
|
|
||||||
ginRouterTable[wsInstance.GetServerPort()].wsServer.HandleMessage(func(session *melody.Session, bytes []byte) {
|
|
||||||
// TODO : 增加指令回调失败的callback
|
|
||||||
ctxInterface, _ := session.Get("ws_context")
|
|
||||||
ctx := ctxInterface.(*context.WSContext)
|
|
||||||
_ = dispatchCommand(ctx, bytes)
|
|
||||||
})
|
|
||||||
// 3, 关闭连接的处理函数
|
|
||||||
ginRouterTable[wsInstance.GetServerPort()].wsServer.HandleClose(func(session *melody.Session, i int, s string) error {
|
|
||||||
ctxInterface, _ := session.Get("ws_context")
|
|
||||||
ctx := ctxInterface.(*context.WSContext)
|
|
||||||
defer func() {
|
|
||||||
if !ginRouterTable[wsInstance.GetServerPort()].conf.StoreConnection || nil == ginRouterTable[wsInstance.GetServerPort()].conf.ConnectionManager {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ginRouterTable[wsInstance.GetServerPort()].conf.ConnectionManager.Del(ctx)
|
|
||||||
}()
|
|
||||||
return wsInstance.Close(ctx, i, s)
|
|
||||||
})
|
|
||||||
// 4. 断开连接的处理函数
|
|
||||||
ginRouterTable[wsInstance.GetServerPort()].wsServer.HandleDisconnect(func(session *melody.Session) {
|
|
||||||
ctxInterface, _ := session.Get("ws_context")
|
|
||||||
ctx := ctxInterface.(*context.WSContext)
|
|
||||||
defer func() {
|
|
||||||
if nil == ginRouterTable[wsInstance.GetServerPort()].conf.ConnectionManager {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ginRouterTable[wsInstance.GetServerPort()].conf.ConnectionManager.Del(ctx)
|
|
||||||
}()
|
|
||||||
wsInstance.Disconnect(ctx)
|
|
||||||
})
|
|
||||||
// 注册指令
|
|
||||||
for _, cmd := range wsInstance.GetCommandList() {
|
|
||||||
if nil != ginRouterTable[wsInstance.GetServerPort()].loggerInstance {
|
|
||||||
ginRouterTable[wsInstance.GetServerPort()].loggerInstance.Debug(
|
|
||||||
"长连接指令注册成功",
|
|
||||||
zap.String("module", wsInstance.GetModuleFlag()),
|
|
||||||
zap.String("command", cmd.GetCommand()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
commandTable[wsInstance.GetModuleFlag()][cmd.GetCommand()] = cmd
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
if err := ginRouterTable[wsInstance.GetServerPort()].ginRouter.Run(fmt.Sprintf(":%d", wsInstance.GetServerPort())); nil != err {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}(wsInstance)
|
|
||||||
}
|
}
|
||||||
wg.Wait()
|
|
||||||
run()
|
run()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化server
|
||||||
|
func initServer(wsInstance abstract.IWebsocket) {
|
||||||
|
// 初始化ws server
|
||||||
|
// 初始化 gin 路由表
|
||||||
|
if _, exist := ginRouterTable[wsInstance.GetServerPort()]; !exist {
|
||||||
|
ginRouterTable[wsInstance.GetServerPort()] = gin.Default()
|
||||||
|
}
|
||||||
|
// 初始化WS-Server表
|
||||||
|
if _, exist := wsServerTable[wsInstance.GetServerPort()]; !exist {
|
||||||
|
wsServerTable[wsInstance.GetServerPort()] = make(map[string]*Server)
|
||||||
|
}
|
||||||
|
if _, exist := wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()]; !exist {
|
||||||
|
// 生成并存储 WS-Server
|
||||||
|
wsSetConfigList := wsInstance.GetWSServerConfig()
|
||||||
|
if nil == wsSetConfigList {
|
||||||
|
wsSetConfigList = make([]config.SetWSServerConfig, 0)
|
||||||
|
}
|
||||||
|
s := &Server{
|
||||||
|
ginRouter: gin.Default(),
|
||||||
|
wsServer: melody.New(),
|
||||||
|
conf: config.NewWSServerConfig(wsSetConfigList...),
|
||||||
|
}
|
||||||
|
if s.conf.LogEnable {
|
||||||
|
// 开启了日志,初始化日志
|
||||||
|
if len(s.conf.LogPath) == 0 {
|
||||||
|
panic(wsInstance.GetModuleFlag() + " 模块开启了日志记录,但是没有配置日志路径")
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
logConf *logger.RotateLogConfig
|
||||||
|
)
|
||||||
|
optionList := make([]logger.SetLoggerOptionFunc, 0)
|
||||||
|
if s.conf.LogConsole {
|
||||||
|
optionList = append(optionList, logger.WithConsoleOutput())
|
||||||
|
}
|
||||||
|
if s.conf.LogConsole {
|
||||||
|
optionList = append(optionList, logger.WithConsoleOutput())
|
||||||
|
}
|
||||||
|
if len(s.conf.LogFile) == 0 {
|
||||||
|
s.conf.LogFile = wsInstance.GetModuleFlag() + ".log"
|
||||||
|
}
|
||||||
|
if logConf, err = logger.NewRotateLogConfig(s.conf.LogPath, s.conf.LogFile, logger.WithTimeIntervalType(s.conf.LogSplitInterval)); nil != err {
|
||||||
|
panic(wsInstance.GetModuleFlag() + " 模块开启了日志记录,日志初始化失败, 失败原因 : " + err.Error())
|
||||||
|
}
|
||||||
|
if s.loggerInstance, err = logger.NewLogger(s.conf.LogLevel, logConf, optionList...); nil != err {
|
||||||
|
panic(wsInstance.GetModuleFlag() + " 模块开启了日志记录,日志初始化失败, 失败原因 : " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if nil == s.loggerInstance && s.conf.LogConsole {
|
||||||
|
var err error
|
||||||
|
// 没有配置文件日志, 但是配置了控制台输出
|
||||||
|
if s.loggerInstance, err = logger.NewConsoleLogger(s.conf.LogLevel); nil != err {
|
||||||
|
panic(wsInstance.GetModuleFlag() + " 模块开启了控制台日志记录,日志初始化失败, 失败原因 : " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()] = s
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化指令存储表
|
||||||
|
if _, exist := commandTable[wsInstance.GetModuleFlag()]; !exist {
|
||||||
|
commandTable[wsInstance.GetModuleFlag()] = make(map[string]abstract.ICommand)
|
||||||
|
}
|
||||||
|
routerGroup := ginRouterTable[wsInstance.GetServerPort()].Group(wsInstance.GetModuleFlag())
|
||||||
|
// 注册路由
|
||||||
|
for _, path := range wsInstance.HandshakeURL() {
|
||||||
|
routerGroup.GET(path, func(ctx *gin.Context) {
|
||||||
|
parameter := map[string]interface{}{
|
||||||
|
"ws_context": context.NewContext(ctx, wsInstance.GetModuleFlag(), nil),
|
||||||
|
}
|
||||||
|
_ = wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].wsServer.HandleRequestWithKeys(ctx.Writer, ctx.Request, parameter)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 注册回调函数
|
||||||
|
// 1. 建立连接的函数
|
||||||
|
wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].wsServer.HandleConnect(func(session *melody.Session) {
|
||||||
|
ctxInterface, _ := session.Get("ws_context")
|
||||||
|
ctx := ctxInterface.(*context.WSContext)
|
||||||
|
ctx.Session = session
|
||||||
|
if err := wsInstance.Connect(ctx); nil == err {
|
||||||
|
if wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].conf.StoreConnection && nil != wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].conf.ConnectionManager {
|
||||||
|
wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].conf.ConnectionManager.Store(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 2. 指令处理的函数
|
||||||
|
wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].wsServer.HandleMessage(func(session *melody.Session, bytes []byte) {
|
||||||
|
// TODO : 增加指令回调失败的callback
|
||||||
|
ctxInterface, _ := session.Get("ws_context")
|
||||||
|
ctx := ctxInterface.(*context.WSContext)
|
||||||
|
_ = dispatchCommand(ctx, bytes)
|
||||||
|
})
|
||||||
|
// 3, 关闭连接的处理函数
|
||||||
|
wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].wsServer.HandleClose(func(session *melody.Session, i int, s string) error {
|
||||||
|
ctxInterface, _ := session.Get("ws_context")
|
||||||
|
ctx := ctxInterface.(*context.WSContext)
|
||||||
|
defer func() {
|
||||||
|
if !wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].conf.StoreConnection || nil == wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].conf.ConnectionManager {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].conf.ConnectionManager.Del(ctx, "")
|
||||||
|
}()
|
||||||
|
return wsInstance.Close(ctx, i, s)
|
||||||
|
})
|
||||||
|
// 4. 断开连接的处理函数
|
||||||
|
wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].wsServer.HandleDisconnect(func(session *melody.Session) {
|
||||||
|
ctxInterface, _ := session.Get("ws_context")
|
||||||
|
ctx := ctxInterface.(*context.WSContext)
|
||||||
|
defer func() {
|
||||||
|
if nil == wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].conf.ConnectionManager {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].conf.ConnectionManager.Del(ctx, "")
|
||||||
|
}()
|
||||||
|
wsInstance.Disconnect(ctx)
|
||||||
|
})
|
||||||
|
// 注册指令
|
||||||
|
for _, cmd := range wsInstance.GetCommandList() {
|
||||||
|
if nil != wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].loggerInstance {
|
||||||
|
wsServerTable[wsInstance.GetServerPort()][wsInstance.GetModuleFlag()].loggerInstance.Debug(
|
||||||
|
"长连接指令注册成功",
|
||||||
|
zap.String("module", wsInstance.GetModuleFlag()),
|
||||||
|
zap.String("command", cmd.GetCommand()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
commandTable[wsInstance.GetModuleFlag()][cmd.GetCommand()] = cmd
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
if err := ginRouterTable[wsInstance.GetServerPort()].Run(fmt.Sprintf(":%d", wsInstance.GetServerPort())); nil != err {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
// dispatchCommand 调度command ...
|
// dispatchCommand 调度command ...
|
||||||
//
|
//
|
||||||
// Author : go_developer@163.com<张德满>
|
// Author : go_developer@163.com<张德满>
|
||||||
|
Loading…
Reference in New Issue
Block a user