├── proto ├── proto_svc.txt ├── proto_client.txt ├── result.proto ├── chat.proto ├── protolist.sh ├── hub.proto ├── router.proto ├── login.proto ├── MakeProto.sh ├── msgbind_gen.go ├── msgsvc_gen.go └── clientmsg_gen.pb.go ├── cfg └── LocalFlag.cfg ├── doc └── architecture.png ├── svc ├── agent │ ├── model │ │ ├── log.go │ │ ├── param.go │ │ ├── frontend.go │ │ ├── routetab.go │ │ └── user.go │ ├── api │ │ ├── log.go │ │ ├── adaptor.go │ │ └── broadcast.go │ ├── backend │ │ ├── log.go │ │ ├── event.go │ │ ├── router_msg.go │ │ └── hooker.go │ ├── frontend │ │ ├── log.go │ │ ├── bind.go │ │ ├── listener.go │ │ ├── packet.go │ │ ├── transmitter.go │ │ └── hooker.go │ ├── heartbeat │ │ ├── log.go │ │ └── heartbeat_msg.go │ ├── routerule │ │ ├── log.go │ │ └── update.go │ └── main.go ├── hub │ ├── api │ │ ├── log.go │ │ ├── pubsub.go │ │ └── hooker.go │ ├── status │ │ ├── log.go │ │ ├── send.go │ │ ├── api.go │ │ └── recv.go │ ├── subscribe │ │ ├── log.go │ │ └── subscribe_msg.go │ ├── model │ │ ├── api.go │ │ ├── status.go │ │ └── channel.go │ └── main.go ├── login │ ├── login │ │ ├── log.go │ │ └── login.go │ └── main.go ├── game │ ├── verify │ │ └── verify_msg.go │ ├── chat │ │ └── chat_msg.go │ └── main.go └── client │ ├── main.go │ └── clientconn.go ├── basefx ├── model │ ├── log.go │ ├── flag.go │ ├── svc.go │ ├── localsvc.go │ └── localsvcchecker.go ├── init.go └── createpeer.go ├── table └── routetable.go ├── go.mod ├── tool └── routegen │ └── main.go ├── go.sum └── README.md /proto/proto_svc.txt: -------------------------------------------------------------------------------- 1 | #服务器间协议,一行一个 2 | router.proto 3 | hub.proto -------------------------------------------------------------------------------- /cfg/LocalFlag.cfg: -------------------------------------------------------------------------------- 1 | logcolor=true 2 | wanip=127.0.0.1 3 | #commtype=ws -------------------------------------------------------------------------------- /proto/proto_client.txt: -------------------------------------------------------------------------------- 1 | #客户端协议,一行一个 2 | result.proto 3 | login.proto 4 | chat.proto -------------------------------------------------------------------------------- /doc/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davyxu/cellmesh_demo/HEAD/doc/architecture.png -------------------------------------------------------------------------------- /svc/agent/model/log.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "github.com/davyxu/golog" 5 | ) 6 | 7 | var log = golog.New("model") 8 | -------------------------------------------------------------------------------- /svc/hub/api/log.go: -------------------------------------------------------------------------------- 1 | package hubapi 2 | 3 | import ( 4 | "github.com/davyxu/golog" 5 | ) 6 | 7 | var log = golog.New("hubapi") 8 | -------------------------------------------------------------------------------- /svc/login/login/log.go: -------------------------------------------------------------------------------- 1 | package login 2 | 3 | import ( 4 | "github.com/davyxu/golog" 5 | ) 6 | 7 | var log = golog.New("login") 8 | -------------------------------------------------------------------------------- /basefx/model/log.go: -------------------------------------------------------------------------------- 1 | package fxmodel 2 | 3 | import ( 4 | "github.com/davyxu/golog" 5 | ) 6 | 7 | var log = golog.New("fxmodel") 8 | -------------------------------------------------------------------------------- /svc/agent/api/log.go: -------------------------------------------------------------------------------- 1 | package agentapi 2 | 3 | import ( 4 | "github.com/davyxu/golog" 5 | ) 6 | 7 | var log = golog.New("agentapi") 8 | -------------------------------------------------------------------------------- /svc/agent/backend/log.go: -------------------------------------------------------------------------------- 1 | package backend 2 | 3 | import ( 4 | "github.com/davyxu/golog" 5 | ) 6 | 7 | var log = golog.New("backend") 8 | -------------------------------------------------------------------------------- /svc/agent/frontend/log.go: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import ( 4 | "github.com/davyxu/golog" 5 | ) 6 | 7 | var log = golog.New("router") 8 | -------------------------------------------------------------------------------- /svc/hub/status/log.go: -------------------------------------------------------------------------------- 1 | package hubstatus 2 | 3 | import ( 4 | "github.com/davyxu/golog" 5 | ) 6 | 7 | var log = golog.New("hubstatus") 8 | -------------------------------------------------------------------------------- /svc/hub/subscribe/log.go: -------------------------------------------------------------------------------- 1 | package subscribe 2 | 3 | import ( 4 | "github.com/davyxu/golog" 5 | ) 6 | 7 | var log = golog.New("subscribe") 8 | -------------------------------------------------------------------------------- /svc/agent/heartbeat/log.go: -------------------------------------------------------------------------------- 1 | package heartbeat 2 | 3 | import ( 4 | "github.com/davyxu/golog" 5 | ) 6 | 7 | var log = golog.New("heartbeat") 8 | -------------------------------------------------------------------------------- /svc/agent/routerule/log.go: -------------------------------------------------------------------------------- 1 | package routerule 2 | 3 | import ( 4 | "github.com/davyxu/golog" 5 | ) 6 | 7 | var log = golog.New("routerule") 8 | -------------------------------------------------------------------------------- /svc/hub/model/api.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "github.com/davyxu/cellnet" 4 | 5 | var ( 6 | HubSession cellnet.Session 7 | OnHubReady func() 8 | ) 9 | -------------------------------------------------------------------------------- /proto/result.proto: -------------------------------------------------------------------------------- 1 | // 添加Service属性的消息会在生成接收代码封装,同时加到路由表中 2 | 3 | enum ResultCode 4 | { 5 | NoError = 0 6 | AgentNotFound = 101 7 | AgentAddressError 8 | GameNotFound 9 | } 10 | -------------------------------------------------------------------------------- /basefx/model/flag.go: -------------------------------------------------------------------------------- 1 | package fxmodel 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh/service" 5 | ) 6 | 7 | var ( 8 | FlagCommunicateType = service.CommandLine.String("commtype", "tcp", "Communicate type, tcp or ws") 9 | ) 10 | -------------------------------------------------------------------------------- /svc/agent/model/param.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type FrontendParameter struct { 4 | SvcName string // 服务名,注册到服务发现 5 | NetProcName string // cellnet处理器名称 6 | NetPeerType string // cellnet的PeerType 7 | ListenAddr string // socket侦听地址 8 | } 9 | -------------------------------------------------------------------------------- /table/routetable.go: -------------------------------------------------------------------------------- 1 | package table 2 | 3 | // 路由规则 4 | type RouteRule struct { 5 | MsgName string 6 | SvcName string 7 | Mode string // auth: 需要授权 pass: 可通过 8 | MsgID int 9 | } 10 | 11 | // 路由表,包含多条路由规则 12 | type RouteTable struct { 13 | Rule []*RouteRule 14 | } 15 | -------------------------------------------------------------------------------- /proto/chat.proto: -------------------------------------------------------------------------------- 1 | 2 | [AutoMsgID Codec:"gogopb" Service: "game" RouteRule: "auth"] 3 | struct ChatREQ { 4 | Content string 5 | } 6 | 7 | [AutoMsgID Codec:"gogopb"] 8 | struct ChatACK{ 9 | Content string 10 | } 11 | 12 | 13 | 14 | [AutoMsgID Codec:"gogopb"] 15 | struct TestACK{ 16 | Dummy string 17 | } 18 | -------------------------------------------------------------------------------- /proto/protolist.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # protolist.sh all 将proto_client.txt和proto_svc.txt的内容输出为行 4 | # protolist.sh XX 将proto_XX.txt的内容输出为行 5 | 6 | if [ "$1" == "all" ] 7 | then 8 | { grep -o '^[^#]*' proto_client.txt; echo " ";grep -o '^[^#]*' proto_svc.txt; }| tr -s "\r\n" " " 9 | else 10 | { grep -o '^[^#]*' proto_${1}.txt; echo " "; }| tr -s "\r\n" " " 11 | fi -------------------------------------------------------------------------------- /proto/hub.proto: -------------------------------------------------------------------------------- 1 | 2 | [AutoMsgID Codec:"protoplus" Service: "hub"] 3 | struct SubscribeChannelREQ { 4 | Channel string 5 | } 6 | 7 | [AutoMsgID Codec:"protoplus"] 8 | struct SubscribeChannelACK{ 9 | Channel string 10 | } 11 | 12 | 13 | [AutoMsgID Codec:"protoplus" Service: "login|match"] 14 | struct SvcStatusACK{ 15 | SvcID string 16 | UserCount int32 17 | } 18 | 19 | -------------------------------------------------------------------------------- /basefx/model/svc.go: -------------------------------------------------------------------------------- 1 | package fxmodel 2 | 3 | import "github.com/davyxu/cellnet" 4 | 5 | var ( 6 | Queue cellnet.EventQueue 7 | ) 8 | 9 | type ServiceParameter struct { 10 | SvcName string // 服务名,注册到服务发现 11 | NetProcName string // cellnet处理器名称 12 | NetPeerType string // cellnet的PeerType 13 | ListenAddr string // socket侦听地址 14 | MaxConnCount int // 最大连接数量 15 | NoQueue bool // 不使用队列 16 | } 17 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/davyxu/cellmesh_demo 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/davyxu/cellmesh v0.1.1-0.20190628065349-a255c0e4e086 7 | github.com/davyxu/cellnet v0.0.0-20190628065413-a644d2409b6d 8 | github.com/davyxu/golog v0.1.0 9 | github.com/davyxu/protoplus v0.1.0 10 | github.com/gogo/protobuf v1.2.1 11 | github.com/gorilla/websocket v1.4.0 12 | ) 13 | 14 | // 本地修改cellmesh时使用 15 | // replace github.com/davyxu/cellmesh => ../cellmesh 16 | -------------------------------------------------------------------------------- /svc/hub/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh_demo/basefx" 5 | "github.com/davyxu/cellmesh_demo/basefx/model" 6 | _ "github.com/davyxu/cellmesh_demo/svc/hub/subscribe" 7 | "github.com/davyxu/golog" 8 | ) 9 | 10 | var log = golog.New("main") 11 | 12 | func main() { 13 | 14 | basefx.Init("hub") 15 | 16 | basefx.CreateCommnicateAcceptor(fxmodel.ServiceParameter{ 17 | SvcName: "hub", 18 | NetProcName: "tcp.svc", 19 | ListenAddr: ":0", 20 | }) 21 | 22 | basefx.StartLoop(nil) 23 | 24 | basefx.Exit() 25 | } 26 | -------------------------------------------------------------------------------- /svc/game/verify/verify_msg.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | import ( 4 | "fmt" 5 | "github.com/davyxu/cellmesh_demo/proto" 6 | "github.com/davyxu/cellmesh_demo/svc/agent/api" 7 | "github.com/davyxu/cellmesh/service" 8 | "github.com/davyxu/cellnet" 9 | ) 10 | 11 | func init() { 12 | 13 | proto.Handle_Game_VerifyREQ = agentapi.HandleBackendMessage(func(ev cellnet.Event, cid proto.ClientID) { 14 | 15 | msg := ev.Message().(*proto.VerifyREQ) 16 | 17 | fmt.Printf("verfiy: %+v \n", msg.GameToken) 18 | 19 | service.Reply(ev, &proto.VerifyACK{}) 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /svc/game/chat/chat_msg.go: -------------------------------------------------------------------------------- 1 | package chat 2 | 3 | import ( 4 | "fmt" 5 | "github.com/davyxu/cellmesh_demo/proto" 6 | "github.com/davyxu/cellmesh_demo/svc/agent/api" 7 | "github.com/davyxu/cellnet" 8 | ) 9 | 10 | func init() { 11 | 12 | proto.Handle_Game_ChatREQ = agentapi.HandleBackendMessage(func(ev cellnet.Event, cid proto.ClientID) { 13 | 14 | msg := ev.Message().(*proto.ChatREQ) 15 | 16 | fmt.Printf("chat: %+v \n", msg.Content) 17 | 18 | // 消息广播到网关并发给客户端 19 | agentapi.BroadcastAll(&proto.ChatACK{ 20 | Content: msg.Content, 21 | }) 22 | 23 | // 消息单发给客户端 24 | agentapi.Send(&cid, &proto.TestACK{ 25 | Dummy: "single send", 26 | }) 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /svc/agent/routerule/update.go: -------------------------------------------------------------------------------- 1 | package routerule 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh_demo/svc/agent/model" 5 | "github.com/davyxu/cellmesh_demo/table" 6 | "github.com/davyxu/cellmesh/discovery" 7 | ) 8 | 9 | // 用Consul KV下载路由规则 10 | func Download() error { 11 | 12 | log.Debugf("Download route rule from discovery...") 13 | 14 | var tab table.RouteTable 15 | 16 | err := discovery.Default.GetValue(model.ConfigPath, &tab) 17 | if err != nil { 18 | return err 19 | } 20 | 21 | model.ClearRule() 22 | 23 | for _, r := range tab.Rule { 24 | model.AddRouteRule(r) 25 | } 26 | 27 | log.Debugf("Total %d rules added", len(tab.Rule)) 28 | 29 | return nil 30 | } 31 | -------------------------------------------------------------------------------- /proto/router.proto: -------------------------------------------------------------------------------- 1 | struct ClientID { 2 | ID int64 // 客户端在网关上的SessionID 3 | SvcID string // 客户端在哪个网关 4 | } 5 | 6 | // backend ->agent 切断用户连接 7 | [AutoMsgID Codec:"protoplus" Service: "agent"] 8 | struct CloseClientACK { 9 | ID []int64 10 | All bool 11 | } 12 | 13 | // agent -> backend 客户端断开 14 | [AutoMsgID Codec:"protoplus"] 15 | struct ClientClosedACK { 16 | ID ClientID 17 | } 18 | 19 | 20 | 21 | // agent <-> backend 在网关和后端服务器之间传输协议 22 | [AutoMsgID Codec:"protoplus"] 23 | struct TransmitACK { 24 | MsgID uint32 // 用户消息ID 25 | MsgData bytes // 用户消息数据 26 | 27 | ClientID int64 // 单发 28 | ClientIDList []int64 // 列表发 29 | All bool // 全发 30 | } -------------------------------------------------------------------------------- /svc/hub/status/send.go: -------------------------------------------------------------------------------- 1 | package hubstatus 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh_demo/basefx/model" 5 | "github.com/davyxu/cellmesh_demo/proto" 6 | "github.com/davyxu/cellmesh_demo/svc/hub/api" 7 | "github.com/davyxu/cellmesh/service" 8 | "github.com/davyxu/cellnet/timer" 9 | "time" 10 | ) 11 | 12 | func StartSendStatus(channelName string, updateInterval time.Duration, statusGetter func() int) { 13 | 14 | timer.NewLoop(fxmodel.Queue, updateInterval, func(loop *timer.Loop) { 15 | 16 | var ack proto.SvcStatusACK 17 | ack.SvcID = service.GetLocalSvcID() 18 | ack.UserCount = int32(statusGetter()) 19 | 20 | hubapi.Publish(channelName, &ack) 21 | 22 | }, nil).Notify().Start() 23 | } 24 | -------------------------------------------------------------------------------- /svc/agent/api/adaptor.go: -------------------------------------------------------------------------------- 1 | package agentapi 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh_demo/proto" 5 | "github.com/davyxu/cellmesh_demo/svc/agent/backend" 6 | "github.com/davyxu/cellmesh/service" 7 | "github.com/davyxu/cellnet" 8 | ) 9 | 10 | // 传入用户处理网关消息回调,返回消息源回调 11 | func HandleBackendMessage(userHandler func(ev cellnet.Event, cid proto.ClientID)) func(ev cellnet.Event) { 12 | 13 | return func(incomingEv cellnet.Event) { 14 | 15 | switch ev := incomingEv.(type) { 16 | case *backend.RecvMsgEvent: 17 | 18 | var cid proto.ClientID 19 | cid.ID = ev.ClientID 20 | 21 | if agentCtx := service.SessionToContext(ev.Session()); agentCtx != nil { 22 | cid.SvcID = agentCtx.SvcID 23 | } 24 | 25 | userHandler(incomingEv, cid) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /proto/login.proto: -------------------------------------------------------------------------------- 1 | // 添加Service属性的消息会在生成接收代码封装,同时加到路由表中 2 | 3 | struct ServerInfo{ 4 | IP string 5 | Port int32 6 | } 7 | 8 | // client -> agent 客户端Ping 9 | [AutoMsgID Codec:"gogopb"] 10 | struct PingACK { 11 | } 12 | 13 | 14 | [AutoMsgID Codec:"gogopb" Service: "login"] 15 | struct LoginREQ { 16 | Version string 17 | Platform string 18 | UID string 19 | } 20 | 21 | 22 | [AutoMsgID Codec:"gogopb"] 23 | struct LoginACK { 24 | Result ResultCode 25 | Server ServerInfo 26 | GameToken string 27 | GameSvcID string // 选中的一台game服务器ID 28 | } 29 | 30 | 31 | [AutoMsgID Codec:"gogopb" Service: "game" RouteRule: "pass"] 32 | struct VerifyREQ { 33 | GameToken string 34 | GameSvcID string 35 | } 36 | 37 | 38 | [AutoMsgID Codec:"gogopb"] 39 | struct VerifyACK { 40 | Result ResultCode 41 | } -------------------------------------------------------------------------------- /svc/hub/model/status.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type Status struct { 8 | UserCount int32 9 | 10 | SvcID string 11 | 12 | LastUpdate time.Time 13 | } 14 | 15 | var ( 16 | statusBySvcID = map[string]*Status{} 17 | ) 18 | 19 | func UpdateStatus(nowStatus *Status) *Status { 20 | 21 | status, _ := statusBySvcID[nowStatus.SvcID] 22 | if status == nil { 23 | status = nowStatus 24 | statusBySvcID[nowStatus.SvcID] = status 25 | } 26 | 27 | status.UserCount = nowStatus.UserCount 28 | status.LastUpdate = time.Now() 29 | 30 | return status 31 | } 32 | 33 | func RemoveStatus(svcid string) { 34 | delete(statusBySvcID, svcid) 35 | } 36 | 37 | func VisitStatus(callback func(status *Status) bool) { 38 | 39 | for _, s := range statusBySvcID { 40 | if !callback(s) { 41 | break 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /svc/agent/backend/event.go: -------------------------------------------------------------------------------- 1 | package backend 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh_demo/proto" 5 | "github.com/davyxu/cellnet" 6 | "github.com/davyxu/cellnet/codec" 7 | ) 8 | 9 | type RecvMsgEvent struct { 10 | Ses cellnet.Session 11 | Msg interface{} 12 | ClientID int64 13 | } 14 | 15 | func (self *RecvMsgEvent) Session() cellnet.Session { 16 | return self.Ses 17 | } 18 | 19 | func (self *RecvMsgEvent) Message() interface{} { 20 | return self.Msg 21 | } 22 | 23 | func (self *RecvMsgEvent) Reply(msg interface{}) { 24 | 25 | data, meta, err := codec.EncodeMessage(msg, nil) 26 | if err != nil { 27 | log.Errorf("Reply.EncodeMessage %s", err) 28 | return 29 | } 30 | 31 | self.Ses.Send(&proto.TransmitACK{ 32 | MsgID: uint32(meta.ID), 33 | MsgData: data, 34 | ClientID: self.ClientID, 35 | }) 36 | 37 | } 38 | -------------------------------------------------------------------------------- /svc/game/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh_demo/basefx" 5 | "github.com/davyxu/cellmesh_demo/basefx/model" 6 | _ "github.com/davyxu/cellmesh_demo/svc/game/chat" 7 | _ "github.com/davyxu/cellmesh_demo/svc/game/verify" 8 | "github.com/davyxu/cellmesh_demo/svc/hub/api" 9 | "github.com/davyxu/cellmesh_demo/svc/hub/status" 10 | "github.com/davyxu/golog" 11 | "time" 12 | ) 13 | 14 | var log = golog.New("main") 15 | 16 | func main() { 17 | 18 | basefx.Init("game") 19 | 20 | basefx.CreateCommnicateAcceptor(fxmodel.ServiceParameter{ 21 | SvcName: "game", 22 | NetProcName: "svc.backend", 23 | ListenAddr: ":0", 24 | }) 25 | 26 | hubapi.ConnectToHub(func() { 27 | 28 | // 开始接收game状态 29 | hubstatus.StartSendStatus("game_status", time.Second*3, func() int { 30 | return 100 31 | }) 32 | }) 33 | 34 | basefx.StartLoop(nil) 35 | 36 | basefx.Exit() 37 | } 38 | -------------------------------------------------------------------------------- /basefx/init.go: -------------------------------------------------------------------------------- 1 | package basefx 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh_demo/basefx/model" 5 | "github.com/davyxu/cellmesh/service" 6 | "github.com/davyxu/cellnet" 7 | "github.com/davyxu/cellnet/msglog" 8 | ) 9 | 10 | // 初始化框架 11 | func Init(procName string) { 12 | 13 | msglog.SetCurrMsgLogMode(msglog.MsgLogMode_BlackList) 14 | msglog.SetMsgLogRule("proto.PingACK", msglog.MsgLogRule_BlackList) 15 | msglog.SetMsgLogRule("proto.SvcStatusACK", msglog.MsgLogRule_BlackList) 16 | 17 | fxmodel.Queue = cellnet.NewEventQueue() 18 | 19 | fxmodel.Queue.StartLoop() 20 | 21 | service.Init(procName) 22 | 23 | service.ConnectDiscovery() 24 | } 25 | 26 | // 等待退出信号 27 | func StartLoop(onReady func()) { 28 | 29 | fxmodel.CheckReady() 30 | 31 | if onReady != nil { 32 | cellnet.QueuedCall(fxmodel.Queue, onReady) 33 | } 34 | 35 | service.WaitExitSignal() 36 | } 37 | 38 | // 退出处理 39 | func Exit() { 40 | fxmodel.StopAllService() 41 | } 42 | -------------------------------------------------------------------------------- /svc/hub/api/pubsub.go: -------------------------------------------------------------------------------- 1 | package hubapi 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh_demo/basefx" 5 | "github.com/davyxu/cellmesh_demo/basefx/model" 6 | "github.com/davyxu/cellmesh_demo/proto" 7 | "github.com/davyxu/cellmesh_demo/svc/hub/model" 8 | "github.com/davyxu/cellnet/relay" 9 | ) 10 | 11 | // 传入你的服务名, 连接到hub 12 | func ConnectToHub(hubReady func()) { 13 | 14 | model.OnHubReady = hubReady 15 | basefx.CreateCommnicateConnector(fxmodel.ServiceParameter{ 16 | SvcName: "hub", 17 | NetProcName: "tcp.hub", 18 | MaxConnCount: 1, 19 | }) 20 | } 21 | 22 | func Subscribe(channel string) { 23 | 24 | if model.HubSession == nil { 25 | log.Errorf("hub session not ready, channel: %s", channel) 26 | return 27 | } 28 | 29 | model.HubSession.Send(&proto.SubscribeChannelREQ{ 30 | Channel: channel, 31 | }) 32 | } 33 | 34 | func Publish(channel string, msg interface{}) { 35 | 36 | if model.HubSession == nil { 37 | log.Errorf("hub session not ready, channel: %s", channel) 38 | return 39 | } 40 | 41 | relay.Relay(model.HubSession, msg, channel) 42 | } 43 | -------------------------------------------------------------------------------- /svc/agent/heartbeat/heartbeat_msg.go: -------------------------------------------------------------------------------- 1 | package heartbeat 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh_demo/svc/agent/model" 5 | "github.com/davyxu/cellmesh/discovery" 6 | "github.com/davyxu/cellmesh/discovery/kvconfig" 7 | "github.com/davyxu/cellnet/timer" 8 | "time" 9 | ) 10 | 11 | func StartCheck() { 12 | 13 | // 从KV获取配置,默认关闭 14 | heatBeatDuration := kvconfig.Int32(discovery.Default, "config/agent/heatbeat_sec", 0) 15 | 16 | // 为0时关闭心跳检查 17 | if heatBeatDuration != 0 { 18 | // 超时检查比心跳稍长 19 | timeOutDur := time.Duration(heatBeatDuration+5) * time.Second 20 | 21 | log.Infof("Heatbeat duration: '%ds' ", heatBeatDuration) 22 | 23 | // 心跳检查 24 | timer.NewLoop(nil, timeOutDur, func(loop *timer.Loop) { 25 | 26 | now := time.Now() 27 | 28 | model.VisitUser(func(u *model.User) bool { 29 | 30 | if now.Sub(u.LastPingTime) > timeOutDur { 31 | log.Warnf("Close client due to heatbeat time out, id: %d", u.ClientSession.ID()) 32 | u.ClientSession.Close() 33 | } 34 | 35 | return true 36 | }) 37 | 38 | }, nil).Start() 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /svc/agent/frontend/bind.go: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import ( 4 | "errors" 5 | "github.com/davyxu/cellmesh_demo/svc/agent/model" 6 | "github.com/davyxu/cellmesh/service" 7 | ) 8 | 9 | var ( 10 | ErrAlreadyBind = errors.New("already bind user") 11 | ErrBackendSDNotFound = errors.New("backend sd not found") 12 | ErrBackendServerNotFound = errors.New("backend svc not found") 13 | ) 14 | 15 | // 将客户端连接绑定到后台服务 16 | func bindClientToBackend(backendSvcID string, clientSesID int64) (*model.User, error) { 17 | 18 | backendSes := service.GetRemoteService(backendSvcID) 19 | 20 | if backendSes == nil { 21 | return nil, ErrBackendServerNotFound 22 | } 23 | 24 | // 取得后台服务的信息 25 | sd := service.SessionToContext(backendSes) 26 | if sd == nil { 27 | return nil, ErrBackendSDNotFound 28 | } 29 | 30 | // 将客户端的id转为session 31 | clientSes := model.GetClientSession(clientSesID) 32 | 33 | // 从客户端的会话取得用户 34 | u := model.SessionToUser(clientSes) 35 | 36 | // 已经绑定 37 | if u != nil { 38 | return nil, ErrAlreadyBind 39 | } 40 | 41 | u = model.CreateUser(clientSes) 42 | 43 | // 更新绑定后台服务的svcid 44 | u.SetBackend(sd.Name, sd.SvcID) 45 | 46 | return u, nil 47 | } 48 | -------------------------------------------------------------------------------- /svc/agent/model/frontend.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "github.com/davyxu/cellnet" 5 | "github.com/davyxu/cellnet/peer" 6 | ) 7 | 8 | var ( 9 | FrontendSessionManager peer.SessionManager 10 | AgentSvcID string // 网关id 11 | ) 12 | 13 | func GetClientSession(sesid int64) cellnet.Session { 14 | 15 | return FrontendSessionManager.GetSession(sesid) 16 | } 17 | 18 | func GetUser(sesid int64) *User { 19 | return SessionToUser(GetClientSession(sesid)) 20 | } 21 | 22 | // 创建一个网关用户 23 | func CreateUser(clientSes cellnet.Session) *User { 24 | 25 | u := NewUser(clientSes) 26 | 27 | // 绑定到session上 28 | clientSes.(cellnet.ContextSet).SetContext("user", u) 29 | return u 30 | } 31 | 32 | // 用session获取用户 33 | func SessionToUser(clientSes cellnet.Session) *User { 34 | 35 | if clientSes == nil { 36 | return nil 37 | } 38 | 39 | if raw, ok := clientSes.(cellnet.ContextSet).GetContext("user"); ok { 40 | return raw.(*User) 41 | } 42 | 43 | return nil 44 | } 45 | 46 | // 遍历所有的用户 47 | func VisitUser(callback func(*User) bool) { 48 | FrontendSessionManager.VisitSession(func(clientSes cellnet.Session) bool { 49 | 50 | if u := SessionToUser(clientSes); u != nil { 51 | return callback(u) 52 | } 53 | 54 | return true 55 | }) 56 | } 57 | -------------------------------------------------------------------------------- /svc/agent/frontend/listener.go: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh_demo/basefx/model" 5 | "github.com/davyxu/cellmesh_demo/svc/agent/model" 6 | "github.com/davyxu/cellmesh/discovery" 7 | "github.com/davyxu/cellmesh/service" 8 | "github.com/davyxu/cellnet" 9 | "github.com/davyxu/cellnet/peer" 10 | "github.com/davyxu/cellnet/proc" 11 | "time" 12 | ) 13 | 14 | func Start(param model.FrontendParameter) { 15 | 16 | clientListener := peer.NewGenericPeer(param.NetPeerType, "agent", param.ListenAddr, nil) 17 | 18 | proc.BindProcessorHandler(clientListener, param.NetProcName, nil) 19 | 20 | if socketOpt, ok := clientListener.(cellnet.TCPSocketOption); ok { 21 | // 无延迟设置缓冲 22 | socketOpt.SetSocketBuffer(2048, 2048, true) 23 | 24 | // 40秒无读,20秒无写断开 25 | socketOpt.SetSocketDeadline(time.Second*40, time.Second*20) 26 | } 27 | 28 | clientListener.Start() 29 | model.FrontendSessionManager = clientListener.(peer.SessionManager) 30 | 31 | // 服务发现注册服务 32 | service.Register(clientListener) 33 | 34 | fxmodel.AddLocalService(clientListener) 35 | } 36 | 37 | func Stop() { 38 | 39 | if model.FrontendSessionManager != nil { 40 | model.FrontendSessionManager.(cellnet.Peer).Stop() 41 | discovery.Default.Deregister(model.AgentSvcID) 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /svc/hub/subscribe/subscribe_msg.go: -------------------------------------------------------------------------------- 1 | package subscribe 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh_demo/proto" 5 | "github.com/davyxu/cellmesh_demo/svc/hub/model" 6 | "github.com/davyxu/cellnet" 7 | "github.com/davyxu/cellnet/relay" 8 | ) 9 | 10 | func init() { 11 | 12 | relay.SetBroadcaster(func(event *relay.RecvMsgEvent) { 13 | 14 | if channelName := event.PassThroughAsString(); channelName != "" { 15 | 16 | model.VisitSubscriber(channelName, func(ses cellnet.Session) bool { 17 | 18 | relay.Relay(ses, event.Message(), channelName) 19 | 20 | return true 21 | }) 22 | } 23 | 24 | }) 25 | 26 | proto.Handle_Hub_SubscribeChannelREQ = func(ev cellnet.Event) { 27 | 28 | msg := ev.Message().(*proto.SubscribeChannelREQ) 29 | model.AddSubscriber(msg.Channel, ev.Session()) 30 | 31 | log.Infof("channel add: '%s', sesid: %d", msg.Channel, ev.Session().ID()) 32 | 33 | ev.Session().Send(&proto.SubscribeChannelACK{ 34 | Channel: msg.Channel, 35 | }) 36 | } 37 | 38 | proto.Handle_Hub_Default = func(ev cellnet.Event) { 39 | 40 | switch ev.Message().(type) { 41 | case *cellnet.SessionClosed: 42 | 43 | model.RemoveSubscriber(ev.Session(), func(chanName string) { 44 | log.Infof("channel remove: '%s', sesid: %d", chanName, ev.Session().ID()) 45 | }) 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /svc/hub/model/channel.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "github.com/davyxu/cellnet" 4 | 5 | var ( 6 | chanByName = map[string][]cellnet.Session{} 7 | ) 8 | 9 | func AddSubscriber(name string, ses cellnet.Session) { 10 | 11 | list, _ := chanByName[name] 12 | list = append(list, ses) 13 | chanByName[name] = list 14 | } 15 | 16 | func RemoveSubscriber(ses cellnet.Session, callback func(chanName string)) { 17 | 18 | var found bool 19 | for { 20 | 21 | found = false 22 | 23 | Refound: 24 | for name, list := range chanByName { 25 | 26 | for index, libSes := range list { 27 | if libSes == ses { 28 | 29 | callback(name) 30 | list = append(list[:index], list[index+1:]...) 31 | 32 | if len(list) == 0 { 33 | delete(chanByName, name) 34 | } else { 35 | chanByName[name] = list 36 | } 37 | 38 | found = true 39 | goto Refound // 避免循环删除造成的故障,再查一次 40 | } 41 | } 42 | } 43 | 44 | // 直到没有删的了 45 | if !found { 46 | break 47 | } 48 | 49 | } 50 | 51 | return 52 | } 53 | 54 | func VisitSubscriber(name string, callback func(ses cellnet.Session) bool) (count int) { 55 | if list, ok := chanByName[name]; ok { 56 | 57 | for _, ses := range list { 58 | count++ 59 | if !callback(ses) { 60 | return 61 | } 62 | } 63 | } 64 | 65 | return 66 | 67 | } 68 | -------------------------------------------------------------------------------- /svc/agent/model/routetab.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh_demo/table" 5 | "sync" 6 | ) 7 | 8 | const ( 9 | ConfigPath = "config_demo/route_rule" 10 | ) 11 | 12 | var ( 13 | // 消息名映射路由规则 14 | ruleByMsgName = map[string]*table.RouteRule{} 15 | ruleByMsgNameGuard sync.RWMutex 16 | 17 | ruleByMsgID = map[int]*table.RouteRule{} 18 | ) 19 | 20 | // 消息名取路由规则 21 | func GetTargetService(msgName string) *table.RouteRule { 22 | 23 | ruleByMsgNameGuard.RLock() 24 | defer ruleByMsgNameGuard.RUnlock() 25 | 26 | if rule, ok := ruleByMsgName[msgName]; ok { 27 | return rule 28 | } 29 | 30 | return nil 31 | } 32 | 33 | func GetRuleByMsgID(msgid int) *table.RouteRule { 34 | ruleByMsgNameGuard.RLock() 35 | defer ruleByMsgNameGuard.RUnlock() 36 | 37 | if rule, ok := ruleByMsgID[msgid]; ok { 38 | return rule 39 | } 40 | 41 | return nil 42 | } 43 | 44 | // 清除所有规则 45 | func ClearRule() { 46 | 47 | ruleByMsgNameGuard.Lock() 48 | ruleByMsgName = map[string]*table.RouteRule{} 49 | ruleByMsgID = map[int]*table.RouteRule{} 50 | ruleByMsgNameGuard.Unlock() 51 | } 52 | 53 | // 添加路由规则 54 | func AddRouteRule(rule *table.RouteRule) { 55 | 56 | ruleByMsgNameGuard.Lock() 57 | ruleByMsgName[rule.MsgName] = rule 58 | if rule.MsgID == 0 { 59 | panic("RouteRule msgid = 0, run MakeProto.sh please!") 60 | } 61 | ruleByMsgID[rule.MsgID] = rule 62 | ruleByMsgNameGuard.Unlock() 63 | } 64 | -------------------------------------------------------------------------------- /svc/agent/frontend/packet.go: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import ( 4 | "encoding/binary" 5 | "errors" 6 | "io" 7 | ) 8 | 9 | var ( 10 | ErrMaxPacket = errors.New("packet over size") 11 | ErrMinPacket = errors.New("packet short size") 12 | ErrShortMsgID = errors.New("short msgid") 13 | ) 14 | 15 | const ( 16 | bodySize = 2 // 包体大小字段 17 | msgIDSize = 2 // 消息ID字段 18 | ) 19 | 20 | // 接收Length-Type-Value格式的封包流程 21 | func RecvLTVPacketData(reader io.Reader, maxPacketSize int) (msgID int, msgData []byte, err error) { 22 | 23 | // Size为uint16,占2字节 24 | var sizeBuffer = make([]byte, bodySize) 25 | 26 | // 持续读取Size直到读到为止 27 | _, err = io.ReadFull(reader, sizeBuffer) 28 | 29 | // 发生错误时返回 30 | if err != nil { 31 | return 32 | } 33 | 34 | if len(sizeBuffer) < bodySize { 35 | err = ErrMinPacket 36 | return 37 | } 38 | 39 | // 用小端格式读取Size 40 | size := binary.LittleEndian.Uint16(sizeBuffer) 41 | 42 | if maxPacketSize > 0 && size >= uint16(maxPacketSize) { 43 | err = ErrMaxPacket 44 | return 45 | } 46 | 47 | // 分配包体大小 48 | // TODO 内存池优化发送后删除 49 | body := make([]byte, size) 50 | 51 | // 读取包体数据 52 | _, err = io.ReadFull(reader, body) 53 | 54 | // 发生错误时返回 55 | if err != nil { 56 | return 57 | } 58 | 59 | if len(body) < bodySize { 60 | err = ErrShortMsgID 61 | return 62 | } 63 | 64 | msgID = int(binary.LittleEndian.Uint16(body)) 65 | 66 | msgData = body[msgIDSize:] 67 | 68 | return 69 | } 70 | -------------------------------------------------------------------------------- /svc/hub/api/hooker.go: -------------------------------------------------------------------------------- 1 | package hubapi 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh/service" 5 | "github.com/davyxu/cellmesh_demo/basefx/model" 6 | "github.com/davyxu/cellmesh_demo/svc/hub/model" 7 | "github.com/davyxu/cellnet" 8 | "github.com/davyxu/cellnet/proc" 9 | "github.com/davyxu/cellnet/proc/tcp" 10 | ) 11 | 12 | type subscriberHooker struct { 13 | } 14 | 15 | func (self subscriberHooker) OnInboundEvent(inputEvent cellnet.Event) (outputEvent cellnet.Event) { 16 | 17 | switch inputEvent.Message().(type) { 18 | case *cellnet.SessionConnected: // 连接上hub时 19 | 20 | model.HubSession = inputEvent.Session() 21 | 22 | // 自动订阅进程名和svcid对应的频道 23 | Subscribe(service.GetProcName()) 24 | Subscribe(service.GetLocalSvcID()) 25 | 26 | // 玩家自定义频道 27 | if model.OnHubReady != nil { 28 | cellnet.QueuedCall(fxmodel.Queue, model.OnHubReady) 29 | } 30 | 31 | } 32 | 33 | return inputEvent 34 | } 35 | 36 | func (self subscriberHooker) OnOutboundEvent(inputEvent cellnet.Event) (outputEvent cellnet.Event) { 37 | 38 | return inputEvent 39 | } 40 | 41 | func init() { 42 | 43 | proc.RegisterProcessor("tcp.hub", func(bundle proc.ProcessorBundle, userCallback cellnet.EventCallback, args ...interface{}) { 44 | 45 | bundle.SetTransmitter(new(tcp.TCPMessageTransmitter)) 46 | bundle.SetHooker(proc.NewMultiHooker(new(subscriberHooker), new(tcp.MsgHooker))) 47 | bundle.SetCallback(proc.NewQueuedEventCallback(userCallback)) 48 | }) 49 | } 50 | -------------------------------------------------------------------------------- /svc/hub/status/api.go: -------------------------------------------------------------------------------- 1 | package hubstatus 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh_demo/svc/hub/model" 5 | "github.com/davyxu/cellmesh/service" 6 | "math/rand" 7 | "sort" 8 | ) 9 | 10 | func SelectServiceByLowUserCount(svcName, svcGroup string, mustConnected bool) (finalSvcID string) { 11 | 12 | var statusList []*model.Status 13 | model.VisitStatus(func(status *model.Status) bool { 14 | 15 | name, _, group, err := service.ParseSvcID(status.SvcID) 16 | if err != nil { 17 | return true 18 | } 19 | 20 | if name != svcName { 21 | return true 22 | } 23 | 24 | if svcGroup == "" || svcGroup == group { 25 | 26 | if !mustConnected || service.GetRemoteService(status.SvcID) != nil { 27 | statusList = append(statusList, status) 28 | } 29 | 30 | } 31 | 32 | return true 33 | }) 34 | 35 | total := len(statusList) 36 | 37 | switch total { 38 | case 0: 39 | return "" 40 | case 1: 41 | return statusList[0].SvcID 42 | default: 43 | 44 | sort.Slice(statusList, func(i, j int) bool { 45 | a := statusList[i] 46 | b := statusList[j] 47 | return a.UserCount < b.UserCount 48 | }) 49 | 50 | lowRange := MaxInt32(int32(total/3), int32(total)) 51 | lowList := statusList[:lowRange] 52 | 53 | final := lowList[rand.Int31n(lowRange)] 54 | finalSvcID = final.SvcID 55 | 56 | } 57 | 58 | return 59 | 60 | } 61 | 62 | func MaxInt32(a, b int32) int32 { 63 | if a > b { 64 | return a 65 | } 66 | 67 | return b 68 | } 69 | -------------------------------------------------------------------------------- /svc/login/login/login.go: -------------------------------------------------------------------------------- 1 | package login 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh_demo/basefx" 5 | "github.com/davyxu/cellmesh_demo/proto" 6 | "github.com/davyxu/cellmesh_demo/svc/hub/status" 7 | "github.com/davyxu/cellmesh/service" 8 | "github.com/davyxu/cellnet" 9 | "github.com/davyxu/cellnet/util" 10 | ) 11 | 12 | func init() { 13 | proto.Handle_Login_LoginREQ = func(ev cellnet.Event) { 14 | 15 | //msg := ev.Message().(*proto.LoginREQ) 16 | // TODO 第三方请求验证及信息拉取 17 | 18 | var ack proto.LoginACK 19 | 20 | agentSvcID := hubstatus.SelectServiceByLowUserCount("agent", "", false) 21 | if agentSvcID == "" { 22 | ack.Result = proto.ResultCode_AgentNotFound 23 | 24 | service.Reply(ev, &ack) 25 | return 26 | } 27 | 28 | agentWAN := basefx.GetRemoteServiceWANAddress("agent", agentSvcID) 29 | 30 | 31 | host, port, err := util.SpliteAddress(agentWAN) 32 | if err != nil { 33 | log.Errorf("invalid address: '%s' %s", agentWAN, err.Error()) 34 | 35 | ack.Result = proto.ResultCode_AgentAddressError 36 | 37 | service.Reply(ev, &ack) 38 | return 39 | } 40 | 41 | ack.Server = &proto.ServerInfo{ 42 | IP: host, 43 | Port: int32(port), 44 | } 45 | 46 | ack.GameSvcID = hubstatus.SelectServiceByLowUserCount("game", "", false) 47 | 48 | if ack.GameSvcID == "" { 49 | ack.Result = proto.ResultCode_GameNotFound 50 | 51 | service.Reply(ev, &ack) 52 | return 53 | } 54 | 55 | service.Reply(ev, &ack) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /basefx/model/localsvc.go: -------------------------------------------------------------------------------- 1 | package fxmodel 2 | 3 | import ( 4 | "github.com/davyxu/cellnet" 5 | "sync" 6 | ) 7 | 8 | var ( 9 | localServices []cellnet.Peer 10 | localServicesGuard sync.RWMutex 11 | ) 12 | 13 | func AddLocalService(p cellnet.Peer) { 14 | localServicesGuard.Lock() 15 | localServices = append(localServices, p) 16 | localServicesGuard.Unlock() 17 | } 18 | 19 | func RemoveLocalService(p cellnet.Peer) { 20 | localServicesGuard.Lock() 21 | for index, libp := range localServices { 22 | if libp == p { 23 | localServices = append(localServices[:index], localServices[index+1:]...) 24 | break 25 | } 26 | 27 | } 28 | localServicesGuard.Unlock() 29 | } 30 | 31 | func GetLocalService(svcName string) cellnet.Peer { 32 | 33 | localServicesGuard.RLock() 34 | defer localServicesGuard.RUnlock() 35 | 36 | for _, svc := range localServices { 37 | if prop, ok := svc.(cellnet.PeerProperty); ok && prop.Name() == svcName { 38 | return svc 39 | } 40 | } 41 | 42 | return nil 43 | } 44 | 45 | func VisitLocalService(callback func(cellnet.Peer) bool) { 46 | localServicesGuard.RLock() 47 | defer localServicesGuard.RUnlock() 48 | 49 | for _, svc := range localServices { 50 | if !callback(svc) { 51 | break 52 | } 53 | } 54 | } 55 | 56 | func StopAllService() { 57 | localServicesGuard.RLock() 58 | defer localServicesGuard.RUnlock() 59 | 60 | for i := len(localServices) - 1; i >= 0; i-- { 61 | svc := localServices[i] 62 | svc.Stop() 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /svc/hub/status/recv.go: -------------------------------------------------------------------------------- 1 | package hubstatus 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh_demo/basefx/model" 5 | "github.com/davyxu/cellmesh_demo/proto" 6 | "github.com/davyxu/cellmesh_demo/svc/hub/api" 7 | "github.com/davyxu/cellmesh_demo/svc/hub/model" 8 | "github.com/davyxu/cellnet" 9 | "github.com/davyxu/cellnet/timer" 10 | "time" 11 | ) 12 | 13 | var ( 14 | recvLoop *timer.Loop 15 | ) 16 | 17 | const ( 18 | statusUpdateTimeout = time.Second * 3 19 | ) 20 | 21 | func StartRecvStatus(channelNames []string, svcStatusHandler *func(ev cellnet.Event)) { 22 | 23 | for _, channelName := range channelNames { 24 | hubapi.Subscribe(channelName) 25 | } 26 | 27 | *svcStatusHandler = func(ev cellnet.Event) { 28 | 29 | msg := ev.Message().(*proto.SvcStatusACK) 30 | 31 | model.UpdateStatus(&model.Status{ 32 | UserCount: msg.UserCount, 33 | SvcID: msg.SvcID, 34 | }) 35 | } 36 | 37 | // 保证可以重入 38 | if recvLoop == nil { 39 | recvLoop = timer.NewLoop(fxmodel.Queue, statusUpdateTimeout, func(loop *timer.Loop) { 40 | 41 | now := time.Now() 42 | var timeoutSvcID []string 43 | 44 | model.VisitStatus(func(status *model.Status) bool { 45 | if now.Sub(status.LastUpdate) > statusUpdateTimeout { 46 | timeoutSvcID = append(timeoutSvcID, status.SvcID) 47 | } 48 | 49 | return true 50 | }) 51 | 52 | for _, svcid := range timeoutSvcID { 53 | //log.Debugln("remove svc status: ", svcid) 54 | model.RemoveStatus(svcid) 55 | } 56 | 57 | }, nil) 58 | 59 | recvLoop.Notify().Start() 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /svc/login/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh_demo/basefx" 5 | fxmodel "github.com/davyxu/cellmesh_demo/basefx/model" 6 | "github.com/davyxu/cellmesh_demo/proto" 7 | hubapi "github.com/davyxu/cellmesh_demo/svc/hub/api" 8 | hubstatus "github.com/davyxu/cellmesh_demo/svc/hub/status" 9 | _ "github.com/davyxu/cellmesh_demo/svc/login/login" 10 | "github.com/davyxu/cellnet" 11 | _ "github.com/davyxu/cellnet/peer/gorillaws" 12 | "github.com/davyxu/cellnet/proc" 13 | "github.com/davyxu/cellnet/proc/gorillaws" 14 | "github.com/davyxu/golog" 15 | ) 16 | 17 | var log = golog.New("main") 18 | 19 | func main() { 20 | 21 | basefx.Init("login") 22 | 23 | // 与客户端通信的处理器 24 | proc.RegisterProcessor("ws.client", func(bundle proc.ProcessorBundle, userCallback cellnet.EventCallback, args ...interface{}) { 25 | 26 | bundle.SetTransmitter(new(gorillaws.WSMessageTransmitter)) 27 | bundle.SetHooker(proc.NewMultiHooker(new(gorillaws.MsgHooker))) 28 | bundle.SetCallback(proc.NewQueuedEventCallback(userCallback)) 29 | }) 30 | 31 | switch *fxmodel.FlagCommunicateType { 32 | case "tcp": 33 | basefx.CreateCommnicateAcceptor(fxmodel.ServiceParameter{ 34 | SvcName: "login", 35 | NetPeerType: "tcp.Acceptor", 36 | NetProcName: "tcp.client", 37 | ListenAddr: ":0", 38 | }) 39 | case "ws": 40 | basefx.CreateCommnicateAcceptor(fxmodel.ServiceParameter{ 41 | SvcName: "login", 42 | NetPeerType: "gorillaws.Acceptor", 43 | NetProcName: "ws.client", 44 | ListenAddr: ":0", 45 | }) 46 | } 47 | 48 | hubapi.ConnectToHub(func() { 49 | 50 | // 开始接收game状态 51 | hubstatus.StartRecvStatus([]string{"game_status", "agent_status"}, &proto.Handle_Login_SvcStatusACK) 52 | }) 53 | 54 | basefx.StartLoop(nil) 55 | 56 | basefx.Exit() 57 | } 58 | -------------------------------------------------------------------------------- /svc/agent/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh/service" 5 | "github.com/davyxu/cellmesh_demo/basefx" 6 | "github.com/davyxu/cellmesh_demo/basefx/model" 7 | _ "github.com/davyxu/cellmesh_demo/proto" // 进入协议 8 | _ "github.com/davyxu/cellmesh_demo/svc/agent/backend" 9 | "github.com/davyxu/cellmesh_demo/svc/agent/frontend" 10 | "github.com/davyxu/cellmesh_demo/svc/agent/heartbeat" 11 | "github.com/davyxu/cellmesh_demo/svc/agent/model" 12 | "github.com/davyxu/cellmesh_demo/svc/agent/routerule" 13 | "github.com/davyxu/cellmesh_demo/svc/hub/api" 14 | "github.com/davyxu/cellmesh_demo/svc/hub/status" 15 | _ "github.com/davyxu/cellnet/peer/gorillaws" 16 | "github.com/davyxu/golog" 17 | "time" 18 | ) 19 | 20 | var log = golog.New("main") 21 | 22 | func main() { 23 | 24 | basefx.Init("agent") 25 | 26 | routerule.Download() 27 | 28 | heartbeat.StartCheck() 29 | 30 | model.AgentSvcID = service.GetLocalSvcID() 31 | 32 | // 要连接的服务列表 33 | basefx.CreateCommnicateConnector(fxmodel.ServiceParameter{ 34 | SvcName: "game", 35 | MaxConnCount: -1, 36 | NetProcName: "agent.backend", 37 | }) 38 | 39 | switch *fxmodel.FlagCommunicateType { 40 | case "tcp": 41 | frontend.Start(model.FrontendParameter{ 42 | SvcName: "agent", 43 | ListenAddr: ":0", 44 | NetPeerType: "tcp.Acceptor", 45 | NetProcName: "tcp.frontend", 46 | }) 47 | case "ws": 48 | frontend.Start(model.FrontendParameter{ 49 | SvcName: "agent", 50 | ListenAddr: ":0", 51 | NetPeerType: "gorillaws.Acceptor", 52 | NetProcName: "ws.frontend", 53 | }) 54 | } 55 | 56 | hubapi.ConnectToHub(func() { 57 | 58 | // 发送网关连接数量 59 | hubstatus.StartSendStatus("agent_status", time.Second*3, func() int { 60 | return model.FrontendSessionManager.SessionCount() 61 | }) 62 | }) 63 | 64 | basefx.StartLoop(nil) 65 | 66 | frontend.Stop() 67 | 68 | basefx.Exit() 69 | } 70 | -------------------------------------------------------------------------------- /svc/agent/model/user.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "errors" 5 | "github.com/davyxu/cellmesh_demo/proto" 6 | "github.com/davyxu/cellmesh/service" 7 | "github.com/davyxu/cellnet" 8 | "time" 9 | ) 10 | 11 | type Backend struct { 12 | SvcName string 13 | SvcID string // 只保留绑定后台的svcid,即便后台更换session,也无需同步 14 | } 15 | 16 | type User struct { 17 | ClientSession cellnet.Session 18 | Targets []*Backend 19 | LastPingTime time.Time 20 | 21 | CID proto.ClientID 22 | } 23 | 24 | // 广播到这个用户绑定的所有后台 25 | func (self *User) BroadcastToBackends(msg interface{}) { 26 | 27 | for _, t := range self.Targets { 28 | 29 | backendSes := service.GetRemoteService(t.SvcID) 30 | if backendSes != nil { 31 | backendSes.Send(msg) 32 | } 33 | } 34 | } 35 | 36 | var ( 37 | ErrBackendNotFound = errors.New("backend not found") 38 | ) 39 | 40 | func (self *User) TransmitToBackend(backendSvcid string, msgID int, msgData []byte) error { 41 | 42 | backendSes := service.GetRemoteService(backendSvcid) 43 | 44 | if backendSes == nil { 45 | return ErrBackendNotFound 46 | } 47 | 48 | backendSes.Send(&proto.TransmitACK{ 49 | MsgID: uint32(msgID), 50 | MsgData: msgData, 51 | ClientID: self.CID.ID, 52 | }) 53 | 54 | return nil 55 | } 56 | 57 | // 绑定用户后台 58 | func (self *User) SetBackend(svcName string, svcID string) { 59 | 60 | for _, t := range self.Targets { 61 | if t.SvcName == svcName { 62 | t.SvcID = svcID 63 | return 64 | } 65 | } 66 | 67 | self.CID = proto.ClientID{ 68 | ID: self.ClientSession.ID(), 69 | SvcID: AgentSvcID, 70 | } 71 | 72 | self.Targets = append(self.Targets, &Backend{ 73 | SvcName: svcName, 74 | SvcID: svcID, 75 | }) 76 | } 77 | 78 | func (self *User) GetBackend(svcName string) string { 79 | 80 | for _, t := range self.Targets { 81 | if t.SvcName == svcName { 82 | return t.SvcID 83 | } 84 | } 85 | 86 | return "" 87 | } 88 | 89 | func NewUser(clientSes cellnet.Session) *User { 90 | return &User{ 91 | ClientSession: clientSes, 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /tool/routegen/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "flag" 6 | "fmt" 7 | "github.com/davyxu/cellmesh_demo/table" 8 | "github.com/davyxu/cellmesh/discovery" 9 | "github.com/davyxu/cellmesh/discovery/memsd/api" 10 | "github.com/davyxu/protoplus/model" 11 | "github.com/davyxu/protoplus/msgidutil" 12 | "github.com/davyxu/protoplus/util" 13 | "os" 14 | ) 15 | 16 | // 从Proto文件中获取路由信息 17 | func GenRouteTable(dset *model.DescriptorSet) (ret *table.RouteTable) { 18 | 19 | ret = new(table.RouteTable) 20 | 21 | for _, d := range dset.Structs() { 22 | 23 | if d.TagValueString("RouteRule") != "" && d.TagValueString("Service") != "" { 24 | 25 | ret.Rule = append(ret.Rule, &table.RouteRule{ 26 | MsgName: d.Name, 27 | SvcName: d.TagValueString("Service"), 28 | Mode: d.TagValueString("RouteRule"), 29 | MsgID: msgidutil.StructMsgID(d), 30 | }) 31 | } 32 | } 33 | 34 | return 35 | } 36 | 37 | // 上传路由表到consul KV 38 | func UploadRouteTable(tab *table.RouteTable) error { 39 | 40 | data, err := json.MarshalIndent(tab, "", "\t") 41 | 42 | if err != nil { 43 | return err 44 | } 45 | 46 | fmt.Printf("Write '%s'", *flagConfigPath) 47 | return discovery.Default.SetValue(*flagConfigPath, string(data)) 48 | } 49 | 50 | var ( 51 | flagConfigPath = flag.String("configpath", "config_demo/route_rule", "discovery kv config path") 52 | ) 53 | 54 | var ( 55 | flagPackage = flag.String("package", "", "package name in source files") 56 | ) 57 | 58 | func main() { 59 | 60 | flag.Parse() 61 | 62 | discovery.Default = memsd.NewDiscovery(nil) 63 | 64 | dset := new(model.DescriptorSet) 65 | dset.PackageName = *flagPackage 66 | 67 | var routeTable *table.RouteTable 68 | 69 | err := util.ParseFileList(dset) 70 | 71 | if err != nil { 72 | goto OnError 73 | } 74 | 75 | routeTable = GenRouteTable(dset) 76 | 77 | err = UploadRouteTable(routeTable) 78 | 79 | if err != nil { 80 | goto OnError 81 | } 82 | 83 | return 84 | 85 | OnError: 86 | fmt.Println(err) 87 | os.Exit(1) 88 | } 89 | -------------------------------------------------------------------------------- /proto/MakeProto.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | BinaryDir=../bin 6 | 7 | ProtocBinary=${BinaryDir}/protoc 8 | 9 | Platform=$(go env GOHOSTOS) 10 | 11 | if [[ ${Platform} == "linux" ]]; then 12 | DownloadURL=https://github.com/protocolbuffers/protobuf/releases/download/v3.8.0/protoc-3.8.0-linux-x86_64.zip 13 | elif [[ ${Platform} == "darwin" ]]; then 14 | DownloadURL=https://github.com/protocolbuffers/protobuf/releases/download/v3.8.0/protoc-3.8.0-osx-x86_64.zip 15 | elif [[ ${Platform} == "windows" ]]; then 16 | DownloadURL=https://github.com/protocolbuffers/protobuf/releases/download/v3.8.0/protoc-3.8.0-win64.zip 17 | ProtocBinary=${ProtocBinary}.exe 18 | fi 19 | 20 | # https://github.com/golang/protobuf/blob/master/.travis.yml 21 | if [[ ! -f ${ProtocBinary} ]]; then 22 | echo "Google protocol buffer compiler is not installed, download from ${DownloadURL} and place at ${BinaryDir}" 23 | exit 1 24 | fi 25 | 26 | # cellmesh服务绑定 27 | CellMeshProtoGen=${BinaryDir}/cmprotogen 28 | go build -v -o ${CellMeshProtoGen} github.com/davyxu/cellmesh/tool/protogen 29 | 30 | # 协议生成 31 | ProtoPlusGen=${BinaryDir}/protoplus 32 | go build -v -o ${ProtoPlusGen} github.com/davyxu/protoplus 33 | 34 | # pb插件 35 | GoGoFaster=${BinaryDir}/protoc-gen-gogofaster 36 | go build -v -o ${GoGoFaster} github.com/gogo/protobuf/protoc-gen-gogofaster 37 | 38 | # 路由工具 39 | RouteGen=${BinaryDir}/routegen 40 | go build -v -o ${RouteGen} github.com/davyxu/cellmesh_demo/tool/routegen 41 | 42 | echo "生成服务器协议的go消息..." 43 | ${ProtoPlusGen} -package=proto -go_out=msgsvc_gen.go `source ./protolist.sh svc` 44 | 45 | echo "生成服务器协议的消息绑定..." 46 | ${CellMeshProtoGen} -package=proto -cmgo_out=msgbind_gen.go `source ./protolist.sh all` 47 | 48 | echo "生成客户端协议的protobuf proto文件..." 49 | ${ProtoPlusGen} --package=proto -pb_out=clientmsg_gen.proto `source ./protolist.sh client` 50 | 51 | echo "生成客户端协议的protobuf的go消息...." 52 | ${ProtocBinary} --plugin=protoc-gen-gogofaster=${GoGoFaster} --gogofaster_out=. --proto_path=. clientmsg_gen.proto 53 | 54 | # 不使用protobuf协议文件,只使用生成后的go文件,删除之 55 | rm -f ./clientmsg_gen.proto 56 | 57 | 58 | echo "更新agent路由表" 59 | ${RouteGen} -package=proto -configpath=config_demo/route_rule `source ./protolist.sh client` 60 | -------------------------------------------------------------------------------- /svc/agent/backend/router_msg.go: -------------------------------------------------------------------------------- 1 | package backend 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh_demo/proto" 5 | "github.com/davyxu/cellmesh_demo/svc/agent/model" 6 | "github.com/davyxu/cellnet" 7 | ) 8 | 9 | func init() { 10 | 11 | proto.Handle_Agent_CloseClientACK = func(ev cellnet.Event) { 12 | 13 | msg := ev.Message().(*proto.CloseClientACK) 14 | 15 | // 不给ID,掐线这个网关的所有客户端 16 | if len(msg.ID) == 0 { 17 | model.VisitUser(func(user *model.User) bool { 18 | user.ClientSession.Close() 19 | return true 20 | }) 21 | 22 | } else { 23 | // 关闭指定的客户端 24 | for _, sesid := range msg.ID { 25 | if u := model.GetUser(sesid); u != nil { 26 | u.ClientSession.Close() 27 | } 28 | } 29 | 30 | } 31 | 32 | } 33 | 34 | proto.Handle_Agent_Default = func(ev cellnet.Event) { 35 | 36 | //switch msg := ev.Message().(type) { 37 | //case *service.ServiceIdentifyACK: 38 | // recoverBackend(ev.Session(), msg.SvcName) 39 | //case *cellnet.SessionClosed: 40 | // removeBackend(ev.Session()) 41 | //} 42 | } 43 | 44 | //// 从后端服务器收到的消息 45 | //relay.SetBroadcaster(func(ev *relay.RecvMsgEvent) { 46 | // 47 | // // 列表广播 48 | // if value := ev.PassThroughAsInt64Slice(); value != nil { 49 | // for _, sesid := range value { 50 | // ses := model.GetClientSession(sesid) 51 | // if ses != nil { 52 | // ses.Send(ev.Msg) 53 | // } 54 | // } 55 | // // 原样回复 56 | // }else if svcid := ev.PassThroughAsString(); svcid != "" { 57 | // if svcid == model.AgentSvcID { 58 | // ses := model.GetClientSession(ev.PassThroughAsInt64()) 59 | // if ses != nil { 60 | // ses.Send(ev.Msg) 61 | // } 62 | // } else { 63 | // panic(fmt.Sprintf("Recv backend msg not belong to this agent, expect '%s', got '%s'", model.AgentSvcID, svcid)) 64 | // } 65 | // // 单发 66 | // } else if clientSesID := ev.PassThroughAsInt64(); clientSesID != 0 { 67 | // ses := model.GetClientSession(clientSesID) 68 | // if ses != nil { 69 | // ses.Send(ev.Msg) 70 | // } 71 | // } else { 72 | // // TODO 只广播给认证用户? 73 | // model.FrontendSessionManager.VisitSession(func(clientSes cellnet.Session) bool { 74 | // 75 | // clientSes.Send(ev.Message()) 76 | // 77 | // return true 78 | // }) 79 | // 80 | // } 81 | // 82 | //}) 83 | 84 | } 85 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/ahmetb/go-linq v3.0.0+incompatible/go.mod h1:PFffvbdbtw+QTB0WKRP0cNht7vnCfnGlEpak/DVg5cY= 2 | github.com/davyxu/cellmesh v0.1.1-0.20190628065349-a255c0e4e086 h1:8M9DHQB9iZ2uNjAP8356ien1X+X4LzhrtxpK7eyHDnE= 3 | github.com/davyxu/cellmesh v0.1.1-0.20190628065349-a255c0e4e086/go.mod h1:3AXtvpdL+bED/AR3Y2taItIrxtRynSIfGM9ORNRhVL8= 4 | github.com/davyxu/cellnet v0.0.0-20190612112848-4f8cb890a9f8 h1:hnIRsbLMSkTNYPuA+ALM6R7yrV/1wl+J02dQ7pIv5Bw= 5 | github.com/davyxu/cellnet v0.0.0-20190612112848-4f8cb890a9f8/go.mod h1:veOb1czkqh9rfO/+KLeAIzRT9vOk9gg3LNXuCXV+QdQ= 6 | github.com/davyxu/cellnet v0.0.0-20190628065413-a644d2409b6d h1:M4eBkPiPdfcvRjhyMI9lwVdo63TxhiKwq0UWZO9/LI8= 7 | github.com/davyxu/cellnet v0.0.0-20190628065413-a644d2409b6d/go.mod h1:veOb1czkqh9rfO/+KLeAIzRT9vOk9gg3LNXuCXV+QdQ= 8 | github.com/davyxu/golexer v0.1.0 h1:PFavbgNV8PUH2HPU1G3o0QMcNJ3I4BkL8esbeenTyMU= 9 | github.com/davyxu/golexer v0.1.0/go.mod h1:K/1PVWqaQEwMs+N+VvaoS66o1BAAwso+jEgXKBIa8QY= 10 | github.com/davyxu/golog v0.1.0 h1:SsV3m2x37sCzFaQzq5OHc5S+PE2VMiL7XUx34JCa7mo= 11 | github.com/davyxu/golog v0.1.0/go.mod h1:YwChkFY5dCYt77yuPlWjcR6KlWqVJNbz3WkwC/8WgQk= 12 | github.com/davyxu/goobjfmt v0.1.0 h1:/Kz4X/UL4Jf5xOaQhP5DxzNtcwsfJqsz6ceoePeHBgA= 13 | github.com/davyxu/goobjfmt v0.1.0/go.mod h1:KKrytCtCXny2sEg3ojQfJ4NThhBP8hKw/qM9vhDwgog= 14 | github.com/davyxu/protoplus v0.1.0 h1:iKk94nwYZdEK8r1r4GZDkW7JnmLJTPYQSVUvBLBxsb8= 15 | github.com/davyxu/protoplus v0.1.0/go.mod h1:WzmNYPvYsyks3G81jCJ/vGY2ljs49qFMfCmXGwvxFLA= 16 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 17 | github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= 18 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= 19 | github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= 20 | github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 21 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 22 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 23 | github.com/mediocregopher/radix.v2 v0.0.0-20181115013041-b67df6e626f9/go.mod h1:fLRUbhbSd5Px2yKUaGYYPltlyxi1guJz1vCmo1RQL50= 24 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 25 | -------------------------------------------------------------------------------- /basefx/model/localsvcchecker.go: -------------------------------------------------------------------------------- 1 | package fxmodel 2 | 3 | import ( 4 | "fmt" 5 | "github.com/davyxu/cellmesh/discovery" 6 | "github.com/davyxu/cellmesh/service" 7 | "github.com/davyxu/cellnet" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | func getPeerStatus(svc cellnet.Peer) string { 13 | 14 | type myPeer interface { 15 | cellnet.PeerReadyChecker 16 | Name() string 17 | Address() string 18 | cellnet.Peer 19 | } 20 | mp := svc.(myPeer) 21 | 22 | var ready string 23 | if mp.IsReady() { 24 | ready = "READY" 25 | } 26 | 27 | var peerName string 28 | var context string 29 | if cs, ok := svc.(cellnet.ContextSet); ok { 30 | 31 | var desc *discovery.ServiceDesc 32 | if cs.FetchContext("sd", &desc) { 33 | context = fmt.Sprintf("--> %22s %22s", desc.ID, desc.Address()) 34 | peerName = desc.Name 35 | } else { 36 | context = mp.Address() 37 | peerName = mp.Name() 38 | } 39 | } 40 | 41 | return fmt.Sprintf("%13s %15s %s [%s]", peerName, mp.TypeName(), context, ready) 42 | } 43 | 44 | func MultiPeerString(ms service.MultiPeer) string { 45 | 46 | raw, ok := ms.GetContext("multi") 47 | if !ok { 48 | return "" 49 | } 50 | 51 | param := raw.(ServiceParameter) 52 | 53 | return fmt.Sprintf("%13s %15s", param.SvcName, param.NetPeerType) 54 | } 55 | 56 | func LocalServiceStatus() string { 57 | 58 | var sb strings.Builder 59 | 60 | VisitLocalService(func(svc cellnet.Peer) bool { 61 | 62 | if pg, ok := svc.(service.MultiPeer); ok { 63 | 64 | // 没有连接发现时 65 | if len(pg.GetPeers()) == 0 { 66 | sb.WriteString(MultiPeerString(pg)) 67 | sb.WriteString("\n") 68 | } else { 69 | for _, p := range pg.GetPeers() { 70 | sb.WriteString(getPeerStatus(p)) 71 | sb.WriteString("\n") 72 | } 73 | } 74 | 75 | } else { 76 | sb.WriteString(getPeerStatus(svc)) 77 | sb.WriteString("\n") 78 | } 79 | 80 | return true 81 | }) 82 | 83 | return sb.String() 84 | } 85 | 86 | func IsAllReady() (ret bool) { 87 | ret = true 88 | VisitLocalService(func(svc cellnet.Peer) bool { 89 | if !svc.(cellnet.PeerReadyChecker).IsReady() { 90 | ret = false 91 | return false 92 | } 93 | 94 | return true 95 | }) 96 | 97 | return 98 | } 99 | 100 | func CheckReady() { 101 | 102 | var lastStatus string 103 | for { 104 | 105 | time.Sleep(time.Second * 3) 106 | 107 | if IsAllReady() { 108 | log.SetColor("green").Infof("All peers ready!\n%s", LocalServiceStatus()) 109 | 110 | break 111 | } 112 | 113 | thisStatus := LocalServiceStatus() 114 | 115 | if lastStatus != thisStatus { 116 | log.Warnf("peers not all ready\n%s", thisStatus) 117 | lastStatus = thisStatus 118 | } 119 | 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /basefx/createpeer.go: -------------------------------------------------------------------------------- 1 | package basefx 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh/discovery" 5 | "github.com/davyxu/cellmesh/service" 6 | "github.com/davyxu/cellmesh_demo/basefx/model" 7 | "github.com/davyxu/cellmesh_demo/proto" 8 | "github.com/davyxu/cellnet" 9 | "github.com/davyxu/cellnet/peer" 10 | "github.com/davyxu/cellnet/proc" 11 | "time" 12 | ) 13 | 14 | func CreateCommnicateAcceptor(param fxmodel.ServiceParameter) cellnet.Peer { 15 | 16 | if param.NetPeerType == "" { 17 | param.NetPeerType = "tcp.Acceptor" 18 | } 19 | 20 | var q cellnet.EventQueue 21 | if !param.NoQueue { 22 | q = fxmodel.Queue 23 | } 24 | 25 | p := peer.NewGenericPeer(param.NetPeerType, param.SvcName, param.ListenAddr, q) 26 | 27 | msgFunc := proto.GetMessageHandler(param.SvcName) 28 | 29 | //"tcp.svc" 30 | proc.BindProcessorHandler(p, param.NetProcName, func(ev cellnet.Event) { 31 | 32 | if msgFunc != nil { 33 | msgFunc(ev) 34 | } 35 | }) 36 | 37 | if opt, ok := p.(cellnet.TCPSocketOption); ok { 38 | opt.SetSocketBuffer(2048, 2048, true) 39 | } 40 | 41 | fxmodel.AddLocalService(p) 42 | 43 | p.Start() 44 | 45 | service.Register(p) 46 | 47 | return p 48 | } 49 | 50 | func CreateCommnicateConnector(param fxmodel.ServiceParameter) { 51 | if param.NetPeerType == "" { 52 | param.NetPeerType = "tcp.Connector" 53 | } 54 | 55 | msgFunc := proto.GetMessageHandler(service.GetProcName()) 56 | 57 | opt := service.DiscoveryOption{ 58 | MaxCount: param.MaxConnCount, 59 | } 60 | 61 | opt.Rules = service.LinkRules 62 | 63 | var q cellnet.EventQueue 64 | if !param.NoQueue { 65 | q = fxmodel.Queue 66 | } 67 | 68 | mp := service.DiscoveryService(param.SvcName, opt, func(multiPeer service.MultiPeer, sd *discovery.ServiceDesc) { 69 | 70 | p := peer.NewGenericPeer(param.NetPeerType, param.SvcName, sd.Address(), q) 71 | 72 | proc.BindProcessorHandler(p, param.NetProcName, func(ev cellnet.Event) { 73 | 74 | if msgFunc != nil { 75 | msgFunc(ev) 76 | } 77 | }) 78 | 79 | if opt, ok := p.(cellnet.TCPSocketOption); ok { 80 | opt.SetSocketBuffer(2048, 2048, true) 81 | } 82 | 83 | p.(cellnet.TCPConnector).SetReconnectDuration(time.Second * 3) 84 | 85 | // 86 | multiPeer.AddPeer(sd, p) 87 | 88 | p.Start() 89 | }) 90 | 91 | mp.(service.MultiPeer).SetContext("multi", param) 92 | 93 | fxmodel.AddLocalService(mp) 94 | 95 | } 96 | 97 | func GetRemoteServiceWANAddress(svcName, svcid string) string { 98 | 99 | result := service.QueryService(svcName, 100 | service.Filter_MatchSvcID(svcid)) 101 | 102 | if result == nil { 103 | return "" 104 | } 105 | 106 | desc := result.(*discovery.ServiceDesc) 107 | 108 | wanAddr := desc.GetMeta("WANAddress") 109 | 110 | if wanAddr != "" { 111 | return wanAddr 112 | } 113 | 114 | // 开发阶段, 返回内网IP 115 | return desc.Address() 116 | } 117 | -------------------------------------------------------------------------------- /svc/agent/api/broadcast.go: -------------------------------------------------------------------------------- 1 | package agentapi 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh_demo/proto" 5 | "github.com/davyxu/cellmesh/service" 6 | "github.com/davyxu/cellnet" 7 | "github.com/davyxu/cellnet/codec" 8 | ) 9 | 10 | // 关闭所有网关上客户端的连接 11 | func CloseAllClient() { 12 | 13 | service.VisitRemoteService(func(ses cellnet.Session, ctx *service.RemoteServiceContext) bool { 14 | 15 | if ctx.Name == "agent" { 16 | ses.Send(&proto.CloseClientACK{ 17 | All: true, 18 | }) 19 | } 20 | 21 | return true 22 | }) 23 | } 24 | 25 | // 广播给所有客户端 26 | func BroadcastAll(msg interface{}) { 27 | 28 | data, meta, err := codec.EncodeMessage(msg, nil) 29 | if err != nil { 30 | log.Errorf("BroadcastAll.EncodeMessage %s", err) 31 | return 32 | } 33 | 34 | service.VisitRemoteService(func(ses cellnet.Session, ctx *service.RemoteServiceContext) bool { 35 | 36 | if ctx.Name == "agent" { 37 | ses.Send(&proto.TransmitACK{ 38 | MsgID: uint32(meta.ID), 39 | MsgData: data, 40 | All: true, 41 | }) 42 | } 43 | 44 | return true 45 | }) 46 | } 47 | 48 | // 给客户端发消息 49 | func Send(cid *proto.ClientID, msg interface{}) { 50 | 51 | agentSes := service.GetRemoteService(cid.SvcID) 52 | if agentSes != nil { 53 | data, meta, err := codec.EncodeMessage(msg, nil) 54 | if err != nil { 55 | log.Errorf("Send.EncodeMessage %s", err) 56 | return 57 | } 58 | 59 | agentSes.Send(&proto.TransmitACK{ 60 | MsgID: uint32(meta.ID), 61 | MsgData: data, 62 | ClientID: cid.ID, 63 | }) 64 | } 65 | } 66 | 67 | type ClientList struct { 68 | sesByAgentSvcID map[string][]int64 69 | } 70 | 71 | // 添加客户端 72 | func (self *ClientList) AddClient(cid *proto.ClientID) { 73 | seslist := self.sesByAgentSvcID[cid.SvcID] 74 | seslist = append(seslist, cid.ID) 75 | self.sesByAgentSvcID[cid.SvcID] = seslist 76 | } 77 | 78 | // 关闭列表中客户端的连接 79 | func (self *ClientList) CloseClient() { 80 | for agentSvcID, sesList := range self.sesByAgentSvcID { 81 | 82 | agentSes := service.GetRemoteService(agentSvcID) 83 | if agentSes != nil { 84 | agentSes.Send(&proto.CloseClientACK{ 85 | ID: sesList, 86 | }) 87 | } 88 | } 89 | } 90 | 91 | // 将消息广播给列表中的客户端 92 | func (self *ClientList) Broadcast(msg interface{}) { 93 | 94 | data, meta, err := codec.EncodeMessage(msg, nil) 95 | if err != nil { 96 | log.Errorf("ClientList.EncodeMessage %s", err) 97 | return 98 | } 99 | 100 | for agentSvcID, sesList := range self.sesByAgentSvcID { 101 | 102 | agentSes := service.GetRemoteService(agentSvcID) 103 | if agentSes != nil { 104 | 105 | agentSes.Send(&proto.TransmitACK{ 106 | MsgID: uint32(meta.ID), 107 | MsgData: data, 108 | ClientIDList: sesList, 109 | }) 110 | 111 | } else { 112 | log.Warnf("Agent not ready, ignore msg, svcid: '%s' msg: '%+v'", agentSvcID, msg) 113 | } 114 | } 115 | } 116 | 117 | // 创建一个客户端列表 118 | func NewClientList() *ClientList { 119 | 120 | return &ClientList{ 121 | sesByAgentSvcID: make(map[string][]int64), 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /svc/client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "flag" 6 | "fmt" 7 | "github.com/davyxu/cellmesh_demo/proto" 8 | "github.com/davyxu/cellmesh/service" 9 | "github.com/davyxu/cellnet" 10 | "github.com/davyxu/cellnet/msglog" 11 | _ "github.com/davyxu/cellnet/peer/gorillaws" 12 | "github.com/davyxu/cellnet/timer" 13 | "github.com/davyxu/golog" 14 | "os" 15 | "strings" 16 | "time" 17 | ) 18 | 19 | var log = golog.New("main") 20 | 21 | type ClientParam struct { 22 | NetPeerType string 23 | NetProcName string 24 | } 25 | 26 | var ( 27 | flagProtocolType = flag.String("commtype", "tcp", "communicate type, tcp or ws") 28 | ) 29 | 30 | // 登录服务器是一个短连接服务器,获取到网关连接后就断开 31 | func login(param *ClientParam) (agentAddr, gameSvcID string) { 32 | 33 | log.Debugln("Create login connection...") 34 | 35 | // 这里为了方便,使用服务发现来连接login, 真正的客户端不应该使用服务发现,而是使用固定的登录地址连接登录服务器 36 | loginReq := CreateConnection("login", param.NetPeerType, param.NetProcName) 37 | 38 | // TODO 短连接请求完毕关闭 39 | 40 | // 封装连接和接收以及超时的过程,真正的客户端可以添加这套机制 41 | RemoteCall(loginReq, &proto.LoginREQ{ 42 | Version: "1.0", 43 | Platform: "demo", 44 | UID: "1234", 45 | }, func(ack *proto.LoginACK) { 46 | 47 | if ack.Result == proto.ResultCode_NoError { 48 | agentAddr = fmt.Sprintf("%s:%d", ack.Server.IP, ack.Server.Port) 49 | gameSvcID = ack.GameSvcID 50 | } else { 51 | panic(ack.Result.String()) 52 | } 53 | 54 | }) 55 | 56 | return 57 | } 58 | 59 | func getAgentSession(agentAddr string, param *ClientParam) (ret cellnet.Session) { 60 | 61 | log.Debugln("Prepare agent connection...") 62 | 63 | waitGameReady := make(chan struct{}) 64 | go KeepConnection("agent", agentAddr, param.NetPeerType, param.NetProcName, func(ses cellnet.Session) { 65 | ret = ses 66 | waitGameReady <- struct{}{} 67 | }, func() { 68 | os.Exit(0) 69 | }) 70 | 71 | <-waitGameReady 72 | 73 | log.Debugln("Agent connection ready") 74 | 75 | return 76 | } 77 | 78 | func ReadConsole(callback func(string)) { 79 | 80 | for { 81 | 82 | // 从标准输入读取字符串,以\n为分割 83 | text, err := bufio.NewReader(os.Stdin).ReadString('\n') 84 | if err != nil { 85 | break 86 | } 87 | 88 | // 去掉读入内容的空白符 89 | text = strings.TrimSpace(text) 90 | 91 | callback(text) 92 | 93 | } 94 | } 95 | 96 | func main() { 97 | 98 | msglog.SetMsgLogRule("proto.PingACK", msglog.MsgLogRule_BlackList) 99 | 100 | service.Init("client") 101 | service.ConnectDiscovery() 102 | 103 | var currParam *ClientParam 104 | switch *flagProtocolType { 105 | case "tcp": 106 | currParam = &ClientParam{NetPeerType: "tcp.SyncConnector", NetProcName: "tcp.demo"} 107 | case "ws": 108 | currParam = &ClientParam{NetPeerType: "gorillaws.SyncConnector", NetProcName: "ws.demo"} 109 | } 110 | 111 | agentAddr, gameSvcID := login(currParam) 112 | 113 | if agentAddr == "" { 114 | return 115 | } 116 | 117 | fmt.Println("agent:", agentAddr) 118 | 119 | agentReq := getAgentSession(agentAddr, currParam) 120 | 121 | RemoteCall(agentReq, &proto.VerifyREQ{ 122 | GameToken: "verify", 123 | GameSvcID: gameSvcID, 124 | }, func(ack *proto.VerifyACK) { 125 | 126 | fmt.Println(ack) 127 | }) 128 | 129 | // 130 | timer.NewLoop(nil, time.Second*5, func(loop *timer.Loop) { 131 | agentReq.Send(&proto.PingACK{}) 132 | 133 | }, nil).Start() 134 | 135 | fmt.Println("Start chat now !") 136 | 137 | ReadConsole(func(s string) { 138 | 139 | RemoteCall(agentReq, &proto.ChatREQ{ 140 | Content: s, 141 | }, func(ack *proto.ChatACK) { 142 | 143 | fmt.Println(ack.Content) 144 | }) 145 | 146 | }) 147 | 148 | } 149 | -------------------------------------------------------------------------------- /svc/agent/frontend/transmitter.go: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import ( 4 | "encoding/binary" 5 | "github.com/davyxu/cellnet" 6 | "github.com/davyxu/cellnet/codec" 7 | "github.com/davyxu/cellnet/util" 8 | "github.com/gorilla/websocket" 9 | "io" 10 | "net" 11 | ) 12 | 13 | type socketOpt interface { 14 | MaxPacketSize() int 15 | ApplySocketReadTimeout(conn net.Conn, callback func()) 16 | ApplySocketWriteTimeout(conn net.Conn, callback func()) 17 | } 18 | 19 | type directTCPTransmitter struct { 20 | } 21 | 22 | // 来自客户端的消息 23 | func (directTCPTransmitter) OnRecvMessage(ses cellnet.Session) (msg interface{}, err error) { 24 | 25 | reader, ok := ses.Raw().(io.Reader) 26 | 27 | // 转换错误,或者连接已经关闭时退出 28 | if !ok || reader == nil { 29 | return nil, nil 30 | } 31 | 32 | opt := ses.Peer().(socketOpt) 33 | 34 | if conn, ok := ses.Raw().(net.Conn); ok { 35 | 36 | for { 37 | 38 | // 有读超时时,设置超时 39 | opt.ApplySocketReadTimeout(conn, func() { 40 | 41 | var msgID int 42 | var msgData []byte 43 | 44 | // 接收来自客户端的封包 45 | msgID, msgData, err = RecvLTVPacketData(reader, opt.MaxPacketSize()) 46 | 47 | // 尝试透传到后台或者解析 48 | if err == nil { 49 | msg, err = ProcFrontendPacket(msgID, msgData, ses) 50 | } 51 | 52 | }) 53 | 54 | // 有错退出 55 | if err != nil { 56 | break 57 | } 58 | 59 | // msg=nil时,透传了客户端的封包到后台, 不用传给下一个proc, 继续重新读取下一个包 60 | } 61 | 62 | } 63 | 64 | return 65 | } 66 | 67 | // 网关发往客户端的消息 68 | func (directTCPTransmitter) OnSendMessage(ses cellnet.Session, msg interface{}) (err error) { 69 | 70 | writer, ok := ses.Raw().(io.Writer) 71 | 72 | // 转换错误,或者连接已经关闭时退出 73 | if !ok || writer == nil { 74 | return nil 75 | } 76 | 77 | opt := ses.Peer().(socketOpt) 78 | 79 | // 有写超时时,设置超时 80 | opt.ApplySocketWriteTimeout(writer.(net.Conn), func() { 81 | 82 | err = util.SendLTVPacket(writer, ses.(cellnet.ContextSet), msg) 83 | 84 | }) 85 | 86 | return 87 | } 88 | 89 | const ( 90 | MsgIDSize = 2 // uint16 91 | ) 92 | 93 | type directWSMessageTransmitter struct { 94 | } 95 | 96 | func (directWSMessageTransmitter) OnRecvMessage(ses cellnet.Session) (msg interface{}, err error) { 97 | 98 | conn, ok := ses.Raw().(*websocket.Conn) 99 | 100 | // 转换错误,或者连接已经关闭时退出 101 | if !ok || conn == nil { 102 | return nil, nil 103 | } 104 | 105 | var ( 106 | messageType int 107 | raw []byte 108 | ) 109 | 110 | for { 111 | messageType, raw, err = conn.ReadMessage() 112 | 113 | if err != nil { 114 | break 115 | } 116 | 117 | switch messageType { 118 | case websocket.BinaryMessage: 119 | msgID := binary.LittleEndian.Uint16(raw) 120 | msgData := raw[MsgIDSize:] 121 | 122 | // 尝试透传到后台或者解析 123 | if err == nil { 124 | msg, err = ProcFrontendPacket(int(msgID), msgData, ses) 125 | } 126 | } 127 | 128 | if err != nil { 129 | break 130 | } 131 | 132 | } 133 | 134 | return 135 | 136 | } 137 | 138 | func (directWSMessageTransmitter) OnSendMessage(ses cellnet.Session, msg interface{}) error { 139 | 140 | conn, ok := ses.Raw().(*websocket.Conn) 141 | 142 | // 转换错误,或者连接已经关闭时退出 143 | if !ok || conn == nil { 144 | return nil 145 | } 146 | 147 | var ( 148 | msgData []byte 149 | msgID int 150 | ) 151 | 152 | switch m := msg.(type) { 153 | case *cellnet.RawPacket: // 发裸包 154 | msgData = m.MsgData 155 | msgID = m.MsgID 156 | default: // 发普通编码包 157 | var err error 158 | var meta *cellnet.MessageMeta 159 | 160 | // 将用户数据转换为字节数组和消息ID 161 | msgData, meta, err = codec.EncodeMessage(msg, nil) 162 | 163 | if err != nil { 164 | return err 165 | } 166 | 167 | msgID = meta.ID 168 | } 169 | 170 | pkt := make([]byte, MsgIDSize+len(msgData)) 171 | binary.LittleEndian.PutUint16(pkt, uint16(msgID)) 172 | copy(pkt[MsgIDSize:], msgData) 173 | 174 | conn.WriteMessage(websocket.BinaryMessage, pkt) 175 | 176 | return nil 177 | } 178 | -------------------------------------------------------------------------------- /svc/agent/frontend/hooker.go: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import ( 4 | "fmt" 5 | "github.com/davyxu/cellmesh_demo/proto" 6 | "github.com/davyxu/cellmesh_demo/svc/agent/model" 7 | "github.com/davyxu/cellnet" 8 | "github.com/davyxu/cellnet/codec" 9 | _ "github.com/davyxu/cellnet/peer/tcp" 10 | "github.com/davyxu/cellnet/proc" 11 | "github.com/davyxu/cellnet/proc/gorillaws" 12 | "github.com/davyxu/cellnet/proc/tcp" 13 | "time" 14 | ) 15 | 16 | var ( 17 | PingACKMsgID = cellnet.MessageMetaByFullName("proto.PingACK").ID 18 | VerifyREQMsgID = cellnet.MessageMetaByFullName("proto.VerifyREQ").ID 19 | ) 20 | 21 | func ProcFrontendPacket(msgID int, msgData []byte, ses cellnet.Session) (msg interface{}, err error) { 22 | // agent自己的内部消息以及预处理消息 23 | switch int(msgID) { 24 | case PingACKMsgID, VerifyREQMsgID: 25 | 26 | // 将字节数组和消息ID用户解出消息 27 | msg, _, err = codec.DecodeMessage(msgID, msgData) 28 | if err != nil { 29 | // TODO 接收错误时,返回消息 30 | return nil, err 31 | } 32 | 33 | switch userMsg := msg.(type) { 34 | case *proto.PingACK: 35 | u := model.SessionToUser(ses) 36 | if u != nil { 37 | u.LastPingTime = time.Now() 38 | 39 | // 回消息 40 | ses.Send(&proto.PingACK{}) 41 | } else { 42 | ses.Close() 43 | } 44 | 45 | // 第一个到网关的消息 46 | case *proto.VerifyREQ: 47 | u, err := bindClientToBackend(userMsg.GameSvcID, ses.ID()) 48 | if err == nil { 49 | u.TransmitToBackend(userMsg.GameSvcID, msgID, msgData) 50 | 51 | } else { 52 | ses.Close() 53 | log.Errorln("bindClientToBackend", err) 54 | } 55 | } 56 | 57 | default: 58 | // 在路由规则中查找消息ID是否是路由规则允许的消息 59 | rule := model.GetRuleByMsgID(msgID) 60 | if rule == nil { 61 | return nil, fmt.Errorf("Message not in route table, msgid: %d, execute MakeProto.sh and restart agent", msgID) 62 | } 63 | 64 | // 找到已经绑定的用户 65 | u := model.SessionToUser(ses) 66 | 67 | if u != nil { 68 | 69 | // 透传到后台 70 | if err = u.TransmitToBackend(u.GetBackend(rule.SvcName), msgID, msgData); err != nil { 71 | log.Warnf("TransmitToBackend %s, msg: '%s' svc: %s", err, rule.MsgName, rule.SvcName) 72 | } 73 | 74 | } else { 75 | // 这是一个未授权的用户发授权消息,可以踢掉 76 | } 77 | } 78 | 79 | return 80 | } 81 | 82 | type FrontendEventHooker struct { 83 | } 84 | 85 | // 网关内部抛出的事件 86 | func (FrontendEventHooker) OnInboundEvent(inputEvent cellnet.Event) (outputEvent cellnet.Event) { 87 | 88 | switch inputEvent.Message().(type) { 89 | case *cellnet.SessionAccepted: 90 | case *cellnet.SessionClosed: 91 | 92 | // 通知后台客户端关闭 93 | u := model.SessionToUser(inputEvent.Session()) 94 | if u != nil { 95 | u.BroadcastToBackends(&proto.ClientClosedACK{ 96 | ID: proto.ClientID{ 97 | ID: inputEvent.Session().ID(), 98 | SvcID: model.AgentSvcID, 99 | }, 100 | }) 101 | } 102 | } 103 | 104 | return inputEvent 105 | } 106 | 107 | // 发送到客户端的消息 108 | func (FrontendEventHooker) OnOutboundEvent(inputEvent cellnet.Event) (outputEvent cellnet.Event) { 109 | 110 | return inputEvent 111 | } 112 | 113 | func init() { 114 | 115 | // 前端的processor 116 | proc.RegisterProcessor("tcp.frontend", func(bundle proc.ProcessorBundle, userCallback cellnet.EventCallback, args ...interface{}) { 117 | 118 | bundle.SetTransmitter(new(directTCPTransmitter)) 119 | bundle.SetHooker(proc.NewMultiHooker( 120 | new(tcp.MsgHooker), // TCP基础消息及日志 121 | new(FrontendEventHooker), // 内部消息处理 122 | )) 123 | bundle.SetCallback(proc.NewQueuedEventCallback(userCallback)) 124 | }) 125 | 126 | // 前端的processor 127 | proc.RegisterProcessor("ws.frontend", func(bundle proc.ProcessorBundle, userCallback cellnet.EventCallback, args ...interface{}) { 128 | 129 | bundle.SetTransmitter(new(directWSMessageTransmitter)) 130 | bundle.SetHooker(proc.NewMultiHooker( 131 | new(gorillaws.MsgHooker), // TCP基础消息及日志 132 | new(FrontendEventHooker), // 内部消息处理 133 | )) 134 | bundle.SetCallback(proc.NewQueuedEventCallback(userCallback)) 135 | }) 136 | } 137 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![MIT licensed][11]][12] [![GoDoc][1]][2] 2 | 3 | [1]: https://godoc.org/github.com/davyxu/cellmesh_demo?status.svg 4 | [2]: https://godoc.org/github.com/davyxu/cellmesh_demo 5 | [11]: https://img.shields.io/badge/license-MIT-blue.svg 6 | [12]: LICENSE 7 | 8 | # cellmesh demo 9 | 基于cellmesh框架的游戏服务器demo 10 | 11 | # cellmesh服务器框架 12 | 13 | 本Demo使用的cellmesh框架请参考 14 | 15 | https://github.com/davyxu/cellmesh 16 | 17 | # 运行Demo 18 | 19 | 使用go module管理源码依赖, 所以确保go版本在1.12以上 20 | 21 | 请确认cellmesh_demo的工程结构为 22 | 23 | 任意文件夹\github.com\davyxu\cellmesh_demo 24 | 25 | ## 准备服务发现 26 | 服务发现系统用于记录已经运行的服务的基本信息,如: IP、内网端口、外网端口等。 27 | 28 | 服务器发现同时也是一个高性能的KV数据库,可以用于保存配置,实现配置的自动分发。 29 | ``` 30 | # 在cellmesh_demo根目录启动服务器发现 以下shell会自动编译和运行服务发现服务 31 | go run github.com/davyxu/cellmesh/discovery/memsd -datafile=persist.json 32 | ``` 33 | 34 | 35 | ## 更新协议及上传路由规则 36 | 37 | 执行下面指令更新路由规则到服务发现 38 | ``` 39 | cd proto 40 | sh ./MakeProto.sh 41 | ``` 42 | 43 | ## 启动demo服务 44 | 45 | 按照下面shell分别启动login, agent, game, hub 服务 46 | ``` 47 | # 在cellmesh_demo根目录启动以下服务 48 | 49 | go run github.com/davyxu/cellmesh_demo/svc/hub 50 | 51 | go run github.com/davyxu/cellmesh_demo/svc/login 52 | 53 | go run github.com/davyxu/cellmesh_demo/svc/agent 54 | 55 | go run github.com/davyxu/cellmesh_demo/svc/game 56 | ``` 57 | 58 | 确认服务器启动完成后,启动模拟客户端 59 | ``` 60 | go run github.com/davyxu/cellmesh_demo/svc/client 61 | ``` 62 | 63 | 启动client后,可在命令行中输入文字作为聊天内容发送 64 | 65 | # 概念 66 | 67 | ## Service(服务) 68 | 69 | 一个Service为一套连接器或侦听器,挂接消息处理的派发器Dispatcher 70 | 71 | - 侦听端口自动分配 72 | 73 | Service默认启动时以地址:0启动,网络底层自动分配端口,由cellmesh将服务信息报告到服务发现 74 | 75 | 其他Service发现新的服务进入网络时,根据需要自动连接服务 76 | 77 | 78 | ## Agent(网关) 79 | 80 | frontend(前端) 81 | 82 | 与客户端连接的前端通信的侦听器 83 | 84 | - 使用心跳+底层断开通知确认User断开 85 | 86 | - 客户端断开时通知后台服务器(ClientClosedACK消息) 87 | 88 | backend(后端) 89 | 90 | 与后台服务器通信的侦听器 91 | 92 | - 后台认证 93 | 94 | 后台服务通过BindBackendACK消息,将后台连接与客户端绑定,客户端固定将对应消息发送到绑定的后台服务器. 95 | 96 | - 后台断线重连 97 | 98 | 后台服务断开重连时,自动维护连接,保证客户端正常收发后台消息 99 | 100 | routerule(路由规则) 101 | 102 | 在proto文件中,消息的RouteRule属性描述如何路由消息到指定的后台服务器 103 | 104 | - 阻断(不填写RouteRule) 105 | 106 | 消息被路由阻断,无法发送到后台服务器 107 | 108 | - 通透(RouteRule=pass) 109 | 110 | 消息始终被路由到后台服务器 111 | 112 | - 后台认证(RouteRule=auth) 113 | 114 | 消息需要后台认证后才可被路由 115 | 116 | 117 | ## Connection Management(连接维护) 118 | 119 | 从服务发现的服务信息,创建到不同服务间的长连接。同时在这些连接断开时维护连接 120 | 121 | 逻辑中根据策略从已有连接及信息选择出连接与目标通信,例如:选择负载最低的一台游戏服务器 122 | 123 | # 目录结构 124 | ``` 125 | demo 126 | basefx 127 | 项目专有框架封装,不跨项目共享 128 | cfg 129 | 开发阶段的快速配置 130 | proto 131 | 协议文件,协议生成代码。 132 | svc 133 | login 134 | 登录,用户的固定接入入口,通过login拿到agent地址,让用户连接到agent(做了一个负载均衡的简易策略,获取人数最少的agent)。 135 | agent 136 | 代理,可以启动多个,agent后面有挂载的服务,如game。 137 | hub 138 | 中心服务,各服务的状态,通过发布和订阅的形式,由hub做中转共享,如在线人数等。 139 | game 140 | 业务逻辑服务,处理通过agent转发过来的协议。 141 | tool 142 | routegen 143 | 路由配置生成器。生成的配置可由agent动态读取并更新路由规则。 144 | util 145 | 所有框架通用的工具代码。 146 | ``` 147 | 148 | # demo工程架构 149 | ![arch](doc/architecture.png) 150 | 151 | - login 152 | 153 | 登录服, 短连接获取服务器列表及平台验证, 通过JWT生成token交由客户端 154 | 155 | - game 156 | 157 | 养成服, 网关后负责养成逻辑,使用客户端上传的JWT token验证客户端身份 158 | 159 | - agent 160 | 161 | 网关, 负责与客户端保持长连接,通过心跳处理客户端连接生命期, 客户端消息转发 162 | 163 | - hub 164 | 165 | 中转, 处理服务器人数负载, 使用模式为订阅分发模式,处理跨服通知 166 | 167 | - client 168 | 169 | 模拟客户端, 模拟客户端逻辑 170 | 171 | 172 | # 开发进度 173 | - [x] 基于Consul的服务发现及Watch机制 174 | - [x] 网关基本逻辑 175 | - [x] 带服务发现的连接器,侦听器 176 | - [x] 网关会话绑定 177 | - [x] 服务发现Consul的KV封装 178 | - [x] 网关路由规则生成,上传和下载 179 | - [x] 系统消息响应入口 180 | - [x] 网关广播 181 | - [x] 网关心跳处理 182 | - [x] 频道订阅发布hub 183 | - [x] 服务在线人数更新及连接选择 184 | - [x] 支持WebSocket网关及登录协议 185 | - [ ] 登录服务器,JWT验证 186 | - [ ] 玩家数据读取 187 | - [ ] 游戏服务器,成长逻辑,花钱升级等级 188 | - [ ] 社交服务器,聊天逻辑 189 | - [ ] 机器人 190 | 191 | # 参考及使用建议 192 | 由于本框架尚在开发中,demo在不断完善添加新功能. 因此响应的接口和设计会经常性发生变化. 193 | 194 | 195 | # Tips 196 | ## 为什么使用memsd的服务发现替换consul? 197 | 早期版本的cellmesh使用consul作为服务发现,cellmesh使用主动汇报服务信息的方式保证consul中能及时更新服务信息。 198 | 但实际使用中发现有如下问题: 199 | 1. 偶尔出现高CPU占用,Windows休眠恢复后也会造成严重的高CPU现象。 200 | 2. consul的API并没有本地cache,需要高速查询时,并没有很好的性能。 201 | 3. 多服更新时没有原子更新,容易形成严重的不同步现象。 202 | 4. 依赖重,代码量巨大,使用vendor而不是go module方式管理代码,编译慢。 203 | 基于以上考虑,决定兼容服务发现接口,同时编写对游戏服务友好的发现系统:memsd。 204 | 205 | 206 | 207 | 友情提示: 208 | demo工程仅是随框架附带的实例代码,建议将demo为蓝本建立自己的工程蓝本。 209 | 210 | 211 | # 备注 212 | 213 | 感觉不错请star, 谢谢! 214 | 215 | 知乎: http://www.zhihu.com/people/sunicdavy 216 | 217 | 提交bug及特性: https://github.com/davyxu/cellmesh/issues 218 | -------------------------------------------------------------------------------- /svc/agent/backend/hooker.go: -------------------------------------------------------------------------------- 1 | package backend 2 | 3 | import ( 4 | "github.com/davyxu/cellmesh/service" 5 | "github.com/davyxu/cellmesh_demo/proto" 6 | "github.com/davyxu/cellmesh_demo/svc/agent/model" 7 | "github.com/davyxu/cellnet" 8 | "github.com/davyxu/cellnet/codec" 9 | "github.com/davyxu/cellnet/msglog" 10 | "github.com/davyxu/cellnet/proc" 11 | "github.com/davyxu/cellnet/proc/tcp" 12 | ) 13 | 14 | type BackendMsgHooker struct { 15 | } 16 | 17 | // 后端服务器接收来自网关的消息 18 | func (BackendMsgHooker) OnInboundEvent(inputEvent cellnet.Event) (outputEvent cellnet.Event) { 19 | 20 | switch incomingMsg := inputEvent.Message().(type) { 21 | case *proto.TransmitACK: 22 | 23 | userMsg, _, err := codec.DecodeMessage(int(incomingMsg.MsgID), incomingMsg.MsgData) 24 | if err != nil { 25 | log.Warnf("Backend msg decode failed, %s, msgid: %d", err.Error(), incomingMsg.MsgID) 26 | return nil 27 | } 28 | 29 | ev := &RecvMsgEvent{ 30 | Ses: inputEvent.Session(), 31 | Msg: userMsg, 32 | ClientID: incomingMsg.ClientID, 33 | } 34 | 35 | outputEvent = ev 36 | 37 | default: 38 | outputEvent = inputEvent 39 | } 40 | 41 | return 42 | } 43 | 44 | // 后端服务器发送到网关的消息 45 | func (BackendMsgHooker) OnOutboundEvent(inputEvent cellnet.Event) (outputEvent cellnet.Event) { 46 | 47 | switch outgoingMsg := inputEvent.Message().(type) { 48 | case *proto.TransmitACK: 49 | 50 | if log.IsDebugEnabled() { 51 | 52 | writeAgentLog(inputEvent.Session(), "send", outgoingMsg) 53 | } 54 | } 55 | 56 | return inputEvent 57 | } 58 | 59 | type broadcasterHooker struct { 60 | } 61 | 62 | // 来自后台服务器的消息 63 | func (broadcasterHooker) OnInboundEvent(inputEvent cellnet.Event) (outputEvent cellnet.Event) { 64 | 65 | switch incomingMsg := inputEvent.Message().(type) { 66 | case *proto.TransmitACK: 67 | 68 | rawPkt := &cellnet.RawPacket{ 69 | MsgData: incomingMsg.MsgData, 70 | MsgID: int(incomingMsg.MsgID), 71 | } 72 | 73 | if log.IsDebugEnabled() { 74 | 75 | writeAgentLog(inputEvent.Session(), "recv", incomingMsg) 76 | } 77 | 78 | // 单发 79 | if incomingMsg.ClientID != 0 { 80 | clientSes := model.GetClientSession(incomingMsg.ClientID) 81 | 82 | if clientSes != nil { 83 | clientSes.Send(rawPkt) 84 | } 85 | // 广播 86 | } else if incomingMsg.ClientIDList != nil { 87 | 88 | for _, cid := range incomingMsg.ClientIDList { 89 | clientSes := model.GetClientSession(cid) 90 | 91 | if clientSes != nil { 92 | clientSes.Send(rawPkt) 93 | } 94 | } 95 | } else if incomingMsg.All { 96 | model.FrontendSessionManager.VisitSession(func(clientSes cellnet.Session) bool { 97 | 98 | clientSes.Send(rawPkt) 99 | return true 100 | }) 101 | } 102 | 103 | // 本事件已经处理, 不再后传 104 | return nil 105 | } 106 | 107 | return inputEvent 108 | } 109 | 110 | // 发送给后台服务器 111 | func (broadcasterHooker) OnOutboundEvent(inputEvent cellnet.Event) (outputEvent cellnet.Event) { 112 | 113 | switch outgoingMsg := inputEvent.Message().(type) { 114 | case *proto.TransmitACK: 115 | 116 | if log.IsDebugEnabled() { 117 | 118 | writeAgentLog(inputEvent.Session(), "send", outgoingMsg) 119 | } 120 | } 121 | 122 | return inputEvent 123 | } 124 | 125 | func writeAgentLog(ses cellnet.Session, dir string, ack *proto.TransmitACK) { 126 | 127 | if !msglog.IsMsgLogValid(int(ack.MsgID)) { 128 | return 129 | } 130 | 131 | peerInfo := ses.Peer().(cellnet.PeerProperty) 132 | 133 | userMsg, _, err := codec.DecodeMessage(int(ack.MsgID), ack.MsgData) 134 | if err == nil { 135 | log.Debugf("#agent.%s(%s)@%d len: %d %s <%d>| %s", 136 | dir, 137 | peerInfo.Name(), 138 | ses.ID(), 139 | cellnet.MessageSize(userMsg), 140 | cellnet.MessageToName(userMsg), 141 | ack.ClientID, 142 | cellnet.MessageToString(userMsg)) 143 | } else { 144 | 145 | // 网关没有相关的消息, 只能打出消息号 146 | log.Debugf("#agent.%s(%s)@%d len: %d msgid: %d <%d>", 147 | dir, 148 | peerInfo.Name(), 149 | ses.ID(), 150 | len(ack.MsgData), 151 | ack.MsgID, 152 | ack.ClientID, 153 | ) 154 | } 155 | } 156 | 157 | func init() { 158 | 159 | // 避免默认消息日志显示本条消息 160 | msglog.SetMsgLogRule("proto.TransmitACK", msglog.MsgLogRule_BlackList) 161 | 162 | // 适用于后端服务的处理器 163 | proc.RegisterProcessor("svc.backend", func(bundle proc.ProcessorBundle, userCallback cellnet.EventCallback, args ...interface{}) { 164 | 165 | bundle.SetTransmitter(new(tcp.TCPMessageTransmitter)) 166 | bundle.SetHooker(proc.NewMultiHooker( 167 | new(service.SvcEventHooker), // 服务互联处理 168 | new(BackendMsgHooker), // 网关消息处理 169 | new(tcp.MsgHooker))) // tcp基础消息处理 170 | bundle.SetCallback(proc.NewQueuedEventCallback(userCallback)) 171 | }) 172 | 173 | // 适用于 174 | proc.RegisterProcessor("agent.backend", func(bundle proc.ProcessorBundle, userCallback cellnet.EventCallback, args ...interface{}) { 175 | 176 | bundle.SetTransmitter(new(tcp.TCPMessageTransmitter)) 177 | bundle.SetHooker(proc.NewMultiHooker( 178 | new(service.SvcEventHooker), // 服务互联处理 179 | new(broadcasterHooker), // 网关消息处理 180 | new(tcp.MsgHooker))) // tcp基础消息处理 181 | bundle.SetCallback(proc.NewQueuedEventCallback(userCallback)) 182 | }) 183 | } 184 | -------------------------------------------------------------------------------- /svc/client/clientconn.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "github.com/davyxu/cellmesh/discovery" 6 | "github.com/davyxu/cellnet" 7 | "github.com/davyxu/cellnet/peer" 8 | _ "github.com/davyxu/cellnet/peer/tcp" 9 | "github.com/davyxu/cellnet/proc" 10 | "github.com/davyxu/cellnet/proc/gorillaws" 11 | "github.com/davyxu/cellnet/proc/tcp" 12 | "reflect" 13 | "sync" 14 | "time" 15 | ) 16 | 17 | func selectStrategy(descList []*discovery.ServiceDesc) *discovery.ServiceDesc { 18 | 19 | if len(descList) == 0 { 20 | return nil 21 | } 22 | 23 | return descList[0] 24 | } 25 | 26 | func queryServiceAddress(serviceName string) (*discovery.ServiceDesc, error) { 27 | descList := discovery.Default.Query(serviceName) 28 | 29 | desc := selectStrategy(descList) 30 | 31 | if desc == nil { 32 | return nil, errors.New("target not reachable:" + serviceName) 33 | } 34 | 35 | return desc, nil 36 | } 37 | 38 | // 建立短连接 39 | func CreateConnection(serviceName, netPeerType, netProcName string) (ret cellnet.Session) { 40 | 41 | notify := discovery.Default.RegisterNotify("add") 42 | 43 | done := make(chan struct{}) 44 | go func() { 45 | for { 46 | 47 | desc, err := queryServiceAddress(serviceName) 48 | 49 | if err == nil { 50 | 51 | p := peer.NewGenericPeer(netPeerType, serviceName, desc.Address(), nil) 52 | proc.BindProcessorHandler(p, netProcName, nil) 53 | 54 | p.Start() 55 | 56 | conn := p.(connector) 57 | 58 | if conn.IsReady() { 59 | ret = conn.Session() 60 | 61 | break 62 | } 63 | 64 | p.Stop() 65 | } 66 | 67 | <-notify 68 | } 69 | 70 | discovery.Default.DeregisterNotify("add", notify) 71 | done <- struct{}{} 72 | }() 73 | 74 | <-done 75 | 76 | return 77 | } 78 | 79 | type connector interface { 80 | cellnet.TCPConnector 81 | cellnet.PeerReadyChecker 82 | } 83 | 84 | // 保持长连接 85 | func KeepConnection(svcid, addr, netPeerType, netProc string, onReady func(cellnet.Session), onClose func()) { 86 | 87 | var stop sync.WaitGroup 88 | 89 | p := peer.NewGenericPeer(netPeerType, svcid, addr, nil) 90 | proc.BindProcessorHandler(p, netProc, func(ev cellnet.Event) { 91 | 92 | switch ev.Message().(type) { 93 | case *cellnet.SessionClosed: 94 | stop.Done() 95 | } 96 | }) 97 | 98 | stop.Add(1) 99 | 100 | p.Start() 101 | 102 | conn := p.(connector) 103 | 104 | if conn.IsReady() { 105 | 106 | onReady(conn.Session()) 107 | 108 | // 连接断开 109 | stop.Wait() 110 | } 111 | 112 | p.Stop() 113 | 114 | if onClose != nil { 115 | onClose() 116 | } 117 | 118 | } 119 | 120 | var ( 121 | callByType sync.Map // map[reflect.Type]func(interface{}) 122 | ) 123 | 124 | type TypeRPCHooker struct { 125 | } 126 | 127 | func (TypeRPCHooker) OnInboundEvent(inputEvent cellnet.Event) (outputEvent cellnet.Event) { 128 | 129 | outputEvent, _, err := ResolveInboundEvent(inputEvent) 130 | if err != nil { 131 | log.Errorln("rpc.ResolveInboundEvent", err) 132 | return 133 | } 134 | 135 | return outputEvent 136 | } 137 | 138 | func (TypeRPCHooker) OnOutboundEvent(inputEvent cellnet.Event) (outputEvent cellnet.Event) { 139 | 140 | return inputEvent 141 | } 142 | 143 | func ResolveInboundEvent(inputEvent cellnet.Event) (ouputEvent cellnet.Event, handled bool, err error) { 144 | incomingMsgType := reflect.TypeOf(inputEvent.Message()).Elem() 145 | 146 | if rawFeedback, ok := callByType.Load(incomingMsgType); ok { 147 | feedBack := rawFeedback.(chan interface{}) 148 | feedBack <- inputEvent.Message() 149 | return inputEvent, true, nil 150 | } 151 | 152 | return inputEvent, false, nil 153 | } 154 | 155 | // callback =func(ack *YouMsgACK) 156 | func RemoteCall(target, req interface{}, callback interface{}) error { 157 | 158 | funcType := reflect.TypeOf(callback) 159 | if funcType.Kind() != reflect.Func { 160 | panic("callback require 'func'") 161 | } 162 | 163 | var ses cellnet.Session 164 | switch tgt := target.(type) { 165 | case cellnet.Session: 166 | ses = tgt 167 | default: 168 | panic("rpc: Invalid peer type, require cellnet.Session") 169 | } 170 | 171 | if ses == nil { 172 | return errors.New("Empty session") 173 | } 174 | 175 | feedBack := make(chan interface{}) 176 | 177 | // 获取回调第一个参数 178 | 179 | if funcType.NumIn() != 1 { 180 | panic("callback func param format like 'func(ack *YouMsgACK)'") 181 | } 182 | 183 | ackType := funcType.In(0) 184 | if ackType.Kind() != reflect.Ptr { 185 | panic("callback func param format like 'func(ack *YouMsgACK)'") 186 | } 187 | 188 | ackType = ackType.Elem() 189 | 190 | callByType.Store(ackType, feedBack) 191 | 192 | defer callByType.Delete(ackType) 193 | 194 | ses.Send(req) 195 | 196 | select { 197 | case ack := <-feedBack: 198 | 199 | vCall := reflect.ValueOf(callback) 200 | 201 | vCall.Call([]reflect.Value{reflect.ValueOf(ack)}) 202 | return nil 203 | case <-time.After(time.Second): 204 | 205 | log.Errorln("RemoteCall: RPC time out") 206 | 207 | return errors.New("RPC Time out") 208 | } 209 | 210 | return nil 211 | } 212 | 213 | func init() { 214 | // 仅供demo使用的 215 | proc.RegisterProcessor("tcp.demo", func(bundle proc.ProcessorBundle, userCallback cellnet.EventCallback, args ...interface{}) { 216 | 217 | bundle.SetTransmitter(new(tcp.TCPMessageTransmitter)) 218 | bundle.SetHooker(proc.NewMultiHooker(new(tcp.MsgHooker), new(TypeRPCHooker))) 219 | bundle.SetCallback(proc.NewQueuedEventCallback(userCallback)) 220 | }) 221 | 222 | proc.RegisterProcessor("ws.demo", func(bundle proc.ProcessorBundle, userCallback cellnet.EventCallback, args ...interface{}) { 223 | 224 | bundle.SetTransmitter(new(gorillaws.WSMessageTransmitter)) 225 | bundle.SetHooker(proc.NewMultiHooker(new(gorillaws.MsgHooker), new(TypeRPCHooker))) 226 | bundle.SetCallback(proc.NewQueuedEventCallback(userCallback)) 227 | }) 228 | } 229 | -------------------------------------------------------------------------------- /proto/msgbind_gen.go: -------------------------------------------------------------------------------- 1 | // Auto generated by github.com/davyxu/cellmesh/protogen 2 | // DO NOT EDIT! 3 | 4 | package proto 5 | 6 | import ( 7 | "github.com/davyxu/cellnet" 8 | "github.com/davyxu/cellnet/codec" 9 | _ "github.com/davyxu/cellnet/codec/gogopb" 10 | _ "github.com/davyxu/cellnet/codec/protoplus" 11 | "reflect" 12 | ) 13 | 14 | // Make compiler import happy 15 | var ( 16 | _ cellnet.Event 17 | _ codec.CodecRecycler 18 | _ reflect.Type 19 | ) 20 | 21 | // agent 22 | var ( 23 | Handle_Agent_CloseClientACK = func(ev cellnet.Event) { panic("'CloseClientACK' not handled") } 24 | Handle_Agent_Default func(ev cellnet.Event) 25 | ) 26 | 27 | // game 28 | var ( 29 | Handle_Game_ChatREQ = func(ev cellnet.Event) { panic("'ChatREQ' not handled") } 30 | Handle_Game_VerifyREQ = func(ev cellnet.Event) { panic("'VerifyREQ' not handled") } 31 | Handle_Game_Default func(ev cellnet.Event) 32 | ) 33 | 34 | // hub 35 | var ( 36 | Handle_Hub_SubscribeChannelREQ = func(ev cellnet.Event) { panic("'SubscribeChannelREQ' not handled") } 37 | Handle_Hub_Default func(ev cellnet.Event) 38 | ) 39 | 40 | // login 41 | var ( 42 | Handle_Login_LoginREQ = func(ev cellnet.Event) { panic("'LoginREQ' not handled") } 43 | Handle_Login_SvcStatusACK = func(ev cellnet.Event) { panic("'SvcStatusACK' not handled") } 44 | Handle_Login_Default func(ev cellnet.Event) 45 | ) 46 | 47 | // match 48 | var ( 49 | Handle_Match_SvcStatusACK = func(ev cellnet.Event) { panic("'SvcStatusACK' not handled") } 50 | Handle_Match_Default func(ev cellnet.Event) 51 | ) 52 | 53 | func GetMessageHandler(svcName string) cellnet.EventCallback { 54 | 55 | switch svcName { 56 | case "agent": 57 | return func(ev cellnet.Event) { 58 | switch ev.Message().(type) { 59 | case *CloseClientACK: 60 | Handle_Agent_CloseClientACK(ev) 61 | default: 62 | if Handle_Agent_Default != nil { 63 | Handle_Agent_Default(ev) 64 | } 65 | } 66 | } 67 | case "game": 68 | return func(ev cellnet.Event) { 69 | switch ev.Message().(type) { 70 | case *ChatREQ: 71 | Handle_Game_ChatREQ(ev) 72 | case *VerifyREQ: 73 | Handle_Game_VerifyREQ(ev) 74 | default: 75 | if Handle_Game_Default != nil { 76 | Handle_Game_Default(ev) 77 | } 78 | } 79 | } 80 | case "hub": 81 | return func(ev cellnet.Event) { 82 | switch ev.Message().(type) { 83 | case *SubscribeChannelREQ: 84 | Handle_Hub_SubscribeChannelREQ(ev) 85 | default: 86 | if Handle_Hub_Default != nil { 87 | Handle_Hub_Default(ev) 88 | } 89 | } 90 | } 91 | case "login": 92 | return func(ev cellnet.Event) { 93 | switch ev.Message().(type) { 94 | case *LoginREQ: 95 | Handle_Login_LoginREQ(ev) 96 | case *SvcStatusACK: 97 | Handle_Login_SvcStatusACK(ev) 98 | default: 99 | if Handle_Login_Default != nil { 100 | Handle_Login_Default(ev) 101 | } 102 | } 103 | } 104 | case "match": 105 | return func(ev cellnet.Event) { 106 | switch ev.Message().(type) { 107 | case *SvcStatusACK: 108 | Handle_Match_SvcStatusACK(ev) 109 | default: 110 | if Handle_Match_Default != nil { 111 | Handle_Match_Default(ev) 112 | } 113 | } 114 | } 115 | } 116 | 117 | return nil 118 | } 119 | 120 | func init() { 121 | 122 | cellnet.RegisterMessageMeta(&cellnet.MessageMeta{ 123 | Codec: codec.MustGetCodec("gogopb"), 124 | Type: reflect.TypeOf((*PingACK)(nil)).Elem(), 125 | ID: 16241, 126 | }) 127 | cellnet.RegisterMessageMeta(&cellnet.MessageMeta{ 128 | Codec: codec.MustGetCodec("gogopb"), 129 | Type: reflect.TypeOf((*LoginREQ)(nil)).Elem(), 130 | ID: 18837, 131 | }) 132 | cellnet.RegisterMessageMeta(&cellnet.MessageMeta{ 133 | Codec: codec.MustGetCodec("gogopb"), 134 | Type: reflect.TypeOf((*LoginACK)(nil)).Elem(), 135 | ID: 46204, 136 | }) 137 | cellnet.RegisterMessageMeta(&cellnet.MessageMeta{ 138 | Codec: codec.MustGetCodec("gogopb"), 139 | Type: reflect.TypeOf((*VerifyREQ)(nil)).Elem(), 140 | ID: 13457, 141 | }) 142 | cellnet.RegisterMessageMeta(&cellnet.MessageMeta{ 143 | Codec: codec.MustGetCodec("gogopb"), 144 | Type: reflect.TypeOf((*VerifyACK)(nil)).Elem(), 145 | ID: 40824, 146 | }) 147 | cellnet.RegisterMessageMeta(&cellnet.MessageMeta{ 148 | Codec: codec.MustGetCodec("gogopb"), 149 | Type: reflect.TypeOf((*ChatREQ)(nil)).Elem(), 150 | ID: 29052, 151 | }) 152 | cellnet.RegisterMessageMeta(&cellnet.MessageMeta{ 153 | Codec: codec.MustGetCodec("gogopb"), 154 | Type: reflect.TypeOf((*ChatACK)(nil)).Elem(), 155 | ID: 56419, 156 | }) 157 | cellnet.RegisterMessageMeta(&cellnet.MessageMeta{ 158 | Codec: codec.MustGetCodec("gogopb"), 159 | Type: reflect.TypeOf((*TestACK)(nil)).Elem(), 160 | ID: 9315, 161 | }) 162 | cellnet.RegisterMessageMeta(&cellnet.MessageMeta{ 163 | Codec: codec.MustGetCodec("protoplus"), 164 | Type: reflect.TypeOf((*CloseClientACK)(nil)).Elem(), 165 | ID: 58040, 166 | }) 167 | cellnet.RegisterMessageMeta(&cellnet.MessageMeta{ 168 | Codec: codec.MustGetCodec("protoplus"), 169 | Type: reflect.TypeOf((*ClientClosedACK)(nil)).Elem(), 170 | ID: 50844, 171 | }) 172 | cellnet.RegisterMessageMeta(&cellnet.MessageMeta{ 173 | Codec: codec.MustGetCodec("protoplus"), 174 | Type: reflect.TypeOf((*TransmitACK)(nil)).Elem(), 175 | ID: 9941, 176 | }) 177 | cellnet.RegisterMessageMeta(&cellnet.MessageMeta{ 178 | Codec: codec.MustGetCodec("protoplus"), 179 | Type: reflect.TypeOf((*SubscribeChannelREQ)(nil)).Elem(), 180 | ID: 27927, 181 | }) 182 | cellnet.RegisterMessageMeta(&cellnet.MessageMeta{ 183 | Codec: codec.MustGetCodec("protoplus"), 184 | Type: reflect.TypeOf((*SubscribeChannelACK)(nil)).Elem(), 185 | ID: 55294, 186 | }) 187 | cellnet.RegisterMessageMeta(&cellnet.MessageMeta{ 188 | Codec: codec.MustGetCodec("protoplus"), 189 | Type: reflect.TypeOf((*SvcStatusACK)(nil)).Elem(), 190 | ID: 50227, 191 | }) 192 | } 193 | -------------------------------------------------------------------------------- /proto/msgsvc_gen.go: -------------------------------------------------------------------------------- 1 | // Generated by github.com/davyxu/protoplus 2 | // DO NOT EDIT! 3 | package proto 4 | 5 | import ( 6 | "github.com/davyxu/protoplus/proto" 7 | "unsafe" 8 | ) 9 | 10 | var ( 11 | _ *proto.Buffer 12 | _ unsafe.Pointer 13 | ) 14 | 15 | type ClientID struct { 16 | ID int64 // 客户端在网关上的SessionID 17 | SvcID string // 客户端在哪个网关 18 | } 19 | 20 | func (self *ClientID) String() string { return proto.CompactTextString(self) } 21 | 22 | func (self *ClientID) Size() (ret int) { 23 | 24 | ret += proto.SizeInt64(0, self.ID) 25 | 26 | ret += proto.SizeString(1, self.SvcID) 27 | 28 | return 29 | } 30 | 31 | func (self *ClientID) Marshal(buffer *proto.Buffer) error { 32 | 33 | proto.MarshalInt64(buffer, 0, self.ID) 34 | 35 | proto.MarshalString(buffer, 1, self.SvcID) 36 | 37 | return nil 38 | } 39 | 40 | func (self *ClientID) Unmarshal(buffer *proto.Buffer, fieldIndex uint64, wt proto.WireType) error { 41 | switch fieldIndex { 42 | case 0: 43 | return proto.UnmarshalInt64(buffer, wt, &self.ID) 44 | case 1: 45 | return proto.UnmarshalString(buffer, wt, &self.SvcID) 46 | 47 | } 48 | 49 | return proto.ErrUnknownField 50 | } 51 | 52 | type CloseClientACK struct { 53 | ID []int64 54 | All bool 55 | } 56 | 57 | func (self *CloseClientACK) String() string { return proto.CompactTextString(self) } 58 | 59 | func (self *CloseClientACK) Size() (ret int) { 60 | 61 | ret += proto.SizeInt64Slice(0, self.ID) 62 | 63 | ret += proto.SizeBool(1, self.All) 64 | 65 | return 66 | } 67 | 68 | func (self *CloseClientACK) Marshal(buffer *proto.Buffer) error { 69 | 70 | proto.MarshalInt64Slice(buffer, 0, self.ID) 71 | 72 | proto.MarshalBool(buffer, 1, self.All) 73 | 74 | return nil 75 | } 76 | 77 | func (self *CloseClientACK) Unmarshal(buffer *proto.Buffer, fieldIndex uint64, wt proto.WireType) error { 78 | switch fieldIndex { 79 | case 0: 80 | return proto.UnmarshalInt64Slice(buffer, wt, &self.ID) 81 | case 1: 82 | return proto.UnmarshalBool(buffer, wt, &self.All) 83 | 84 | } 85 | 86 | return proto.ErrUnknownField 87 | } 88 | 89 | type ClientClosedACK struct { 90 | ID ClientID 91 | } 92 | 93 | func (self *ClientClosedACK) String() string { return proto.CompactTextString(self) } 94 | 95 | func (self *ClientClosedACK) Size() (ret int) { 96 | 97 | ret += proto.SizeStruct(0, &self.ID) 98 | 99 | return 100 | } 101 | 102 | func (self *ClientClosedACK) Marshal(buffer *proto.Buffer) error { 103 | 104 | proto.MarshalStruct(buffer, 0, &self.ID) 105 | 106 | return nil 107 | } 108 | 109 | func (self *ClientClosedACK) Unmarshal(buffer *proto.Buffer, fieldIndex uint64, wt proto.WireType) error { 110 | switch fieldIndex { 111 | case 0: 112 | return proto.UnmarshalStruct(buffer, wt, &self.ID) 113 | 114 | } 115 | 116 | return proto.ErrUnknownField 117 | } 118 | 119 | type TransmitACK struct { 120 | MsgID uint32 // 用户消息ID 121 | MsgData []byte // 用户消息数据 122 | ClientID int64 // 单发 123 | ClientIDList []int64 // 列表发 124 | All bool // 全发 125 | } 126 | 127 | func (self *TransmitACK) String() string { return proto.CompactTextString(self) } 128 | 129 | func (self *TransmitACK) Size() (ret int) { 130 | 131 | ret += proto.SizeUInt32(0, self.MsgID) 132 | 133 | ret += proto.SizeBytes(1, self.MsgData) 134 | 135 | ret += proto.SizeInt64(2, self.ClientID) 136 | 137 | ret += proto.SizeInt64Slice(3, self.ClientIDList) 138 | 139 | ret += proto.SizeBool(4, self.All) 140 | 141 | return 142 | } 143 | 144 | func (self *TransmitACK) Marshal(buffer *proto.Buffer) error { 145 | 146 | proto.MarshalUInt32(buffer, 0, self.MsgID) 147 | 148 | proto.MarshalBytes(buffer, 1, self.MsgData) 149 | 150 | proto.MarshalInt64(buffer, 2, self.ClientID) 151 | 152 | proto.MarshalInt64Slice(buffer, 3, self.ClientIDList) 153 | 154 | proto.MarshalBool(buffer, 4, self.All) 155 | 156 | return nil 157 | } 158 | 159 | func (self *TransmitACK) Unmarshal(buffer *proto.Buffer, fieldIndex uint64, wt proto.WireType) error { 160 | switch fieldIndex { 161 | case 0: 162 | return proto.UnmarshalUInt32(buffer, wt, &self.MsgID) 163 | case 1: 164 | return proto.UnmarshalBytes(buffer, wt, &self.MsgData) 165 | case 2: 166 | return proto.UnmarshalInt64(buffer, wt, &self.ClientID) 167 | case 3: 168 | return proto.UnmarshalInt64Slice(buffer, wt, &self.ClientIDList) 169 | case 4: 170 | return proto.UnmarshalBool(buffer, wt, &self.All) 171 | 172 | } 173 | 174 | return proto.ErrUnknownField 175 | } 176 | 177 | type SubscribeChannelREQ struct { 178 | Channel string 179 | } 180 | 181 | func (self *SubscribeChannelREQ) String() string { return proto.CompactTextString(self) } 182 | 183 | func (self *SubscribeChannelREQ) Size() (ret int) { 184 | 185 | ret += proto.SizeString(0, self.Channel) 186 | 187 | return 188 | } 189 | 190 | func (self *SubscribeChannelREQ) Marshal(buffer *proto.Buffer) error { 191 | 192 | proto.MarshalString(buffer, 0, self.Channel) 193 | 194 | return nil 195 | } 196 | 197 | func (self *SubscribeChannelREQ) Unmarshal(buffer *proto.Buffer, fieldIndex uint64, wt proto.WireType) error { 198 | switch fieldIndex { 199 | case 0: 200 | return proto.UnmarshalString(buffer, wt, &self.Channel) 201 | 202 | } 203 | 204 | return proto.ErrUnknownField 205 | } 206 | 207 | type SubscribeChannelACK struct { 208 | Channel string 209 | } 210 | 211 | func (self *SubscribeChannelACK) String() string { return proto.CompactTextString(self) } 212 | 213 | func (self *SubscribeChannelACK) Size() (ret int) { 214 | 215 | ret += proto.SizeString(0, self.Channel) 216 | 217 | return 218 | } 219 | 220 | func (self *SubscribeChannelACK) Marshal(buffer *proto.Buffer) error { 221 | 222 | proto.MarshalString(buffer, 0, self.Channel) 223 | 224 | return nil 225 | } 226 | 227 | func (self *SubscribeChannelACK) Unmarshal(buffer *proto.Buffer, fieldIndex uint64, wt proto.WireType) error { 228 | switch fieldIndex { 229 | case 0: 230 | return proto.UnmarshalString(buffer, wt, &self.Channel) 231 | 232 | } 233 | 234 | return proto.ErrUnknownField 235 | } 236 | 237 | type SvcStatusACK struct { 238 | SvcID string 239 | UserCount int32 240 | } 241 | 242 | func (self *SvcStatusACK) String() string { return proto.CompactTextString(self) } 243 | 244 | func (self *SvcStatusACK) Size() (ret int) { 245 | 246 | ret += proto.SizeString(0, self.SvcID) 247 | 248 | ret += proto.SizeInt32(1, self.UserCount) 249 | 250 | return 251 | } 252 | 253 | func (self *SvcStatusACK) Marshal(buffer *proto.Buffer) error { 254 | 255 | proto.MarshalString(buffer, 0, self.SvcID) 256 | 257 | proto.MarshalInt32(buffer, 1, self.UserCount) 258 | 259 | return nil 260 | } 261 | 262 | func (self *SvcStatusACK) Unmarshal(buffer *proto.Buffer, fieldIndex uint64, wt proto.WireType) error { 263 | switch fieldIndex { 264 | case 0: 265 | return proto.UnmarshalString(buffer, wt, &self.SvcID) 266 | case 1: 267 | return proto.UnmarshalInt32(buffer, wt, &self.UserCount) 268 | 269 | } 270 | 271 | return proto.ErrUnknownField 272 | } 273 | -------------------------------------------------------------------------------- /proto/clientmsg_gen.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-gogo. DO NOT EDIT. 2 | // source: clientmsg_gen.proto 3 | 4 | package proto 5 | 6 | import ( 7 | fmt "fmt" 8 | proto "github.com/gogo/protobuf/proto" 9 | io "io" 10 | math "math" 11 | ) 12 | 13 | // Reference imports to suppress errors if they are not otherwise used. 14 | var _ = proto.Marshal 15 | var _ = fmt.Errorf 16 | var _ = math.Inf 17 | 18 | // This is a compile-time assertion to ensure that this generated file 19 | // is compatible with the proto package it is being compiled against. 20 | // A compilation error at this line likely means your copy of the 21 | // proto package needs to be updated. 22 | const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package 23 | 24 | type ResultCode int32 25 | 26 | const ( 27 | ResultCode_NoError ResultCode = 0 28 | ResultCode_AgentNotFound ResultCode = 101 29 | ResultCode_AgentAddressError ResultCode = 102 30 | ResultCode_GameNotFound ResultCode = 103 31 | ) 32 | 33 | var ResultCode_name = map[int32]string{ 34 | 0: "NoError", 35 | 101: "AgentNotFound", 36 | 102: "AgentAddressError", 37 | 103: "GameNotFound", 38 | } 39 | 40 | var ResultCode_value = map[string]int32{ 41 | "NoError": 0, 42 | "AgentNotFound": 101, 43 | "AgentAddressError": 102, 44 | "GameNotFound": 103, 45 | } 46 | 47 | func (x ResultCode) String() string { 48 | return proto.EnumName(ResultCode_name, int32(x)) 49 | } 50 | 51 | func (ResultCode) EnumDescriptor() ([]byte, []int) { 52 | return fileDescriptor_54458e0ca6367313, []int{0} 53 | } 54 | 55 | type ServerInfo struct { 56 | IP string `protobuf:"bytes,1,opt,name=IP,proto3" json:"IP,omitempty"` 57 | Port int32 `protobuf:"varint,2,opt,name=Port,proto3" json:"Port,omitempty"` 58 | } 59 | 60 | func (m *ServerInfo) Reset() { *m = ServerInfo{} } 61 | func (m *ServerInfo) String() string { return proto.CompactTextString(m) } 62 | func (*ServerInfo) ProtoMessage() {} 63 | func (*ServerInfo) Descriptor() ([]byte, []int) { 64 | return fileDescriptor_54458e0ca6367313, []int{0} 65 | } 66 | func (m *ServerInfo) XXX_Unmarshal(b []byte) error { 67 | return m.Unmarshal(b) 68 | } 69 | func (m *ServerInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 70 | if deterministic { 71 | return xxx_messageInfo_ServerInfo.Marshal(b, m, deterministic) 72 | } else { 73 | b = b[:cap(b)] 74 | n, err := m.MarshalTo(b) 75 | if err != nil { 76 | return nil, err 77 | } 78 | return b[:n], nil 79 | } 80 | } 81 | func (m *ServerInfo) XXX_Merge(src proto.Message) { 82 | xxx_messageInfo_ServerInfo.Merge(m, src) 83 | } 84 | func (m *ServerInfo) XXX_Size() int { 85 | return m.Size() 86 | } 87 | func (m *ServerInfo) XXX_DiscardUnknown() { 88 | xxx_messageInfo_ServerInfo.DiscardUnknown(m) 89 | } 90 | 91 | var xxx_messageInfo_ServerInfo proto.InternalMessageInfo 92 | 93 | func (m *ServerInfo) GetIP() string { 94 | if m != nil { 95 | return m.IP 96 | } 97 | return "" 98 | } 99 | 100 | func (m *ServerInfo) GetPort() int32 { 101 | if m != nil { 102 | return m.Port 103 | } 104 | return 0 105 | } 106 | 107 | type PingACK struct { 108 | } 109 | 110 | func (m *PingACK) Reset() { *m = PingACK{} } 111 | func (m *PingACK) String() string { return proto.CompactTextString(m) } 112 | func (*PingACK) ProtoMessage() {} 113 | func (*PingACK) Descriptor() ([]byte, []int) { 114 | return fileDescriptor_54458e0ca6367313, []int{1} 115 | } 116 | func (m *PingACK) XXX_Unmarshal(b []byte) error { 117 | return m.Unmarshal(b) 118 | } 119 | func (m *PingACK) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 120 | if deterministic { 121 | return xxx_messageInfo_PingACK.Marshal(b, m, deterministic) 122 | } else { 123 | b = b[:cap(b)] 124 | n, err := m.MarshalTo(b) 125 | if err != nil { 126 | return nil, err 127 | } 128 | return b[:n], nil 129 | } 130 | } 131 | func (m *PingACK) XXX_Merge(src proto.Message) { 132 | xxx_messageInfo_PingACK.Merge(m, src) 133 | } 134 | func (m *PingACK) XXX_Size() int { 135 | return m.Size() 136 | } 137 | func (m *PingACK) XXX_DiscardUnknown() { 138 | xxx_messageInfo_PingACK.DiscardUnknown(m) 139 | } 140 | 141 | var xxx_messageInfo_PingACK proto.InternalMessageInfo 142 | 143 | type LoginREQ struct { 144 | Version string `protobuf:"bytes,1,opt,name=Version,proto3" json:"Version,omitempty"` 145 | Platform string `protobuf:"bytes,2,opt,name=Platform,proto3" json:"Platform,omitempty"` 146 | UID string `protobuf:"bytes,3,opt,name=UID,proto3" json:"UID,omitempty"` 147 | } 148 | 149 | func (m *LoginREQ) Reset() { *m = LoginREQ{} } 150 | func (m *LoginREQ) String() string { return proto.CompactTextString(m) } 151 | func (*LoginREQ) ProtoMessage() {} 152 | func (*LoginREQ) Descriptor() ([]byte, []int) { 153 | return fileDescriptor_54458e0ca6367313, []int{2} 154 | } 155 | func (m *LoginREQ) XXX_Unmarshal(b []byte) error { 156 | return m.Unmarshal(b) 157 | } 158 | func (m *LoginREQ) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 159 | if deterministic { 160 | return xxx_messageInfo_LoginREQ.Marshal(b, m, deterministic) 161 | } else { 162 | b = b[:cap(b)] 163 | n, err := m.MarshalTo(b) 164 | if err != nil { 165 | return nil, err 166 | } 167 | return b[:n], nil 168 | } 169 | } 170 | func (m *LoginREQ) XXX_Merge(src proto.Message) { 171 | xxx_messageInfo_LoginREQ.Merge(m, src) 172 | } 173 | func (m *LoginREQ) XXX_Size() int { 174 | return m.Size() 175 | } 176 | func (m *LoginREQ) XXX_DiscardUnknown() { 177 | xxx_messageInfo_LoginREQ.DiscardUnknown(m) 178 | } 179 | 180 | var xxx_messageInfo_LoginREQ proto.InternalMessageInfo 181 | 182 | func (m *LoginREQ) GetVersion() string { 183 | if m != nil { 184 | return m.Version 185 | } 186 | return "" 187 | } 188 | 189 | func (m *LoginREQ) GetPlatform() string { 190 | if m != nil { 191 | return m.Platform 192 | } 193 | return "" 194 | } 195 | 196 | func (m *LoginREQ) GetUID() string { 197 | if m != nil { 198 | return m.UID 199 | } 200 | return "" 201 | } 202 | 203 | type LoginACK struct { 204 | Result ResultCode `protobuf:"varint,1,opt,name=Result,proto3,enum=proto.ResultCode" json:"Result,omitempty"` 205 | Server *ServerInfo `protobuf:"bytes,2,opt,name=Server,proto3" json:"Server,omitempty"` 206 | GameToken string `protobuf:"bytes,3,opt,name=GameToken,proto3" json:"GameToken,omitempty"` 207 | GameSvcID string `protobuf:"bytes,4,opt,name=GameSvcID,proto3" json:"GameSvcID,omitempty"` 208 | } 209 | 210 | func (m *LoginACK) Reset() { *m = LoginACK{} } 211 | func (m *LoginACK) String() string { return proto.CompactTextString(m) } 212 | func (*LoginACK) ProtoMessage() {} 213 | func (*LoginACK) Descriptor() ([]byte, []int) { 214 | return fileDescriptor_54458e0ca6367313, []int{3} 215 | } 216 | func (m *LoginACK) XXX_Unmarshal(b []byte) error { 217 | return m.Unmarshal(b) 218 | } 219 | func (m *LoginACK) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 220 | if deterministic { 221 | return xxx_messageInfo_LoginACK.Marshal(b, m, deterministic) 222 | } else { 223 | b = b[:cap(b)] 224 | n, err := m.MarshalTo(b) 225 | if err != nil { 226 | return nil, err 227 | } 228 | return b[:n], nil 229 | } 230 | } 231 | func (m *LoginACK) XXX_Merge(src proto.Message) { 232 | xxx_messageInfo_LoginACK.Merge(m, src) 233 | } 234 | func (m *LoginACK) XXX_Size() int { 235 | return m.Size() 236 | } 237 | func (m *LoginACK) XXX_DiscardUnknown() { 238 | xxx_messageInfo_LoginACK.DiscardUnknown(m) 239 | } 240 | 241 | var xxx_messageInfo_LoginACK proto.InternalMessageInfo 242 | 243 | func (m *LoginACK) GetResult() ResultCode { 244 | if m != nil { 245 | return m.Result 246 | } 247 | return ResultCode_NoError 248 | } 249 | 250 | func (m *LoginACK) GetServer() *ServerInfo { 251 | if m != nil { 252 | return m.Server 253 | } 254 | return nil 255 | } 256 | 257 | func (m *LoginACK) GetGameToken() string { 258 | if m != nil { 259 | return m.GameToken 260 | } 261 | return "" 262 | } 263 | 264 | func (m *LoginACK) GetGameSvcID() string { 265 | if m != nil { 266 | return m.GameSvcID 267 | } 268 | return "" 269 | } 270 | 271 | type VerifyREQ struct { 272 | GameToken string `protobuf:"bytes,1,opt,name=GameToken,proto3" json:"GameToken,omitempty"` 273 | GameSvcID string `protobuf:"bytes,2,opt,name=GameSvcID,proto3" json:"GameSvcID,omitempty"` 274 | } 275 | 276 | func (m *VerifyREQ) Reset() { *m = VerifyREQ{} } 277 | func (m *VerifyREQ) String() string { return proto.CompactTextString(m) } 278 | func (*VerifyREQ) ProtoMessage() {} 279 | func (*VerifyREQ) Descriptor() ([]byte, []int) { 280 | return fileDescriptor_54458e0ca6367313, []int{4} 281 | } 282 | func (m *VerifyREQ) XXX_Unmarshal(b []byte) error { 283 | return m.Unmarshal(b) 284 | } 285 | func (m *VerifyREQ) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 286 | if deterministic { 287 | return xxx_messageInfo_VerifyREQ.Marshal(b, m, deterministic) 288 | } else { 289 | b = b[:cap(b)] 290 | n, err := m.MarshalTo(b) 291 | if err != nil { 292 | return nil, err 293 | } 294 | return b[:n], nil 295 | } 296 | } 297 | func (m *VerifyREQ) XXX_Merge(src proto.Message) { 298 | xxx_messageInfo_VerifyREQ.Merge(m, src) 299 | } 300 | func (m *VerifyREQ) XXX_Size() int { 301 | return m.Size() 302 | } 303 | func (m *VerifyREQ) XXX_DiscardUnknown() { 304 | xxx_messageInfo_VerifyREQ.DiscardUnknown(m) 305 | } 306 | 307 | var xxx_messageInfo_VerifyREQ proto.InternalMessageInfo 308 | 309 | func (m *VerifyREQ) GetGameToken() string { 310 | if m != nil { 311 | return m.GameToken 312 | } 313 | return "" 314 | } 315 | 316 | func (m *VerifyREQ) GetGameSvcID() string { 317 | if m != nil { 318 | return m.GameSvcID 319 | } 320 | return "" 321 | } 322 | 323 | type VerifyACK struct { 324 | Result ResultCode `protobuf:"varint,1,opt,name=Result,proto3,enum=proto.ResultCode" json:"Result,omitempty"` 325 | } 326 | 327 | func (m *VerifyACK) Reset() { *m = VerifyACK{} } 328 | func (m *VerifyACK) String() string { return proto.CompactTextString(m) } 329 | func (*VerifyACK) ProtoMessage() {} 330 | func (*VerifyACK) Descriptor() ([]byte, []int) { 331 | return fileDescriptor_54458e0ca6367313, []int{5} 332 | } 333 | func (m *VerifyACK) XXX_Unmarshal(b []byte) error { 334 | return m.Unmarshal(b) 335 | } 336 | func (m *VerifyACK) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 337 | if deterministic { 338 | return xxx_messageInfo_VerifyACK.Marshal(b, m, deterministic) 339 | } else { 340 | b = b[:cap(b)] 341 | n, err := m.MarshalTo(b) 342 | if err != nil { 343 | return nil, err 344 | } 345 | return b[:n], nil 346 | } 347 | } 348 | func (m *VerifyACK) XXX_Merge(src proto.Message) { 349 | xxx_messageInfo_VerifyACK.Merge(m, src) 350 | } 351 | func (m *VerifyACK) XXX_Size() int { 352 | return m.Size() 353 | } 354 | func (m *VerifyACK) XXX_DiscardUnknown() { 355 | xxx_messageInfo_VerifyACK.DiscardUnknown(m) 356 | } 357 | 358 | var xxx_messageInfo_VerifyACK proto.InternalMessageInfo 359 | 360 | func (m *VerifyACK) GetResult() ResultCode { 361 | if m != nil { 362 | return m.Result 363 | } 364 | return ResultCode_NoError 365 | } 366 | 367 | type ChatREQ struct { 368 | Content string `protobuf:"bytes,1,opt,name=Content,proto3" json:"Content,omitempty"` 369 | } 370 | 371 | func (m *ChatREQ) Reset() { *m = ChatREQ{} } 372 | func (m *ChatREQ) String() string { return proto.CompactTextString(m) } 373 | func (*ChatREQ) ProtoMessage() {} 374 | func (*ChatREQ) Descriptor() ([]byte, []int) { 375 | return fileDescriptor_54458e0ca6367313, []int{6} 376 | } 377 | func (m *ChatREQ) XXX_Unmarshal(b []byte) error { 378 | return m.Unmarshal(b) 379 | } 380 | func (m *ChatREQ) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 381 | if deterministic { 382 | return xxx_messageInfo_ChatREQ.Marshal(b, m, deterministic) 383 | } else { 384 | b = b[:cap(b)] 385 | n, err := m.MarshalTo(b) 386 | if err != nil { 387 | return nil, err 388 | } 389 | return b[:n], nil 390 | } 391 | } 392 | func (m *ChatREQ) XXX_Merge(src proto.Message) { 393 | xxx_messageInfo_ChatREQ.Merge(m, src) 394 | } 395 | func (m *ChatREQ) XXX_Size() int { 396 | return m.Size() 397 | } 398 | func (m *ChatREQ) XXX_DiscardUnknown() { 399 | xxx_messageInfo_ChatREQ.DiscardUnknown(m) 400 | } 401 | 402 | var xxx_messageInfo_ChatREQ proto.InternalMessageInfo 403 | 404 | func (m *ChatREQ) GetContent() string { 405 | if m != nil { 406 | return m.Content 407 | } 408 | return "" 409 | } 410 | 411 | type ChatACK struct { 412 | Content string `protobuf:"bytes,1,opt,name=Content,proto3" json:"Content,omitempty"` 413 | } 414 | 415 | func (m *ChatACK) Reset() { *m = ChatACK{} } 416 | func (m *ChatACK) String() string { return proto.CompactTextString(m) } 417 | func (*ChatACK) ProtoMessage() {} 418 | func (*ChatACK) Descriptor() ([]byte, []int) { 419 | return fileDescriptor_54458e0ca6367313, []int{7} 420 | } 421 | func (m *ChatACK) XXX_Unmarshal(b []byte) error { 422 | return m.Unmarshal(b) 423 | } 424 | func (m *ChatACK) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 425 | if deterministic { 426 | return xxx_messageInfo_ChatACK.Marshal(b, m, deterministic) 427 | } else { 428 | b = b[:cap(b)] 429 | n, err := m.MarshalTo(b) 430 | if err != nil { 431 | return nil, err 432 | } 433 | return b[:n], nil 434 | } 435 | } 436 | func (m *ChatACK) XXX_Merge(src proto.Message) { 437 | xxx_messageInfo_ChatACK.Merge(m, src) 438 | } 439 | func (m *ChatACK) XXX_Size() int { 440 | return m.Size() 441 | } 442 | func (m *ChatACK) XXX_DiscardUnknown() { 443 | xxx_messageInfo_ChatACK.DiscardUnknown(m) 444 | } 445 | 446 | var xxx_messageInfo_ChatACK proto.InternalMessageInfo 447 | 448 | func (m *ChatACK) GetContent() string { 449 | if m != nil { 450 | return m.Content 451 | } 452 | return "" 453 | } 454 | 455 | type TestACK struct { 456 | Dummy string `protobuf:"bytes,1,opt,name=Dummy,proto3" json:"Dummy,omitempty"` 457 | } 458 | 459 | func (m *TestACK) Reset() { *m = TestACK{} } 460 | func (m *TestACK) String() string { return proto.CompactTextString(m) } 461 | func (*TestACK) ProtoMessage() {} 462 | func (*TestACK) Descriptor() ([]byte, []int) { 463 | return fileDescriptor_54458e0ca6367313, []int{8} 464 | } 465 | func (m *TestACK) XXX_Unmarshal(b []byte) error { 466 | return m.Unmarshal(b) 467 | } 468 | func (m *TestACK) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 469 | if deterministic { 470 | return xxx_messageInfo_TestACK.Marshal(b, m, deterministic) 471 | } else { 472 | b = b[:cap(b)] 473 | n, err := m.MarshalTo(b) 474 | if err != nil { 475 | return nil, err 476 | } 477 | return b[:n], nil 478 | } 479 | } 480 | func (m *TestACK) XXX_Merge(src proto.Message) { 481 | xxx_messageInfo_TestACK.Merge(m, src) 482 | } 483 | func (m *TestACK) XXX_Size() int { 484 | return m.Size() 485 | } 486 | func (m *TestACK) XXX_DiscardUnknown() { 487 | xxx_messageInfo_TestACK.DiscardUnknown(m) 488 | } 489 | 490 | var xxx_messageInfo_TestACK proto.InternalMessageInfo 491 | 492 | func (m *TestACK) GetDummy() string { 493 | if m != nil { 494 | return m.Dummy 495 | } 496 | return "" 497 | } 498 | 499 | func init() { 500 | proto.RegisterEnum("proto.ResultCode", ResultCode_name, ResultCode_value) 501 | proto.RegisterType((*ServerInfo)(nil), "proto.ServerInfo") 502 | proto.RegisterType((*PingACK)(nil), "proto.PingACK") 503 | proto.RegisterType((*LoginREQ)(nil), "proto.LoginREQ") 504 | proto.RegisterType((*LoginACK)(nil), "proto.LoginACK") 505 | proto.RegisterType((*VerifyREQ)(nil), "proto.VerifyREQ") 506 | proto.RegisterType((*VerifyACK)(nil), "proto.VerifyACK") 507 | proto.RegisterType((*ChatREQ)(nil), "proto.ChatREQ") 508 | proto.RegisterType((*ChatACK)(nil), "proto.ChatACK") 509 | proto.RegisterType((*TestACK)(nil), "proto.TestACK") 510 | } 511 | 512 | func init() { proto.RegisterFile("clientmsg_gen.proto", fileDescriptor_54458e0ca6367313) } 513 | 514 | var fileDescriptor_54458e0ca6367313 = []byte{ 515 | // 397 bytes of a gzipped FileDescriptorProto 516 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x90, 0xdf, 0xaa, 0xd3, 0x30, 517 | 0x1c, 0xc7, 0x9b, 0x9e, 0xb3, 0xd3, 0xd3, 0xdf, 0xd1, 0x43, 0x17, 0x15, 0x8a, 0x48, 0x1d, 0xf5, 518 | 0x66, 0x7a, 0x31, 0x44, 0xc1, 0xfb, 0xda, 0xcd, 0x51, 0x26, 0xa3, 0x66, 0x7f, 0x6e, 0x65, 0xae, 519 | 0x69, 0x2d, 0xae, 0x89, 0xa4, 0xd9, 0x60, 0x6f, 0xe1, 0x03, 0xf8, 0x40, 0x5e, 0xee, 0xd2, 0x4b, 520 | 0xd9, 0x5e, 0x44, 0x9a, 0xa6, 0x2b, 0x0a, 0x0a, 0xe7, 0xaa, 0xf9, 0x7d, 0xf3, 0xe9, 0x27, 0xf9, 521 | 0x06, 0x1e, 0xac, 0x37, 0x39, 0x65, 0xb2, 0x28, 0xb3, 0x8f, 0x19, 0x65, 0x83, 0xaf, 0x82, 0x4b, 522 | 0x8e, 0x3b, 0xea, 0xe3, 0xbf, 0x04, 0x98, 0x51, 0xb1, 0xa3, 0x22, 0x62, 0x29, 0xc7, 0xb7, 0x60, 523 | 0x46, 0xb1, 0x8b, 0x7a, 0xa8, 0x6f, 0x13, 0x33, 0x8a, 0x31, 0x86, 0xcb, 0x98, 0x0b, 0xe9, 0x9a, 524 | 0x3d, 0xd4, 0xef, 0x10, 0xb5, 0xf6, 0x6d, 0xb0, 0xe2, 0x9c, 0x65, 0x41, 0x38, 0xf1, 0x09, 0x5c, 525 | 0xbf, 0xe7, 0x59, 0xce, 0xc8, 0xe8, 0x03, 0x76, 0xc1, 0x5a, 0x52, 0x51, 0xe6, 0x9c, 0xe9, 0xff, 526 | 0x9b, 0x11, 0x3f, 0x86, 0xeb, 0x78, 0xb3, 0x92, 0x29, 0x17, 0x85, 0x12, 0xd9, 0xe4, 0x3c, 0x63, 527 | 0x07, 0x2e, 0x16, 0xd1, 0xd0, 0xbd, 0x50, 0x71, 0xb5, 0xf4, 0xbf, 0x23, 0x2d, 0x0d, 0xc2, 0x09, 528 | 0x7e, 0x0e, 0x57, 0x84, 0x96, 0xdb, 0x8d, 0x54, 0xce, 0xdb, 0x57, 0xdd, 0xfa, 0xf2, 0x83, 0x3a, 529 | 0x0c, 0x79, 0x42, 0x89, 0x06, 0x2a, 0xb4, 0x2e, 0xa2, 0xce, 0xb8, 0x39, 0xa3, 0x6d, 0x3b, 0xa2, 530 | 0x01, 0xfc, 0x04, 0xec, 0xf1, 0xaa, 0xa0, 0x73, 0xfe, 0x85, 0x32, 0x7d, 0x74, 0x1b, 0x34, 0xbb, 531 | 0xb3, 0xdd, 0x3a, 0x1a, 0xba, 0x97, 0xed, 0xae, 0x0a, 0xfc, 0x31, 0xd8, 0x4b, 0x2a, 0xf2, 0x74, 532 | 0x5f, 0x75, 0xfe, 0x43, 0x84, 0xfe, 0x2b, 0x32, 0xff, 0x16, 0xbd, 0x69, 0x44, 0x77, 0xeb, 0xe9, 533 | 0x3f, 0x03, 0x2b, 0xfc, 0xbc, 0x92, 0xfa, 0xc9, 0x43, 0xce, 0x24, 0x65, 0xb2, 0x79, 0x72, 0x3d, 534 | 0x36, 0x50, 0xa5, 0xfe, 0x37, 0xf4, 0x14, 0xac, 0x39, 0x2d, 0x15, 0xf4, 0x10, 0x3a, 0xc3, 0x6d, 535 | 0x51, 0xec, 0x35, 0x52, 0x0f, 0x2f, 0x16, 0x00, 0xed, 0x05, 0xf0, 0x0d, 0x58, 0x53, 0x3e, 0x12, 536 | 0x82, 0x0b, 0xc7, 0xc0, 0x5d, 0xb8, 0x1f, 0x64, 0x94, 0xc9, 0x29, 0x97, 0xef, 0xf8, 0x96, 0x25, 537 | 0x0e, 0xc5, 0x8f, 0xa0, 0xab, 0xa2, 0x20, 0x49, 0x04, 0x2d, 0xcb, 0x9a, 0x4c, 0xb1, 0x03, 0xf7, 538 | 0xaa, 0xd2, 0x67, 0x30, 0x7b, 0xeb, 0xfe, 0x38, 0x7a, 0xe8, 0x70, 0xf4, 0xd0, 0xaf, 0xa3, 0x87, 539 | 0xbe, 0x9d, 0x3c, 0xe3, 0x70, 0xf2, 0x8c, 0x9f, 0x27, 0xcf, 0xf8, 0x74, 0xa5, 0x5a, 0xbf, 0xfe, 540 | 0x1d, 0x00, 0x00, 0xff, 0xff, 0xa1, 0x5b, 0x8b, 0xe5, 0xb1, 0x02, 0x00, 0x00, 541 | } 542 | 543 | func (m *ServerInfo) Marshal() (dAtA []byte, err error) { 544 | size := m.Size() 545 | dAtA = make([]byte, size) 546 | n, err := m.MarshalTo(dAtA) 547 | if err != nil { 548 | return nil, err 549 | } 550 | return dAtA[:n], nil 551 | } 552 | 553 | func (m *ServerInfo) MarshalTo(dAtA []byte) (int, error) { 554 | var i int 555 | _ = i 556 | var l int 557 | _ = l 558 | if len(m.IP) > 0 { 559 | dAtA[i] = 0xa 560 | i++ 561 | i = encodeVarintClientmsgGen(dAtA, i, uint64(len(m.IP))) 562 | i += copy(dAtA[i:], m.IP) 563 | } 564 | if m.Port != 0 { 565 | dAtA[i] = 0x10 566 | i++ 567 | i = encodeVarintClientmsgGen(dAtA, i, uint64(m.Port)) 568 | } 569 | return i, nil 570 | } 571 | 572 | func (m *PingACK) Marshal() (dAtA []byte, err error) { 573 | size := m.Size() 574 | dAtA = make([]byte, size) 575 | n, err := m.MarshalTo(dAtA) 576 | if err != nil { 577 | return nil, err 578 | } 579 | return dAtA[:n], nil 580 | } 581 | 582 | func (m *PingACK) MarshalTo(dAtA []byte) (int, error) { 583 | var i int 584 | _ = i 585 | var l int 586 | _ = l 587 | return i, nil 588 | } 589 | 590 | func (m *LoginREQ) Marshal() (dAtA []byte, err error) { 591 | size := m.Size() 592 | dAtA = make([]byte, size) 593 | n, err := m.MarshalTo(dAtA) 594 | if err != nil { 595 | return nil, err 596 | } 597 | return dAtA[:n], nil 598 | } 599 | 600 | func (m *LoginREQ) MarshalTo(dAtA []byte) (int, error) { 601 | var i int 602 | _ = i 603 | var l int 604 | _ = l 605 | if len(m.Version) > 0 { 606 | dAtA[i] = 0xa 607 | i++ 608 | i = encodeVarintClientmsgGen(dAtA, i, uint64(len(m.Version))) 609 | i += copy(dAtA[i:], m.Version) 610 | } 611 | if len(m.Platform) > 0 { 612 | dAtA[i] = 0x12 613 | i++ 614 | i = encodeVarintClientmsgGen(dAtA, i, uint64(len(m.Platform))) 615 | i += copy(dAtA[i:], m.Platform) 616 | } 617 | if len(m.UID) > 0 { 618 | dAtA[i] = 0x1a 619 | i++ 620 | i = encodeVarintClientmsgGen(dAtA, i, uint64(len(m.UID))) 621 | i += copy(dAtA[i:], m.UID) 622 | } 623 | return i, nil 624 | } 625 | 626 | func (m *LoginACK) Marshal() (dAtA []byte, err error) { 627 | size := m.Size() 628 | dAtA = make([]byte, size) 629 | n, err := m.MarshalTo(dAtA) 630 | if err != nil { 631 | return nil, err 632 | } 633 | return dAtA[:n], nil 634 | } 635 | 636 | func (m *LoginACK) MarshalTo(dAtA []byte) (int, error) { 637 | var i int 638 | _ = i 639 | var l int 640 | _ = l 641 | if m.Result != 0 { 642 | dAtA[i] = 0x8 643 | i++ 644 | i = encodeVarintClientmsgGen(dAtA, i, uint64(m.Result)) 645 | } 646 | if m.Server != nil { 647 | dAtA[i] = 0x12 648 | i++ 649 | i = encodeVarintClientmsgGen(dAtA, i, uint64(m.Server.Size())) 650 | n1, err := m.Server.MarshalTo(dAtA[i:]) 651 | if err != nil { 652 | return 0, err 653 | } 654 | i += n1 655 | } 656 | if len(m.GameToken) > 0 { 657 | dAtA[i] = 0x1a 658 | i++ 659 | i = encodeVarintClientmsgGen(dAtA, i, uint64(len(m.GameToken))) 660 | i += copy(dAtA[i:], m.GameToken) 661 | } 662 | if len(m.GameSvcID) > 0 { 663 | dAtA[i] = 0x22 664 | i++ 665 | i = encodeVarintClientmsgGen(dAtA, i, uint64(len(m.GameSvcID))) 666 | i += copy(dAtA[i:], m.GameSvcID) 667 | } 668 | return i, nil 669 | } 670 | 671 | func (m *VerifyREQ) Marshal() (dAtA []byte, err error) { 672 | size := m.Size() 673 | dAtA = make([]byte, size) 674 | n, err := m.MarshalTo(dAtA) 675 | if err != nil { 676 | return nil, err 677 | } 678 | return dAtA[:n], nil 679 | } 680 | 681 | func (m *VerifyREQ) MarshalTo(dAtA []byte) (int, error) { 682 | var i int 683 | _ = i 684 | var l int 685 | _ = l 686 | if len(m.GameToken) > 0 { 687 | dAtA[i] = 0xa 688 | i++ 689 | i = encodeVarintClientmsgGen(dAtA, i, uint64(len(m.GameToken))) 690 | i += copy(dAtA[i:], m.GameToken) 691 | } 692 | if len(m.GameSvcID) > 0 { 693 | dAtA[i] = 0x12 694 | i++ 695 | i = encodeVarintClientmsgGen(dAtA, i, uint64(len(m.GameSvcID))) 696 | i += copy(dAtA[i:], m.GameSvcID) 697 | } 698 | return i, nil 699 | } 700 | 701 | func (m *VerifyACK) Marshal() (dAtA []byte, err error) { 702 | size := m.Size() 703 | dAtA = make([]byte, size) 704 | n, err := m.MarshalTo(dAtA) 705 | if err != nil { 706 | return nil, err 707 | } 708 | return dAtA[:n], nil 709 | } 710 | 711 | func (m *VerifyACK) MarshalTo(dAtA []byte) (int, error) { 712 | var i int 713 | _ = i 714 | var l int 715 | _ = l 716 | if m.Result != 0 { 717 | dAtA[i] = 0x8 718 | i++ 719 | i = encodeVarintClientmsgGen(dAtA, i, uint64(m.Result)) 720 | } 721 | return i, nil 722 | } 723 | 724 | func (m *ChatREQ) Marshal() (dAtA []byte, err error) { 725 | size := m.Size() 726 | dAtA = make([]byte, size) 727 | n, err := m.MarshalTo(dAtA) 728 | if err != nil { 729 | return nil, err 730 | } 731 | return dAtA[:n], nil 732 | } 733 | 734 | func (m *ChatREQ) MarshalTo(dAtA []byte) (int, error) { 735 | var i int 736 | _ = i 737 | var l int 738 | _ = l 739 | if len(m.Content) > 0 { 740 | dAtA[i] = 0xa 741 | i++ 742 | i = encodeVarintClientmsgGen(dAtA, i, uint64(len(m.Content))) 743 | i += copy(dAtA[i:], m.Content) 744 | } 745 | return i, nil 746 | } 747 | 748 | func (m *ChatACK) Marshal() (dAtA []byte, err error) { 749 | size := m.Size() 750 | dAtA = make([]byte, size) 751 | n, err := m.MarshalTo(dAtA) 752 | if err != nil { 753 | return nil, err 754 | } 755 | return dAtA[:n], nil 756 | } 757 | 758 | func (m *ChatACK) MarshalTo(dAtA []byte) (int, error) { 759 | var i int 760 | _ = i 761 | var l int 762 | _ = l 763 | if len(m.Content) > 0 { 764 | dAtA[i] = 0xa 765 | i++ 766 | i = encodeVarintClientmsgGen(dAtA, i, uint64(len(m.Content))) 767 | i += copy(dAtA[i:], m.Content) 768 | } 769 | return i, nil 770 | } 771 | 772 | func (m *TestACK) Marshal() (dAtA []byte, err error) { 773 | size := m.Size() 774 | dAtA = make([]byte, size) 775 | n, err := m.MarshalTo(dAtA) 776 | if err != nil { 777 | return nil, err 778 | } 779 | return dAtA[:n], nil 780 | } 781 | 782 | func (m *TestACK) MarshalTo(dAtA []byte) (int, error) { 783 | var i int 784 | _ = i 785 | var l int 786 | _ = l 787 | if len(m.Dummy) > 0 { 788 | dAtA[i] = 0xa 789 | i++ 790 | i = encodeVarintClientmsgGen(dAtA, i, uint64(len(m.Dummy))) 791 | i += copy(dAtA[i:], m.Dummy) 792 | } 793 | return i, nil 794 | } 795 | 796 | func encodeVarintClientmsgGen(dAtA []byte, offset int, v uint64) int { 797 | for v >= 1<<7 { 798 | dAtA[offset] = uint8(v&0x7f | 0x80) 799 | v >>= 7 800 | offset++ 801 | } 802 | dAtA[offset] = uint8(v) 803 | return offset + 1 804 | } 805 | func (m *ServerInfo) Size() (n int) { 806 | if m == nil { 807 | return 0 808 | } 809 | var l int 810 | _ = l 811 | l = len(m.IP) 812 | if l > 0 { 813 | n += 1 + l + sovClientmsgGen(uint64(l)) 814 | } 815 | if m.Port != 0 { 816 | n += 1 + sovClientmsgGen(uint64(m.Port)) 817 | } 818 | return n 819 | } 820 | 821 | func (m *PingACK) Size() (n int) { 822 | if m == nil { 823 | return 0 824 | } 825 | var l int 826 | _ = l 827 | return n 828 | } 829 | 830 | func (m *LoginREQ) Size() (n int) { 831 | if m == nil { 832 | return 0 833 | } 834 | var l int 835 | _ = l 836 | l = len(m.Version) 837 | if l > 0 { 838 | n += 1 + l + sovClientmsgGen(uint64(l)) 839 | } 840 | l = len(m.Platform) 841 | if l > 0 { 842 | n += 1 + l + sovClientmsgGen(uint64(l)) 843 | } 844 | l = len(m.UID) 845 | if l > 0 { 846 | n += 1 + l + sovClientmsgGen(uint64(l)) 847 | } 848 | return n 849 | } 850 | 851 | func (m *LoginACK) Size() (n int) { 852 | if m == nil { 853 | return 0 854 | } 855 | var l int 856 | _ = l 857 | if m.Result != 0 { 858 | n += 1 + sovClientmsgGen(uint64(m.Result)) 859 | } 860 | if m.Server != nil { 861 | l = m.Server.Size() 862 | n += 1 + l + sovClientmsgGen(uint64(l)) 863 | } 864 | l = len(m.GameToken) 865 | if l > 0 { 866 | n += 1 + l + sovClientmsgGen(uint64(l)) 867 | } 868 | l = len(m.GameSvcID) 869 | if l > 0 { 870 | n += 1 + l + sovClientmsgGen(uint64(l)) 871 | } 872 | return n 873 | } 874 | 875 | func (m *VerifyREQ) Size() (n int) { 876 | if m == nil { 877 | return 0 878 | } 879 | var l int 880 | _ = l 881 | l = len(m.GameToken) 882 | if l > 0 { 883 | n += 1 + l + sovClientmsgGen(uint64(l)) 884 | } 885 | l = len(m.GameSvcID) 886 | if l > 0 { 887 | n += 1 + l + sovClientmsgGen(uint64(l)) 888 | } 889 | return n 890 | } 891 | 892 | func (m *VerifyACK) Size() (n int) { 893 | if m == nil { 894 | return 0 895 | } 896 | var l int 897 | _ = l 898 | if m.Result != 0 { 899 | n += 1 + sovClientmsgGen(uint64(m.Result)) 900 | } 901 | return n 902 | } 903 | 904 | func (m *ChatREQ) Size() (n int) { 905 | if m == nil { 906 | return 0 907 | } 908 | var l int 909 | _ = l 910 | l = len(m.Content) 911 | if l > 0 { 912 | n += 1 + l + sovClientmsgGen(uint64(l)) 913 | } 914 | return n 915 | } 916 | 917 | func (m *ChatACK) Size() (n int) { 918 | if m == nil { 919 | return 0 920 | } 921 | var l int 922 | _ = l 923 | l = len(m.Content) 924 | if l > 0 { 925 | n += 1 + l + sovClientmsgGen(uint64(l)) 926 | } 927 | return n 928 | } 929 | 930 | func (m *TestACK) Size() (n int) { 931 | if m == nil { 932 | return 0 933 | } 934 | var l int 935 | _ = l 936 | l = len(m.Dummy) 937 | if l > 0 { 938 | n += 1 + l + sovClientmsgGen(uint64(l)) 939 | } 940 | return n 941 | } 942 | 943 | func sovClientmsgGen(x uint64) (n int) { 944 | for { 945 | n++ 946 | x >>= 7 947 | if x == 0 { 948 | break 949 | } 950 | } 951 | return n 952 | } 953 | func sozClientmsgGen(x uint64) (n int) { 954 | return sovClientmsgGen(uint64((x << 1) ^ uint64((int64(x) >> 63)))) 955 | } 956 | func (m *ServerInfo) Unmarshal(dAtA []byte) error { 957 | l := len(dAtA) 958 | iNdEx := 0 959 | for iNdEx < l { 960 | preIndex := iNdEx 961 | var wire uint64 962 | for shift := uint(0); ; shift += 7 { 963 | if shift >= 64 { 964 | return ErrIntOverflowClientmsgGen 965 | } 966 | if iNdEx >= l { 967 | return io.ErrUnexpectedEOF 968 | } 969 | b := dAtA[iNdEx] 970 | iNdEx++ 971 | wire |= uint64(b&0x7F) << shift 972 | if b < 0x80 { 973 | break 974 | } 975 | } 976 | fieldNum := int32(wire >> 3) 977 | wireType := int(wire & 0x7) 978 | if wireType == 4 { 979 | return fmt.Errorf("proto: ServerInfo: wiretype end group for non-group") 980 | } 981 | if fieldNum <= 0 { 982 | return fmt.Errorf("proto: ServerInfo: illegal tag %d (wire type %d)", fieldNum, wire) 983 | } 984 | switch fieldNum { 985 | case 1: 986 | if wireType != 2 { 987 | return fmt.Errorf("proto: wrong wireType = %d for field IP", wireType) 988 | } 989 | var stringLen uint64 990 | for shift := uint(0); ; shift += 7 { 991 | if shift >= 64 { 992 | return ErrIntOverflowClientmsgGen 993 | } 994 | if iNdEx >= l { 995 | return io.ErrUnexpectedEOF 996 | } 997 | b := dAtA[iNdEx] 998 | iNdEx++ 999 | stringLen |= uint64(b&0x7F) << shift 1000 | if b < 0x80 { 1001 | break 1002 | } 1003 | } 1004 | intStringLen := int(stringLen) 1005 | if intStringLen < 0 { 1006 | return ErrInvalidLengthClientmsgGen 1007 | } 1008 | postIndex := iNdEx + intStringLen 1009 | if postIndex < 0 { 1010 | return ErrInvalidLengthClientmsgGen 1011 | } 1012 | if postIndex > l { 1013 | return io.ErrUnexpectedEOF 1014 | } 1015 | m.IP = string(dAtA[iNdEx:postIndex]) 1016 | iNdEx = postIndex 1017 | case 2: 1018 | if wireType != 0 { 1019 | return fmt.Errorf("proto: wrong wireType = %d for field Port", wireType) 1020 | } 1021 | m.Port = 0 1022 | for shift := uint(0); ; shift += 7 { 1023 | if shift >= 64 { 1024 | return ErrIntOverflowClientmsgGen 1025 | } 1026 | if iNdEx >= l { 1027 | return io.ErrUnexpectedEOF 1028 | } 1029 | b := dAtA[iNdEx] 1030 | iNdEx++ 1031 | m.Port |= int32(b&0x7F) << shift 1032 | if b < 0x80 { 1033 | break 1034 | } 1035 | } 1036 | default: 1037 | iNdEx = preIndex 1038 | skippy, err := skipClientmsgGen(dAtA[iNdEx:]) 1039 | if err != nil { 1040 | return err 1041 | } 1042 | if skippy < 0 { 1043 | return ErrInvalidLengthClientmsgGen 1044 | } 1045 | if (iNdEx + skippy) < 0 { 1046 | return ErrInvalidLengthClientmsgGen 1047 | } 1048 | if (iNdEx + skippy) > l { 1049 | return io.ErrUnexpectedEOF 1050 | } 1051 | iNdEx += skippy 1052 | } 1053 | } 1054 | 1055 | if iNdEx > l { 1056 | return io.ErrUnexpectedEOF 1057 | } 1058 | return nil 1059 | } 1060 | func (m *PingACK) Unmarshal(dAtA []byte) error { 1061 | l := len(dAtA) 1062 | iNdEx := 0 1063 | for iNdEx < l { 1064 | preIndex := iNdEx 1065 | var wire uint64 1066 | for shift := uint(0); ; shift += 7 { 1067 | if shift >= 64 { 1068 | return ErrIntOverflowClientmsgGen 1069 | } 1070 | if iNdEx >= l { 1071 | return io.ErrUnexpectedEOF 1072 | } 1073 | b := dAtA[iNdEx] 1074 | iNdEx++ 1075 | wire |= uint64(b&0x7F) << shift 1076 | if b < 0x80 { 1077 | break 1078 | } 1079 | } 1080 | fieldNum := int32(wire >> 3) 1081 | wireType := int(wire & 0x7) 1082 | if wireType == 4 { 1083 | return fmt.Errorf("proto: PingACK: wiretype end group for non-group") 1084 | } 1085 | if fieldNum <= 0 { 1086 | return fmt.Errorf("proto: PingACK: illegal tag %d (wire type %d)", fieldNum, wire) 1087 | } 1088 | switch fieldNum { 1089 | default: 1090 | iNdEx = preIndex 1091 | skippy, err := skipClientmsgGen(dAtA[iNdEx:]) 1092 | if err != nil { 1093 | return err 1094 | } 1095 | if skippy < 0 { 1096 | return ErrInvalidLengthClientmsgGen 1097 | } 1098 | if (iNdEx + skippy) < 0 { 1099 | return ErrInvalidLengthClientmsgGen 1100 | } 1101 | if (iNdEx + skippy) > l { 1102 | return io.ErrUnexpectedEOF 1103 | } 1104 | iNdEx += skippy 1105 | } 1106 | } 1107 | 1108 | if iNdEx > l { 1109 | return io.ErrUnexpectedEOF 1110 | } 1111 | return nil 1112 | } 1113 | func (m *LoginREQ) Unmarshal(dAtA []byte) error { 1114 | l := len(dAtA) 1115 | iNdEx := 0 1116 | for iNdEx < l { 1117 | preIndex := iNdEx 1118 | var wire uint64 1119 | for shift := uint(0); ; shift += 7 { 1120 | if shift >= 64 { 1121 | return ErrIntOverflowClientmsgGen 1122 | } 1123 | if iNdEx >= l { 1124 | return io.ErrUnexpectedEOF 1125 | } 1126 | b := dAtA[iNdEx] 1127 | iNdEx++ 1128 | wire |= uint64(b&0x7F) << shift 1129 | if b < 0x80 { 1130 | break 1131 | } 1132 | } 1133 | fieldNum := int32(wire >> 3) 1134 | wireType := int(wire & 0x7) 1135 | if wireType == 4 { 1136 | return fmt.Errorf("proto: LoginREQ: wiretype end group for non-group") 1137 | } 1138 | if fieldNum <= 0 { 1139 | return fmt.Errorf("proto: LoginREQ: illegal tag %d (wire type %d)", fieldNum, wire) 1140 | } 1141 | switch fieldNum { 1142 | case 1: 1143 | if wireType != 2 { 1144 | return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) 1145 | } 1146 | var stringLen uint64 1147 | for shift := uint(0); ; shift += 7 { 1148 | if shift >= 64 { 1149 | return ErrIntOverflowClientmsgGen 1150 | } 1151 | if iNdEx >= l { 1152 | return io.ErrUnexpectedEOF 1153 | } 1154 | b := dAtA[iNdEx] 1155 | iNdEx++ 1156 | stringLen |= uint64(b&0x7F) << shift 1157 | if b < 0x80 { 1158 | break 1159 | } 1160 | } 1161 | intStringLen := int(stringLen) 1162 | if intStringLen < 0 { 1163 | return ErrInvalidLengthClientmsgGen 1164 | } 1165 | postIndex := iNdEx + intStringLen 1166 | if postIndex < 0 { 1167 | return ErrInvalidLengthClientmsgGen 1168 | } 1169 | if postIndex > l { 1170 | return io.ErrUnexpectedEOF 1171 | } 1172 | m.Version = string(dAtA[iNdEx:postIndex]) 1173 | iNdEx = postIndex 1174 | case 2: 1175 | if wireType != 2 { 1176 | return fmt.Errorf("proto: wrong wireType = %d for field Platform", wireType) 1177 | } 1178 | var stringLen uint64 1179 | for shift := uint(0); ; shift += 7 { 1180 | if shift >= 64 { 1181 | return ErrIntOverflowClientmsgGen 1182 | } 1183 | if iNdEx >= l { 1184 | return io.ErrUnexpectedEOF 1185 | } 1186 | b := dAtA[iNdEx] 1187 | iNdEx++ 1188 | stringLen |= uint64(b&0x7F) << shift 1189 | if b < 0x80 { 1190 | break 1191 | } 1192 | } 1193 | intStringLen := int(stringLen) 1194 | if intStringLen < 0 { 1195 | return ErrInvalidLengthClientmsgGen 1196 | } 1197 | postIndex := iNdEx + intStringLen 1198 | if postIndex < 0 { 1199 | return ErrInvalidLengthClientmsgGen 1200 | } 1201 | if postIndex > l { 1202 | return io.ErrUnexpectedEOF 1203 | } 1204 | m.Platform = string(dAtA[iNdEx:postIndex]) 1205 | iNdEx = postIndex 1206 | case 3: 1207 | if wireType != 2 { 1208 | return fmt.Errorf("proto: wrong wireType = %d for field UID", wireType) 1209 | } 1210 | var stringLen uint64 1211 | for shift := uint(0); ; shift += 7 { 1212 | if shift >= 64 { 1213 | return ErrIntOverflowClientmsgGen 1214 | } 1215 | if iNdEx >= l { 1216 | return io.ErrUnexpectedEOF 1217 | } 1218 | b := dAtA[iNdEx] 1219 | iNdEx++ 1220 | stringLen |= uint64(b&0x7F) << shift 1221 | if b < 0x80 { 1222 | break 1223 | } 1224 | } 1225 | intStringLen := int(stringLen) 1226 | if intStringLen < 0 { 1227 | return ErrInvalidLengthClientmsgGen 1228 | } 1229 | postIndex := iNdEx + intStringLen 1230 | if postIndex < 0 { 1231 | return ErrInvalidLengthClientmsgGen 1232 | } 1233 | if postIndex > l { 1234 | return io.ErrUnexpectedEOF 1235 | } 1236 | m.UID = string(dAtA[iNdEx:postIndex]) 1237 | iNdEx = postIndex 1238 | default: 1239 | iNdEx = preIndex 1240 | skippy, err := skipClientmsgGen(dAtA[iNdEx:]) 1241 | if err != nil { 1242 | return err 1243 | } 1244 | if skippy < 0 { 1245 | return ErrInvalidLengthClientmsgGen 1246 | } 1247 | if (iNdEx + skippy) < 0 { 1248 | return ErrInvalidLengthClientmsgGen 1249 | } 1250 | if (iNdEx + skippy) > l { 1251 | return io.ErrUnexpectedEOF 1252 | } 1253 | iNdEx += skippy 1254 | } 1255 | } 1256 | 1257 | if iNdEx > l { 1258 | return io.ErrUnexpectedEOF 1259 | } 1260 | return nil 1261 | } 1262 | func (m *LoginACK) Unmarshal(dAtA []byte) error { 1263 | l := len(dAtA) 1264 | iNdEx := 0 1265 | for iNdEx < l { 1266 | preIndex := iNdEx 1267 | var wire uint64 1268 | for shift := uint(0); ; shift += 7 { 1269 | if shift >= 64 { 1270 | return ErrIntOverflowClientmsgGen 1271 | } 1272 | if iNdEx >= l { 1273 | return io.ErrUnexpectedEOF 1274 | } 1275 | b := dAtA[iNdEx] 1276 | iNdEx++ 1277 | wire |= uint64(b&0x7F) << shift 1278 | if b < 0x80 { 1279 | break 1280 | } 1281 | } 1282 | fieldNum := int32(wire >> 3) 1283 | wireType := int(wire & 0x7) 1284 | if wireType == 4 { 1285 | return fmt.Errorf("proto: LoginACK: wiretype end group for non-group") 1286 | } 1287 | if fieldNum <= 0 { 1288 | return fmt.Errorf("proto: LoginACK: illegal tag %d (wire type %d)", fieldNum, wire) 1289 | } 1290 | switch fieldNum { 1291 | case 1: 1292 | if wireType != 0 { 1293 | return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) 1294 | } 1295 | m.Result = 0 1296 | for shift := uint(0); ; shift += 7 { 1297 | if shift >= 64 { 1298 | return ErrIntOverflowClientmsgGen 1299 | } 1300 | if iNdEx >= l { 1301 | return io.ErrUnexpectedEOF 1302 | } 1303 | b := dAtA[iNdEx] 1304 | iNdEx++ 1305 | m.Result |= ResultCode(b&0x7F) << shift 1306 | if b < 0x80 { 1307 | break 1308 | } 1309 | } 1310 | case 2: 1311 | if wireType != 2 { 1312 | return fmt.Errorf("proto: wrong wireType = %d for field Server", wireType) 1313 | } 1314 | var msglen int 1315 | for shift := uint(0); ; shift += 7 { 1316 | if shift >= 64 { 1317 | return ErrIntOverflowClientmsgGen 1318 | } 1319 | if iNdEx >= l { 1320 | return io.ErrUnexpectedEOF 1321 | } 1322 | b := dAtA[iNdEx] 1323 | iNdEx++ 1324 | msglen |= int(b&0x7F) << shift 1325 | if b < 0x80 { 1326 | break 1327 | } 1328 | } 1329 | if msglen < 0 { 1330 | return ErrInvalidLengthClientmsgGen 1331 | } 1332 | postIndex := iNdEx + msglen 1333 | if postIndex < 0 { 1334 | return ErrInvalidLengthClientmsgGen 1335 | } 1336 | if postIndex > l { 1337 | return io.ErrUnexpectedEOF 1338 | } 1339 | if m.Server == nil { 1340 | m.Server = &ServerInfo{} 1341 | } 1342 | if err := m.Server.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { 1343 | return err 1344 | } 1345 | iNdEx = postIndex 1346 | case 3: 1347 | if wireType != 2 { 1348 | return fmt.Errorf("proto: wrong wireType = %d for field GameToken", wireType) 1349 | } 1350 | var stringLen uint64 1351 | for shift := uint(0); ; shift += 7 { 1352 | if shift >= 64 { 1353 | return ErrIntOverflowClientmsgGen 1354 | } 1355 | if iNdEx >= l { 1356 | return io.ErrUnexpectedEOF 1357 | } 1358 | b := dAtA[iNdEx] 1359 | iNdEx++ 1360 | stringLen |= uint64(b&0x7F) << shift 1361 | if b < 0x80 { 1362 | break 1363 | } 1364 | } 1365 | intStringLen := int(stringLen) 1366 | if intStringLen < 0 { 1367 | return ErrInvalidLengthClientmsgGen 1368 | } 1369 | postIndex := iNdEx + intStringLen 1370 | if postIndex < 0 { 1371 | return ErrInvalidLengthClientmsgGen 1372 | } 1373 | if postIndex > l { 1374 | return io.ErrUnexpectedEOF 1375 | } 1376 | m.GameToken = string(dAtA[iNdEx:postIndex]) 1377 | iNdEx = postIndex 1378 | case 4: 1379 | if wireType != 2 { 1380 | return fmt.Errorf("proto: wrong wireType = %d for field GameSvcID", wireType) 1381 | } 1382 | var stringLen uint64 1383 | for shift := uint(0); ; shift += 7 { 1384 | if shift >= 64 { 1385 | return ErrIntOverflowClientmsgGen 1386 | } 1387 | if iNdEx >= l { 1388 | return io.ErrUnexpectedEOF 1389 | } 1390 | b := dAtA[iNdEx] 1391 | iNdEx++ 1392 | stringLen |= uint64(b&0x7F) << shift 1393 | if b < 0x80 { 1394 | break 1395 | } 1396 | } 1397 | intStringLen := int(stringLen) 1398 | if intStringLen < 0 { 1399 | return ErrInvalidLengthClientmsgGen 1400 | } 1401 | postIndex := iNdEx + intStringLen 1402 | if postIndex < 0 { 1403 | return ErrInvalidLengthClientmsgGen 1404 | } 1405 | if postIndex > l { 1406 | return io.ErrUnexpectedEOF 1407 | } 1408 | m.GameSvcID = string(dAtA[iNdEx:postIndex]) 1409 | iNdEx = postIndex 1410 | default: 1411 | iNdEx = preIndex 1412 | skippy, err := skipClientmsgGen(dAtA[iNdEx:]) 1413 | if err != nil { 1414 | return err 1415 | } 1416 | if skippy < 0 { 1417 | return ErrInvalidLengthClientmsgGen 1418 | } 1419 | if (iNdEx + skippy) < 0 { 1420 | return ErrInvalidLengthClientmsgGen 1421 | } 1422 | if (iNdEx + skippy) > l { 1423 | return io.ErrUnexpectedEOF 1424 | } 1425 | iNdEx += skippy 1426 | } 1427 | } 1428 | 1429 | if iNdEx > l { 1430 | return io.ErrUnexpectedEOF 1431 | } 1432 | return nil 1433 | } 1434 | func (m *VerifyREQ) Unmarshal(dAtA []byte) error { 1435 | l := len(dAtA) 1436 | iNdEx := 0 1437 | for iNdEx < l { 1438 | preIndex := iNdEx 1439 | var wire uint64 1440 | for shift := uint(0); ; shift += 7 { 1441 | if shift >= 64 { 1442 | return ErrIntOverflowClientmsgGen 1443 | } 1444 | if iNdEx >= l { 1445 | return io.ErrUnexpectedEOF 1446 | } 1447 | b := dAtA[iNdEx] 1448 | iNdEx++ 1449 | wire |= uint64(b&0x7F) << shift 1450 | if b < 0x80 { 1451 | break 1452 | } 1453 | } 1454 | fieldNum := int32(wire >> 3) 1455 | wireType := int(wire & 0x7) 1456 | if wireType == 4 { 1457 | return fmt.Errorf("proto: VerifyREQ: wiretype end group for non-group") 1458 | } 1459 | if fieldNum <= 0 { 1460 | return fmt.Errorf("proto: VerifyREQ: illegal tag %d (wire type %d)", fieldNum, wire) 1461 | } 1462 | switch fieldNum { 1463 | case 1: 1464 | if wireType != 2 { 1465 | return fmt.Errorf("proto: wrong wireType = %d for field GameToken", wireType) 1466 | } 1467 | var stringLen uint64 1468 | for shift := uint(0); ; shift += 7 { 1469 | if shift >= 64 { 1470 | return ErrIntOverflowClientmsgGen 1471 | } 1472 | if iNdEx >= l { 1473 | return io.ErrUnexpectedEOF 1474 | } 1475 | b := dAtA[iNdEx] 1476 | iNdEx++ 1477 | stringLen |= uint64(b&0x7F) << shift 1478 | if b < 0x80 { 1479 | break 1480 | } 1481 | } 1482 | intStringLen := int(stringLen) 1483 | if intStringLen < 0 { 1484 | return ErrInvalidLengthClientmsgGen 1485 | } 1486 | postIndex := iNdEx + intStringLen 1487 | if postIndex < 0 { 1488 | return ErrInvalidLengthClientmsgGen 1489 | } 1490 | if postIndex > l { 1491 | return io.ErrUnexpectedEOF 1492 | } 1493 | m.GameToken = string(dAtA[iNdEx:postIndex]) 1494 | iNdEx = postIndex 1495 | case 2: 1496 | if wireType != 2 { 1497 | return fmt.Errorf("proto: wrong wireType = %d for field GameSvcID", wireType) 1498 | } 1499 | var stringLen uint64 1500 | for shift := uint(0); ; shift += 7 { 1501 | if shift >= 64 { 1502 | return ErrIntOverflowClientmsgGen 1503 | } 1504 | if iNdEx >= l { 1505 | return io.ErrUnexpectedEOF 1506 | } 1507 | b := dAtA[iNdEx] 1508 | iNdEx++ 1509 | stringLen |= uint64(b&0x7F) << shift 1510 | if b < 0x80 { 1511 | break 1512 | } 1513 | } 1514 | intStringLen := int(stringLen) 1515 | if intStringLen < 0 { 1516 | return ErrInvalidLengthClientmsgGen 1517 | } 1518 | postIndex := iNdEx + intStringLen 1519 | if postIndex < 0 { 1520 | return ErrInvalidLengthClientmsgGen 1521 | } 1522 | if postIndex > l { 1523 | return io.ErrUnexpectedEOF 1524 | } 1525 | m.GameSvcID = string(dAtA[iNdEx:postIndex]) 1526 | iNdEx = postIndex 1527 | default: 1528 | iNdEx = preIndex 1529 | skippy, err := skipClientmsgGen(dAtA[iNdEx:]) 1530 | if err != nil { 1531 | return err 1532 | } 1533 | if skippy < 0 { 1534 | return ErrInvalidLengthClientmsgGen 1535 | } 1536 | if (iNdEx + skippy) < 0 { 1537 | return ErrInvalidLengthClientmsgGen 1538 | } 1539 | if (iNdEx + skippy) > l { 1540 | return io.ErrUnexpectedEOF 1541 | } 1542 | iNdEx += skippy 1543 | } 1544 | } 1545 | 1546 | if iNdEx > l { 1547 | return io.ErrUnexpectedEOF 1548 | } 1549 | return nil 1550 | } 1551 | func (m *VerifyACK) Unmarshal(dAtA []byte) error { 1552 | l := len(dAtA) 1553 | iNdEx := 0 1554 | for iNdEx < l { 1555 | preIndex := iNdEx 1556 | var wire uint64 1557 | for shift := uint(0); ; shift += 7 { 1558 | if shift >= 64 { 1559 | return ErrIntOverflowClientmsgGen 1560 | } 1561 | if iNdEx >= l { 1562 | return io.ErrUnexpectedEOF 1563 | } 1564 | b := dAtA[iNdEx] 1565 | iNdEx++ 1566 | wire |= uint64(b&0x7F) << shift 1567 | if b < 0x80 { 1568 | break 1569 | } 1570 | } 1571 | fieldNum := int32(wire >> 3) 1572 | wireType := int(wire & 0x7) 1573 | if wireType == 4 { 1574 | return fmt.Errorf("proto: VerifyACK: wiretype end group for non-group") 1575 | } 1576 | if fieldNum <= 0 { 1577 | return fmt.Errorf("proto: VerifyACK: illegal tag %d (wire type %d)", fieldNum, wire) 1578 | } 1579 | switch fieldNum { 1580 | case 1: 1581 | if wireType != 0 { 1582 | return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) 1583 | } 1584 | m.Result = 0 1585 | for shift := uint(0); ; shift += 7 { 1586 | if shift >= 64 { 1587 | return ErrIntOverflowClientmsgGen 1588 | } 1589 | if iNdEx >= l { 1590 | return io.ErrUnexpectedEOF 1591 | } 1592 | b := dAtA[iNdEx] 1593 | iNdEx++ 1594 | m.Result |= ResultCode(b&0x7F) << shift 1595 | if b < 0x80 { 1596 | break 1597 | } 1598 | } 1599 | default: 1600 | iNdEx = preIndex 1601 | skippy, err := skipClientmsgGen(dAtA[iNdEx:]) 1602 | if err != nil { 1603 | return err 1604 | } 1605 | if skippy < 0 { 1606 | return ErrInvalidLengthClientmsgGen 1607 | } 1608 | if (iNdEx + skippy) < 0 { 1609 | return ErrInvalidLengthClientmsgGen 1610 | } 1611 | if (iNdEx + skippy) > l { 1612 | return io.ErrUnexpectedEOF 1613 | } 1614 | iNdEx += skippy 1615 | } 1616 | } 1617 | 1618 | if iNdEx > l { 1619 | return io.ErrUnexpectedEOF 1620 | } 1621 | return nil 1622 | } 1623 | func (m *ChatREQ) Unmarshal(dAtA []byte) error { 1624 | l := len(dAtA) 1625 | iNdEx := 0 1626 | for iNdEx < l { 1627 | preIndex := iNdEx 1628 | var wire uint64 1629 | for shift := uint(0); ; shift += 7 { 1630 | if shift >= 64 { 1631 | return ErrIntOverflowClientmsgGen 1632 | } 1633 | if iNdEx >= l { 1634 | return io.ErrUnexpectedEOF 1635 | } 1636 | b := dAtA[iNdEx] 1637 | iNdEx++ 1638 | wire |= uint64(b&0x7F) << shift 1639 | if b < 0x80 { 1640 | break 1641 | } 1642 | } 1643 | fieldNum := int32(wire >> 3) 1644 | wireType := int(wire & 0x7) 1645 | if wireType == 4 { 1646 | return fmt.Errorf("proto: ChatREQ: wiretype end group for non-group") 1647 | } 1648 | if fieldNum <= 0 { 1649 | return fmt.Errorf("proto: ChatREQ: illegal tag %d (wire type %d)", fieldNum, wire) 1650 | } 1651 | switch fieldNum { 1652 | case 1: 1653 | if wireType != 2 { 1654 | return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) 1655 | } 1656 | var stringLen uint64 1657 | for shift := uint(0); ; shift += 7 { 1658 | if shift >= 64 { 1659 | return ErrIntOverflowClientmsgGen 1660 | } 1661 | if iNdEx >= l { 1662 | return io.ErrUnexpectedEOF 1663 | } 1664 | b := dAtA[iNdEx] 1665 | iNdEx++ 1666 | stringLen |= uint64(b&0x7F) << shift 1667 | if b < 0x80 { 1668 | break 1669 | } 1670 | } 1671 | intStringLen := int(stringLen) 1672 | if intStringLen < 0 { 1673 | return ErrInvalidLengthClientmsgGen 1674 | } 1675 | postIndex := iNdEx + intStringLen 1676 | if postIndex < 0 { 1677 | return ErrInvalidLengthClientmsgGen 1678 | } 1679 | if postIndex > l { 1680 | return io.ErrUnexpectedEOF 1681 | } 1682 | m.Content = string(dAtA[iNdEx:postIndex]) 1683 | iNdEx = postIndex 1684 | default: 1685 | iNdEx = preIndex 1686 | skippy, err := skipClientmsgGen(dAtA[iNdEx:]) 1687 | if err != nil { 1688 | return err 1689 | } 1690 | if skippy < 0 { 1691 | return ErrInvalidLengthClientmsgGen 1692 | } 1693 | if (iNdEx + skippy) < 0 { 1694 | return ErrInvalidLengthClientmsgGen 1695 | } 1696 | if (iNdEx + skippy) > l { 1697 | return io.ErrUnexpectedEOF 1698 | } 1699 | iNdEx += skippy 1700 | } 1701 | } 1702 | 1703 | if iNdEx > l { 1704 | return io.ErrUnexpectedEOF 1705 | } 1706 | return nil 1707 | } 1708 | func (m *ChatACK) Unmarshal(dAtA []byte) error { 1709 | l := len(dAtA) 1710 | iNdEx := 0 1711 | for iNdEx < l { 1712 | preIndex := iNdEx 1713 | var wire uint64 1714 | for shift := uint(0); ; shift += 7 { 1715 | if shift >= 64 { 1716 | return ErrIntOverflowClientmsgGen 1717 | } 1718 | if iNdEx >= l { 1719 | return io.ErrUnexpectedEOF 1720 | } 1721 | b := dAtA[iNdEx] 1722 | iNdEx++ 1723 | wire |= uint64(b&0x7F) << shift 1724 | if b < 0x80 { 1725 | break 1726 | } 1727 | } 1728 | fieldNum := int32(wire >> 3) 1729 | wireType := int(wire & 0x7) 1730 | if wireType == 4 { 1731 | return fmt.Errorf("proto: ChatACK: wiretype end group for non-group") 1732 | } 1733 | if fieldNum <= 0 { 1734 | return fmt.Errorf("proto: ChatACK: illegal tag %d (wire type %d)", fieldNum, wire) 1735 | } 1736 | switch fieldNum { 1737 | case 1: 1738 | if wireType != 2 { 1739 | return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) 1740 | } 1741 | var stringLen uint64 1742 | for shift := uint(0); ; shift += 7 { 1743 | if shift >= 64 { 1744 | return ErrIntOverflowClientmsgGen 1745 | } 1746 | if iNdEx >= l { 1747 | return io.ErrUnexpectedEOF 1748 | } 1749 | b := dAtA[iNdEx] 1750 | iNdEx++ 1751 | stringLen |= uint64(b&0x7F) << shift 1752 | if b < 0x80 { 1753 | break 1754 | } 1755 | } 1756 | intStringLen := int(stringLen) 1757 | if intStringLen < 0 { 1758 | return ErrInvalidLengthClientmsgGen 1759 | } 1760 | postIndex := iNdEx + intStringLen 1761 | if postIndex < 0 { 1762 | return ErrInvalidLengthClientmsgGen 1763 | } 1764 | if postIndex > l { 1765 | return io.ErrUnexpectedEOF 1766 | } 1767 | m.Content = string(dAtA[iNdEx:postIndex]) 1768 | iNdEx = postIndex 1769 | default: 1770 | iNdEx = preIndex 1771 | skippy, err := skipClientmsgGen(dAtA[iNdEx:]) 1772 | if err != nil { 1773 | return err 1774 | } 1775 | if skippy < 0 { 1776 | return ErrInvalidLengthClientmsgGen 1777 | } 1778 | if (iNdEx + skippy) < 0 { 1779 | return ErrInvalidLengthClientmsgGen 1780 | } 1781 | if (iNdEx + skippy) > l { 1782 | return io.ErrUnexpectedEOF 1783 | } 1784 | iNdEx += skippy 1785 | } 1786 | } 1787 | 1788 | if iNdEx > l { 1789 | return io.ErrUnexpectedEOF 1790 | } 1791 | return nil 1792 | } 1793 | func (m *TestACK) Unmarshal(dAtA []byte) error { 1794 | l := len(dAtA) 1795 | iNdEx := 0 1796 | for iNdEx < l { 1797 | preIndex := iNdEx 1798 | var wire uint64 1799 | for shift := uint(0); ; shift += 7 { 1800 | if shift >= 64 { 1801 | return ErrIntOverflowClientmsgGen 1802 | } 1803 | if iNdEx >= l { 1804 | return io.ErrUnexpectedEOF 1805 | } 1806 | b := dAtA[iNdEx] 1807 | iNdEx++ 1808 | wire |= uint64(b&0x7F) << shift 1809 | if b < 0x80 { 1810 | break 1811 | } 1812 | } 1813 | fieldNum := int32(wire >> 3) 1814 | wireType := int(wire & 0x7) 1815 | if wireType == 4 { 1816 | return fmt.Errorf("proto: TestACK: wiretype end group for non-group") 1817 | } 1818 | if fieldNum <= 0 { 1819 | return fmt.Errorf("proto: TestACK: illegal tag %d (wire type %d)", fieldNum, wire) 1820 | } 1821 | switch fieldNum { 1822 | case 1: 1823 | if wireType != 2 { 1824 | return fmt.Errorf("proto: wrong wireType = %d for field Dummy", wireType) 1825 | } 1826 | var stringLen uint64 1827 | for shift := uint(0); ; shift += 7 { 1828 | if shift >= 64 { 1829 | return ErrIntOverflowClientmsgGen 1830 | } 1831 | if iNdEx >= l { 1832 | return io.ErrUnexpectedEOF 1833 | } 1834 | b := dAtA[iNdEx] 1835 | iNdEx++ 1836 | stringLen |= uint64(b&0x7F) << shift 1837 | if b < 0x80 { 1838 | break 1839 | } 1840 | } 1841 | intStringLen := int(stringLen) 1842 | if intStringLen < 0 { 1843 | return ErrInvalidLengthClientmsgGen 1844 | } 1845 | postIndex := iNdEx + intStringLen 1846 | if postIndex < 0 { 1847 | return ErrInvalidLengthClientmsgGen 1848 | } 1849 | if postIndex > l { 1850 | return io.ErrUnexpectedEOF 1851 | } 1852 | m.Dummy = string(dAtA[iNdEx:postIndex]) 1853 | iNdEx = postIndex 1854 | default: 1855 | iNdEx = preIndex 1856 | skippy, err := skipClientmsgGen(dAtA[iNdEx:]) 1857 | if err != nil { 1858 | return err 1859 | } 1860 | if skippy < 0 { 1861 | return ErrInvalidLengthClientmsgGen 1862 | } 1863 | if (iNdEx + skippy) < 0 { 1864 | return ErrInvalidLengthClientmsgGen 1865 | } 1866 | if (iNdEx + skippy) > l { 1867 | return io.ErrUnexpectedEOF 1868 | } 1869 | iNdEx += skippy 1870 | } 1871 | } 1872 | 1873 | if iNdEx > l { 1874 | return io.ErrUnexpectedEOF 1875 | } 1876 | return nil 1877 | } 1878 | func skipClientmsgGen(dAtA []byte) (n int, err error) { 1879 | l := len(dAtA) 1880 | iNdEx := 0 1881 | for iNdEx < l { 1882 | var wire uint64 1883 | for shift := uint(0); ; shift += 7 { 1884 | if shift >= 64 { 1885 | return 0, ErrIntOverflowClientmsgGen 1886 | } 1887 | if iNdEx >= l { 1888 | return 0, io.ErrUnexpectedEOF 1889 | } 1890 | b := dAtA[iNdEx] 1891 | iNdEx++ 1892 | wire |= (uint64(b) & 0x7F) << shift 1893 | if b < 0x80 { 1894 | break 1895 | } 1896 | } 1897 | wireType := int(wire & 0x7) 1898 | switch wireType { 1899 | case 0: 1900 | for shift := uint(0); ; shift += 7 { 1901 | if shift >= 64 { 1902 | return 0, ErrIntOverflowClientmsgGen 1903 | } 1904 | if iNdEx >= l { 1905 | return 0, io.ErrUnexpectedEOF 1906 | } 1907 | iNdEx++ 1908 | if dAtA[iNdEx-1] < 0x80 { 1909 | break 1910 | } 1911 | } 1912 | return iNdEx, nil 1913 | case 1: 1914 | iNdEx += 8 1915 | return iNdEx, nil 1916 | case 2: 1917 | var length int 1918 | for shift := uint(0); ; shift += 7 { 1919 | if shift >= 64 { 1920 | return 0, ErrIntOverflowClientmsgGen 1921 | } 1922 | if iNdEx >= l { 1923 | return 0, io.ErrUnexpectedEOF 1924 | } 1925 | b := dAtA[iNdEx] 1926 | iNdEx++ 1927 | length |= (int(b) & 0x7F) << shift 1928 | if b < 0x80 { 1929 | break 1930 | } 1931 | } 1932 | if length < 0 { 1933 | return 0, ErrInvalidLengthClientmsgGen 1934 | } 1935 | iNdEx += length 1936 | if iNdEx < 0 { 1937 | return 0, ErrInvalidLengthClientmsgGen 1938 | } 1939 | return iNdEx, nil 1940 | case 3: 1941 | for { 1942 | var innerWire uint64 1943 | var start int = iNdEx 1944 | for shift := uint(0); ; shift += 7 { 1945 | if shift >= 64 { 1946 | return 0, ErrIntOverflowClientmsgGen 1947 | } 1948 | if iNdEx >= l { 1949 | return 0, io.ErrUnexpectedEOF 1950 | } 1951 | b := dAtA[iNdEx] 1952 | iNdEx++ 1953 | innerWire |= (uint64(b) & 0x7F) << shift 1954 | if b < 0x80 { 1955 | break 1956 | } 1957 | } 1958 | innerWireType := int(innerWire & 0x7) 1959 | if innerWireType == 4 { 1960 | break 1961 | } 1962 | next, err := skipClientmsgGen(dAtA[start:]) 1963 | if err != nil { 1964 | return 0, err 1965 | } 1966 | iNdEx = start + next 1967 | if iNdEx < 0 { 1968 | return 0, ErrInvalidLengthClientmsgGen 1969 | } 1970 | } 1971 | return iNdEx, nil 1972 | case 4: 1973 | return iNdEx, nil 1974 | case 5: 1975 | iNdEx += 4 1976 | return iNdEx, nil 1977 | default: 1978 | return 0, fmt.Errorf("proto: illegal wireType %d", wireType) 1979 | } 1980 | } 1981 | panic("unreachable") 1982 | } 1983 | 1984 | var ( 1985 | ErrInvalidLengthClientmsgGen = fmt.Errorf("proto: negative length found during unmarshaling") 1986 | ErrIntOverflowClientmsgGen = fmt.Errorf("proto: integer overflow") 1987 | ) 1988 | --------------------------------------------------------------------------------