diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..83e73ed9d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "go.toolsEnvVars": { + "GOROOT": "E:\\golang\\go" + } +} \ No newline at end of file diff --git a/common/cool/coolconfig/config.go b/common/cool/coolconfig/config.go index 16e9c0218..6d7be6cdd 100644 --- a/common/cool/coolconfig/config.go +++ b/common/cool/coolconfig/config.go @@ -9,7 +9,7 @@ type sConfig struct { File *file `json:"file,omitempty"` // 文件上传配置 Name string `json:"name"` // 项目名称 Port string `json:"port"` - PortBL uint32 `json:"port_bl"` + PortBL uint16 `json:"port_bl"` } // OSS相关配置 diff --git a/common/data/entity/wscodec.go b/common/data/entity/wscodec.go index 880cda2c4..841e588a7 100644 --- a/common/data/entity/wscodec.go +++ b/common/data/entity/wscodec.go @@ -73,7 +73,7 @@ func (w *WsCodec) ReadBufferBytes(c gnet.Conn) (gnet.Action, int) { return gnet.None, size } func (w *WsCodec) Decode(c gnet.Conn) (outs []wsutil.Message, err error) { - fmt.Println("do Decode") + // fmt.Println("do Decode") messages, err := w.readWsMessages() if err != nil { logging.Errorf("Error reading message! %v", err) diff --git a/common/rpc/rpc.go b/common/rpc/rpc.go index 852883196..8661b070f 100644 --- a/common/rpc/rpc.go +++ b/common/rpc/rpc.go @@ -13,6 +13,7 @@ import ( const rpcaddr = "127.0.0.1:40000" var clientmap = make(map[uint16]*ClientHandler) //客户端map +var clientidmap = make(map[uint16]uint16) //客户端map //var usermap = make(map[int]int) //用户->客户端的map // Define the client handler interface @@ -45,18 +46,21 @@ func (h *ServerHandler) Kick(ctx context.Context, userid uint32) error { } // 注册logic服务器 -func (h *ServerHandler) RegisterLogic(ctx context.Context, port uint16) error { +func (h *ServerHandler) RegisterLogic(ctx context.Context, id, port uint16) error { //TODO 待修复滚动更新可能导致的玩家可以同时在旧服务器和新服务器同时在线的bug revClient, ok := jsonrpc.ExtractReverseClient[ClientHandler](ctx) if !ok { return fmt.Errorf("no reverse client") } - aa, ok := clientmap[port] - if ok && aa != nil { - aa.QuitSelf(0) + aa, ok := clientidmap[id] + if ok { //如果已经存在且这个端口已经被存过 + + t := clientmap[aa] + t.QuitSelf(0) } clientmap[port] = &revClient + clientidmap[id] = port return nil } @@ -77,21 +81,24 @@ func StartServer() { var closer jsonrpc.ClientCloser -func StartClient(port uint16, callback any) *struct { +func StartClient(id, port uint16, callback any) *struct { Kick func(uint32) error - RegisterLogic func(uint16) error + RegisterLogic func(uint16, uint16) error } { - closer1, err := jsonrpc.NewMergeClient(context.Background(), "ws://"+rpcaddr, "", []interface{}{ - &RPCClient, - }, nil, jsonrpc.WithClientHandler("", callback)) + closer1, err := jsonrpc.NewMergeClient(context.Background(), + "ws://"+rpcaddr, "", []interface{}{ + &RPCClient, + }, nil, jsonrpc.WithClientHandler("", callback), + jsonrpc.WithReconnFun(func() { RPCClient.RegisterLogic(id, port) }), + ) if err != nil { log.Fatalf("Failed to create client: %v", err) } if port != 0 { //注册logic - RPCClient.RegisterLogic(port) + RPCClient.RegisterLogic(id, port) } @@ -110,7 +117,7 @@ func CloseClient() { var RPCClient struct { Kick func(uint32) error //踢人 - RegisterLogic func(uint16) error //注册服务器消息 + RegisterLogic func(uint16, uint16) error // UserLogin func(int32, int32) error //用户登录事件 // UserLogout func(int32, int32) error //用户登出事件 diff --git a/common/serialize/go-jsonrpc/client.go b/common/serialize/go-jsonrpc/client.go index 69a9cfecf..1cc3e6852 100644 --- a/common/serialize/go-jsonrpc/client.go +++ b/common/serialize/go-jsonrpc/client.go @@ -323,6 +323,7 @@ func websocketClient(ctx context.Context, addr string, namespace string, outs [] requests: requests, stop: stop, exiting: exiting, + reconfun: config.reconnfun, } go func() { diff --git a/common/serialize/go-jsonrpc/options.go b/common/serialize/go-jsonrpc/options.go index 8b4d0e971..810e55363 100644 --- a/common/serialize/go-jsonrpc/options.go +++ b/common/serialize/go-jsonrpc/options.go @@ -32,6 +32,7 @@ type Config struct { proxyConnFactory func(func() (*websocket.Conn, error)) func() (*websocket.Conn, error) // for testing methodNamer MethodNameFormatter + reconnfun func() } func defaultConfig() Config { @@ -100,6 +101,11 @@ func WithClientHandler(ns string, hnd interface{}) func(c *Config) { c.reverseHandlers = append(c.reverseHandlers, clientHandler{ns, hnd}) } } +func WithReconnFun(s func()) func(c *Config) { + return func(c *Config) { + c.reconnfun = s + } +} // WithClientHandlerAlias creates an alias for a client HANDLER method - for handlers created // with WithClientHandler diff --git a/common/serialize/go-jsonrpc/websocket.go b/common/serialize/go-jsonrpc/websocket.go index 1ab117b71..b4e6d9947 100644 --- a/common/serialize/go-jsonrpc/websocket.go +++ b/common/serialize/go-jsonrpc/websocket.go @@ -61,6 +61,7 @@ type wsConn struct { stopPings func() stop <-chan struct{} exiting chan struct{} + reconfun func() // incoming messages incoming chan io.Reader @@ -661,6 +662,7 @@ func (c *wsConn) tryReconnect(ctx context.Context) bool { c.writeLk.Unlock() go c.nextMessage() + c.reconfun() }() return true @@ -789,6 +791,7 @@ func (c *wsConn) handleWsConn(ctx context.Context) { log.Debugw("websocket error", "error", err, "lastAction", action, "time", time.Since(start)) // only client needs to reconnect + if !c.tryReconnect(ctx) { return // failed to reconnect } @@ -938,3 +941,34 @@ func normalizeID(id interface{}) (interface{}, error) { return nil, xerrors.Errorf("invalid id type: %T", id) } } + +// Retry 执行带指数退避的重试 +// 参数: +// - baseDelay: 基础延迟时间 +// - maxRetries: 最大重试次数 +// - fn: 需要执行的函数,返回bool表示是否成功,error为具体错误 +// +// 返回: +// - 最后一次错误(如果所有重试都失败) +func Retry(baseDelay time.Duration, maxRetries int, fn func() (bool, error)) error { + var lastErr error + + for i := 0; i <= maxRetries; i++ { + if i > 0 { + // 计算当前重试的延迟时间(指数增长) + delay := baseDelay * time.Duration(1< type ServerList struct { *cool.Model - OnlineID uint32 `gorm:"column:online_id;comment:'在线ID';uniqueIndex" json:"online_id"` + OnlineID uint16 `gorm:"column:online_id;comment:'在线ID';uniqueIndex" json:"online_id"` //IP string `gorm:"type:varchar(16);comment:'服务器IP'" json:"ip"` Port uint16 `gorm:"comment:'端口号,通常是小整数'" json:"port"` //IsOpen bool `gorm:"default:true;not null;comment:'服务器是否开启,默认为开启状态'" json:"is_open"` diff --git a/modules/blazing/service/login.go b/modules/blazing/service/login.go index f1100cfe7..284bfb5b7 100644 --- a/modules/blazing/service/login.go +++ b/modules/blazing/service/login.go @@ -50,10 +50,10 @@ func (s *LoginService) GetSessionId(accountID uint) (string, string, error) { // /t1. // 以上过程只需全局一次,且应在生成ID之前完成。 } -func (s *LoginService) SetServerID(OnlineID uint32, Port uint16, t *struct { +func (s *LoginService) SetServerID(OnlineID uint16, Port uint16, t *struct { Kick func(uint32) error - RegisterLogic func(uint16) error + RegisterLogic func(uint16, uint16) error }) error { m := cool.DBM(s.Model).Where("online_id", OnlineID)