├── .gitignore ├── go.mod ├── config.ini ├── lib ├── BaseInterface.go ├── worker │ ├── GatewayHandle.go │ ├── RegisterEvent.go │ └── GatewayEvent.go ├── config.go ├── gateway │ ├── RegisterEvent.go │ ├── Router.go │ ├── WorkerEvent.go │ ├── WebSocketEvent.go │ └── WorkerHandle.go ├── Gateway.go ├── register │ └── RegisterEvent.go └── GatewayProtocol.go ├── main.go ├── apps └── main.go ├── console ├── Worker.go ├── Register.go └── Gateway.go └── go.sum /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /.idea 3 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ctfang/goworker 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/ctfang/command v0.0.0-20190327092056-27958f50a31c 7 | github.com/ctfang/network v0.0.0-20190619120328-6dbb209f2d1f 8 | github.com/techleeone/gophp v0.1.0 9 | ) 10 | -------------------------------------------------------------------------------- /config.ini: -------------------------------------------------------------------------------- 1 | ; 本机ip,分布式部署时使用内网ip 2 | LanIp=192.168.23.58 3 | ; 网关地址websocket 4 | gateway="0.0.0.0:7272" 5 | ; 注册中心 6 | register="127.0.0.1:1238" 7 | ;register="192.168.26.2:3000" 8 | ;register="192.168.251.184:1238" 9 | ; 内部通讯地址 10 | worker="192.168.23.58:4000" 11 | ; 通讯秘钥 12 | secret="" -------------------------------------------------------------------------------- /lib/BaseInterface.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | type LogicEvent interface { 4 | OnStart() 5 | // 新链接 6 | OnConnect(clientId string) 7 | // 当客户端连接上gateway完成websocket握手时触发的回调函数。 8 | OnWebSocketConnect(clientId string, header []byte) 9 | // 新信息 10 | OnMessage(clientId string, body []byte) 11 | // 链接关闭 12 | OnClose(clientId string) 13 | } 14 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/ctfang/command" 5 | "github.com/ctfang/goworker/console" 6 | ) 7 | 8 | func main() { 9 | app := command.New() 10 | 11 | app.SetConfig("config.ini") 12 | app.IniConfig() 13 | 14 | AddCommands(&app) 15 | app.Run() 16 | } 17 | 18 | func AddCommands(app *command.Console) { 19 | app.AddCommand(&console.Register{}) 20 | app.AddCommand(&console.Gateway{}) 21 | app.AddCommand(&console.Worker{}) 22 | } 23 | -------------------------------------------------------------------------------- /apps/main.go: -------------------------------------------------------------------------------- 1 | package apps 2 | 3 | import ( 4 | "github.com/ctfang/goworker/lib" 5 | "log" 6 | ) 7 | 8 | type MainEvent struct { 9 | } 10 | 11 | func (*MainEvent) OnWebSocketConnect(clientId string, header []byte) { 12 | 13 | } 14 | 15 | func (*MainEvent) OnStart() { 16 | log.Println("OnStart ") 17 | } 18 | 19 | func (*MainEvent) OnConnect(clientId string) { 20 | log.Println("OnConnect ", clientId) 21 | } 22 | 23 | func (*MainEvent) OnMessage(clientId string, body []byte) { 24 | log.Println("OnMessage ", clientId, string(body)) 25 | lib.SendToAll([]byte(clientId+"中文")) 26 | } 27 | 28 | func (*MainEvent) OnClose(clientId string) { 29 | log.Println("OnClose ", clientId) 30 | } 31 | -------------------------------------------------------------------------------- /lib/worker/GatewayHandle.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "github.com/ctfang/goworker/lib" 5 | "github.com/ctfang/network" 6 | "log" 7 | ) 8 | 9 | type GatewayHandle struct { 10 | } 11 | 12 | func (g *GatewayHandle) OnConnect(message lib.GatewayMessage) { 13 | clientId := network.Bin2hex(message.LocalIp, message.LocalPort, message.ConnectionId) 14 | lib.BussinessEvent.OnConnect(clientId) 15 | } 16 | 17 | func (*GatewayHandle) OnMessage(message lib.GatewayMessage) { 18 | clientId := network.Bin2hex(message.LocalIp, message.LocalPort, message.ConnectionId) 19 | lib.BussinessEvent.OnMessage(clientId, message.Body) 20 | } 21 | 22 | func (*GatewayHandle) OnClose(message lib.GatewayMessage) { 23 | clientId := network.Bin2hex(message.LocalIp, message.LocalPort, message.ConnectionId) 24 | lib.BussinessEvent.OnClose(clientId) 25 | } 26 | 27 | func (*GatewayHandle) onWebsocketConnect(message lib.GatewayMessage) { 28 | clientId := network.Bin2hex(message.LocalIp, message.LocalPort, message.ConnectionId) 29 | lib.BussinessEvent.OnWebSocketConnect(clientId,message.Body) 30 | } 31 | 32 | func (*GatewayHandle) OnTodo(message lib.GatewayMessage) { 33 | log.Println("todo ",message) 34 | } -------------------------------------------------------------------------------- /console/Worker.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import ( 4 | "github.com/ctfang/command" 5 | "github.com/ctfang/goworker/apps" 6 | "github.com/ctfang/goworker/lib" 7 | "github.com/ctfang/goworker/lib/worker" 8 | "github.com/ctfang/network" 9 | "time" 10 | ) 11 | 12 | type Worker struct { 13 | } 14 | 15 | func (Worker) Configure() command.Configure { 16 | return command.Configure{ 17 | Name: "worker", 18 | Description: "业务worker进程", 19 | Input: command.Argument{ 20 | Argument: []command.ArgParam{ 21 | {Name: "runType", Description: "执行操作:start、stop、status"}, 22 | }, 23 | Option: []command.ArgParam{ 24 | {Name: "register", Default: "127.0.0.1:1238", Description: "注册中心"}, 25 | {Name: "secret", Default: "", Description: "通讯秘钥"}, 26 | }, 27 | }, 28 | } 29 | } 30 | 31 | func (Worker) Execute(input command.Input) { 32 | lib.Config.SetInput(input) 33 | lib.BussinessEvent = &apps.MainEvent{} 34 | 35 | // 连接到注册中心 36 | register := network.NewClient(lib.Config.Register.Origin) 37 | register.SetEvent(worker.NewRegisterEvent()) 38 | register.ListenAndServe() 39 | 40 | // 断线重连 41 | for { 42 | ticker := time.NewTicker(time.Second * 2) 43 | select { 44 | case <-ticker.C: 45 | register.ListenAndServe() 46 | } 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/ctfang/command v0.0.0-20190327092056-27958f50a31c h1:mCNCOn6DSwHxtoxla5QxAMZ7p/2UIniZHQM7mvaUeFI= 2 | github.com/ctfang/command v0.0.0-20190327092056-27958f50a31c/go.mod h1:iWJcUCwZReswQ7T5IaRE6ZvGzZ/m9v53Z1na20JttV8= 3 | github.com/ctfang/network v0.0.0-20190604113635-31985f3d312d h1:z9AL9UQknGJhOf2ccGTFa2LD2uAKGzQabClsairrTNA= 4 | github.com/ctfang/network v0.0.0-20190604113635-31985f3d312d/go.mod h1:T8Pco7U5qsYFXByUz1wkizHyPt3w6UxRToVKn6oShEE= 5 | github.com/ctfang/network v0.0.0-20190611093222-38944ae190b1 h1:O+932qUQXQgiIBZJFdBPXCV17k0jHcL+o2bP0IduwYA= 6 | github.com/ctfang/network v0.0.0-20190611093222-38944ae190b1/go.mod h1:T8Pco7U5qsYFXByUz1wkizHyPt3w6UxRToVKn6oShEE= 7 | github.com/ctfang/network v0.0.0-20190611114547-09c3330fa64f h1:3BQL1JKGYtE7LJeCMez+jAB9ZXlNc9C9CHXFRi7JgaY= 8 | github.com/ctfang/network v0.0.0-20190611114547-09c3330fa64f/go.mod h1:T8Pco7U5qsYFXByUz1wkizHyPt3w6UxRToVKn6oShEE= 9 | github.com/ctfang/network v0.0.0-20190619120328-6dbb209f2d1f h1:BebY2JiOW1tGbDUeYfWidjyDPmRfeCWwLenp1j5YyGs= 10 | github.com/ctfang/network v0.0.0-20190619120328-6dbb209f2d1f/go.mod h1:T8Pco7U5qsYFXByUz1wkizHyPt3w6UxRToVKn6oShEE= 11 | github.com/techleeone/gophp v0.1.0 h1:egZLeqwIBm9lnZ3ZkRLIf1nKHFFr/89aH9lvMCClE9o= 12 | github.com/techleeone/gophp v0.1.0/go.mod h1:vFf38I92ZchWPK9yrH/qPs/SL7M4beCwkxfWcvupEBU= 13 | -------------------------------------------------------------------------------- /lib/config.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "github.com/ctfang/command" 5 | "github.com/ctfang/network" 6 | ) 7 | 8 | var BussinessEvent LogicEvent 9 | 10 | var Config = config{} 11 | 12 | type config struct { 13 | Gateway *network.Url// 网关 14 | Home *network.Url// 本地地址 15 | Worker *network.Url// 业务处理(内部通讯)地址 16 | Register *network.Url// 注册中心 17 | SecretKey string 18 | } 19 | 20 | func (self *config) SetInput(input command.Input) { 21 | if self.Home == nil { 22 | home := input.GetOption("LanIp") 23 | if home != "" { 24 | self.Home = network.NewUrl("pack://" + home) 25 | } else { 26 | home := input.GetOption("worker") 27 | if home!="" { 28 | self.Home = network.NewUrl("pack://" + home) 29 | } 30 | } 31 | } 32 | if self.Register == nil { 33 | register := input.GetOption("register") 34 | if register!="" { 35 | self.Register = network.NewUrl("text://" + register) 36 | } 37 | } 38 | if self.Gateway == nil { 39 | Gateway := input.GetOption("gateway") 40 | if Gateway!="" { 41 | self.Gateway = network.NewUrl("ws://" + Gateway) 42 | } 43 | } 44 | if self.Worker == nil { 45 | Worker := input.GetOption("worker") 46 | if Worker!="" { 47 | self.Worker = network.NewUrl("pack://" + Worker) 48 | } 49 | } 50 | if self.SecretKey == "" { 51 | self.SecretKey = input.GetOption("secret") 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/gateway/RegisterEvent.go: -------------------------------------------------------------------------------- 1 | package gateway 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/ctfang/goworker/lib" 6 | "github.com/ctfang/network" 7 | "log" 8 | "time" 9 | ) 10 | 11 | type RegisterMessage struct { 12 | Event string `json:"event"` 13 | Address string `json:"address"` 14 | SecretKey string `json:"secret_key"` 15 | } 16 | 17 | type RegisterEvent struct { 18 | retry int16 19 | listen network.ListenTcp 20 | } 21 | 22 | // @error 23 | func (r *RegisterEvent) OnError(listen network.ListenTcp, err error) { 24 | r.retry++ 25 | log.Println("注册中心连接失败,2秒后重试", r.retry) 26 | ticker := time.NewTicker(time.Second * 2) 27 | select { 28 | case <-ticker.C: 29 | listen.ListenAndServe() 30 | break 31 | } 32 | } 33 | 34 | func (r *RegisterEvent) OnStart(listen network.ListenTcp) { 35 | log.Println("connect the register to: ", listen.Url().Origin) 36 | r.listen = listen 37 | } 38 | 39 | func (*RegisterEvent) OnConnect(c network.Connect) { 40 | // 发送内部通讯地址到注册中心 41 | conData := RegisterMessage{ 42 | Event: "gateway_connect", 43 | Address: lib.Config.Home.Host, 44 | SecretKey: lib.Config.SecretKey, 45 | } 46 | byteStr, _ := json.Marshal(conData) 47 | go c.SendByte(byteStr) 48 | } 49 | 50 | func (*RegisterEvent) OnMessage(c network.Connect, message []byte) { 51 | log.Println("gateway 收到注册中心的信息 ", string(message)) 52 | } 53 | 54 | func (r *RegisterEvent) OnClose(c network.Connect) { 55 | // 注册中心 关闭,定时检查 56 | log.Print("注册中心断开连接,2秒后重连 ", r.retry) 57 | ticker := time.NewTicker(time.Second * 2) 58 | select { 59 | case <-ticker.C: 60 | r.listen.ListenAndServe() 61 | } 62 | } 63 | 64 | // 连接注册中心 65 | func NewRegisterEvent() network.Event { 66 | return &RegisterEvent{} 67 | } 68 | -------------------------------------------------------------------------------- /console/Register.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import ( 4 | "fmt" 5 | "github.com/ctfang/command" 6 | "github.com/ctfang/goworker/lib" 7 | "github.com/ctfang/goworker/lib/register" 8 | "github.com/ctfang/network" 9 | "log" 10 | "os" 11 | ) 12 | 13 | type Register struct { 14 | Name string 15 | } 16 | 17 | func (self *Register) Configure() command.Configure { 18 | self.Name = "register" 19 | return command.Configure{ 20 | Name: self.Name, 21 | Description: "注册中心", 22 | Input: command.Argument{ 23 | Argument: []command.ArgParam{ 24 | {Name: "runType", Description: "执行操作:start、stop、status"}, 25 | }, 26 | Option: []command.ArgParam{ 27 | {Name: "register", Description: "手动设置地址"}, 28 | {Name: "secret", Default: "", Description: "通讯秘钥"}, 29 | }, 30 | }, 31 | } 32 | } 33 | 34 | func (self *Register) Execute(input command.Input) { 35 | switch input.GetArgument("runType") { 36 | case "start": 37 | self.start(input) 38 | case "stop": 39 | self.stop(input) 40 | case "status": 41 | self.status(input) 42 | } 43 | } 44 | 45 | func (self *Register) start(input command.Input) { 46 | if input.IsDaemon() { 47 | logFile, _ := os.OpenFile("register.log", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666) 48 | log.SetOutput(logFile) 49 | } 50 | command.SavePidToFile(self.Name) 51 | command.ListenStopSignal(func(sig os.Signal) { 52 | command.DeleteSavePidToFile(self.Name) 53 | os.Exit(0) 54 | }) 55 | 56 | lib.Config.SetInput(input) 57 | 58 | server := network.NewServer(lib.Config.Register.Origin) 59 | server.SetEvent(register.NewRegisterEvent()) 60 | server.ListenAndServe() 61 | } 62 | 63 | func (self *Register) status(input command.Input) { 64 | log.Println("未做") 65 | } 66 | 67 | func (self *Register) stop(input command.Input) { 68 | err := command.StopSignal(self.Name) 69 | if err != nil { 70 | fmt.Println("停止失败") 71 | } 72 | fmt.Println("停止成功") 73 | } 74 | 75 | -------------------------------------------------------------------------------- /lib/Gateway.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "github.com/ctfang/network" 5 | "strconv" 6 | ) 7 | 8 | var GatewayList = &gatewayList{ 9 | GatewayCons: map[string]network.Connect{}, 10 | } 11 | 12 | var emptyGatewayMessage = GatewayMessage{ 13 | PackageLen: 0, 14 | Cmd: 0, 15 | LocalIp: 0, 16 | LocalPort: 0, 17 | ClientIp: 0, 18 | ClientPort: 0, 19 | ConnectionId: 0, 20 | Flag: 1, 21 | GatewayPort: 0, 22 | ExtLen: 0, 23 | ExtData: "", 24 | Body: nil, 25 | } 26 | 27 | type gatewayList struct { 28 | // [ip:port]con 29 | GatewayCons map[string]network.Connect 30 | } 31 | 32 | func (self *gatewayList) SendToGateway(address string,msg GatewayMessage) { 33 | con,ok := self.GatewayCons[address] 34 | if ok { 35 | msgByte := GatewayMessageToByte(msg) 36 | con.SendByte(msgByte) 37 | } 38 | } 39 | func (self *gatewayList) SendToAllGateway(msg GatewayMessage) { 40 | msgByte := GatewayMessageToByte(msg) 41 | for _,con := range self.GatewayCons { 42 | con.SendByte(msgByte) 43 | } 44 | } 45 | 46 | type gateway struct{} 47 | 48 | func SendToAll(body []byte) { 49 | msg := emptyGatewayMessage 50 | msg.PackageLen = 28 + uint32(len(body)) 51 | msg.Cmd = CMD_SEND_TO_ALL 52 | msg.Body = body 53 | GatewayList.SendToAllGateway(msg) 54 | } 55 | 56 | // 向客户端client_id发送数据 57 | // 发给用户网关 58 | func SendToClient(clientId string, body []byte) { 59 | ip, port, id := network.DecodeBin2hex(clientId) 60 | msg := emptyGatewayMessage 61 | msg.PackageLen = 28 + uint32(len(body)) 62 | msg.Cmd = CMD_SEND_TO_ONE 63 | msg.ConnectionId = id 64 | msg.Body = body 65 | 66 | address := network.Long2Ip(ip) + ":" + strconv.Itoa(int(port)) 67 | GatewayList.SendToGateway(address,msg) 68 | } 69 | 70 | // 断开与client_id对应的客户端的连接 71 | func CloseClient(clientId string) { 72 | 73 | } 74 | 75 | // 判断$client_id是否还在线 76 | func IsOnline(clientId string) bool { 77 | return false 78 | } 79 | -------------------------------------------------------------------------------- /console/Gateway.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import ( 4 | "fmt" 5 | "github.com/ctfang/command" 6 | "github.com/ctfang/goworker/lib" 7 | "github.com/ctfang/goworker/lib/gateway" 8 | "github.com/ctfang/network" 9 | "log" 10 | ) 11 | 12 | type Gateway struct { 13 | Name string 14 | } 15 | 16 | func (self *Gateway) Configure() command.Configure { 17 | self.Name = "gateway" 18 | return command.Configure{ 19 | Name: self.Name, 20 | Description: "网关进程gateway", 21 | Input: command.Argument{ 22 | Argument: []command.ArgParam{ 23 | {Name: "runType", Description: "执行操作:start、stop、status"}, 24 | }, 25 | Option: []command.ArgParam{ 26 | {Name: "gateway", Default: "127.0.0.1:8080", Description: "网关地址websocket"}, 27 | {Name: "register", Default: "127.0.0.1:1238", Description: "注册中心"}, 28 | {Name: "worker", Default: "127.0.0.1:4000", Description: "内部通讯地址"}, 29 | {Name: "secret", Default: "", Description: "通讯秘钥"}, 30 | }, 31 | }, 32 | } 33 | } 34 | 35 | func (self *Gateway) Execute(input command.Input) { 36 | switch input.GetArgument("runType") { 37 | case "start": 38 | self.start(input) 39 | case "stop": 40 | self.stop(input) 41 | case "status": 42 | self.status(input) 43 | } 44 | } 45 | 46 | func (self *Gateway) start(input command.Input) { 47 | lib.Config.SetInput(input) 48 | 49 | // 启动一个内部通讯tcp server 50 | worker := network.NewServer(lib.Config.Worker.Origin) 51 | worker.SetEvent(gateway.NewWorkerEvent()) 52 | go worker.ListenAndServe() 53 | 54 | // 连接到注册中心 55 | register := network.NewClient(lib.Config.Register.Origin) 56 | register.SetEvent(gateway.NewRegisterEvent()) 57 | go register.ListenAndServe() 58 | 59 | // 启动对客户端的websocket连接 60 | // network.WebsocketMessageType = network.BinaryMessage 61 | server := network.NewServer(lib.Config.Gateway.Origin) 62 | server.SetEvent(gateway.NewWebSocketEvent()) 63 | server.ListenAndServe() 64 | } 65 | 66 | func (self *Gateway) status(input command.Input) { 67 | log.Println("未做") 68 | } 69 | 70 | func (self *Gateway) stop(input command.Input) { 71 | err := command.StopSignal(self.Name) 72 | if err != nil { 73 | fmt.Println("停止失败") 74 | } 75 | fmt.Println("停止成功") 76 | } 77 | -------------------------------------------------------------------------------- /lib/worker/RegisterEvent.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/ctfang/goworker/lib" 6 | "github.com/ctfang/network" 7 | "log" 8 | ) 9 | 10 | type RegisterEvent struct { 11 | listen network.ListenTcp 12 | } 13 | 14 | type WorkerConnect struct { 15 | Event string `json:"event"` 16 | SecretKey string `json:"secret_key"` 17 | } 18 | 19 | type BroadcastAddresses struct { 20 | Event string `json:"event"` 21 | Addresses []string `json:"addresses"` 22 | } 23 | 24 | func (r *RegisterEvent) OnStart(listen network.ListenTcp) { 25 | log.Println("connect the register to: ", listen.Url().Origin) 26 | r.listen = listen 27 | } 28 | 29 | func (*RegisterEvent) OnConnect(c network.Connect) { 30 | conData := WorkerConnect{ 31 | Event: "worker_connect", 32 | SecretKey: lib.Config.SecretKey, 33 | } 34 | byteStr, _ := json.Marshal(conData) 35 | go c.SendByte(byteStr) 36 | } 37 | 38 | func (r *RegisterEvent) OnMessage(c network.Connect, message []byte) { 39 | strMsg := string(message) 40 | msgBA := BroadcastAddresses{} 41 | err := json.Unmarshal([]byte(strMsg), &msgBA) 42 | if err != nil { 43 | return 44 | } 45 | switch msgBA.Event { 46 | case "broadcast_addresses": 47 | for _, addr := range msgBA.Addresses { 48 | if _, ok := lib.GatewayList.GatewayCons[addr]; !ok { 49 | lib.GatewayList.GatewayCons[addr] = nil 50 | } 51 | } 52 | r.checkGatewayConnections() 53 | default: 54 | log.Println("不认识的事件", msgBA) 55 | } 56 | } 57 | 58 | func (*RegisterEvent) OnClose(c network.Connect) { 59 | 60 | } 61 | 62 | func (*RegisterEvent) OnError(listen network.ListenTcp, err error) { 63 | 64 | } 65 | 66 | func (r *RegisterEvent) checkGatewayConnections() { 67 | for addr, con := range lib.GatewayList.GatewayCons { 68 | if con == nil { 69 | address := "pack://"+addr 70 | worker := network.NewClient(address) 71 | worker.SetEvent(NewGatewayEvent(r, address)) 72 | go worker.ListenAndServe() 73 | } 74 | } 75 | } 76 | 77 | /* 78 | 连接成功 or 失败 79 | */ 80 | func (r *RegisterEvent) UpdateGatewayConnections(addr string, con network.Connect) { 81 | if con != nil { 82 | lib.GatewayList.GatewayCons[addr] = con 83 | } else { 84 | delete(lib.GatewayList.GatewayCons, addr) 85 | } 86 | } 87 | 88 | /* 89 | 连接注册中心 90 | */ 91 | func NewRegisterEvent() network.Event { 92 | return &RegisterEvent{} 93 | } 94 | -------------------------------------------------------------------------------- /lib/gateway/Router.go: -------------------------------------------------------------------------------- 1 | package gateway 2 | 3 | import ( 4 | "errors" 5 | "github.com/ctfang/network" 6 | "sync" 7 | ) 8 | 9 | type WorkerRouter struct { 10 | lock *sync.RWMutex 11 | // worker ConnectionId 映射 worker 12 | workers map[uint32]network.Connect 13 | // client ConnectionId 映射 client 14 | Clients map[uint32]network.Connect 15 | // client ConnectionId 映射 worker ,记录已经通讯过的通道 client =》 worker 16 | clientList map[uint32]network.Connect 17 | } 18 | 19 | var Router = &WorkerRouter{ 20 | lock: &sync.RWMutex{}, 21 | workers: map[uint32]network.Connect{}, 22 | Clients: map[uint32]network.Connect{}, 23 | clientList: map[uint32]network.Connect{}, 24 | } 25 | 26 | func (w *WorkerRouter) GetWorker(c network.Connect) (network.Connect, error) { 27 | w.lock.Lock() 28 | defer w.lock.Unlock() 29 | cid := c.Id() 30 | if worker, ok := w.clientList[cid]; ok { 31 | // 已经通信过的通道 32 | return worker, nil 33 | } else { 34 | // 随机分配一个worker 35 | for _, worker := range w.workers { 36 | w.clientList[cid] = worker 37 | return worker, nil 38 | } 39 | } 40 | // 不存在 41 | return nil, errors.New("找不到worker") 42 | } 43 | 44 | func (w *WorkerRouter) AddedWorker(worker network.Connect) { 45 | w.lock.Lock() 46 | defer w.lock.Unlock() 47 | w.workers[worker.Id()] = worker 48 | } 49 | 50 | /** 51 | worker 断开 52 | */ 53 | func (w *WorkerRouter) DeleteWorker(worker network.Connect) { 54 | w.lock.Lock() 55 | defer w.lock.Unlock() 56 | cid := worker.Id() 57 | delete(w.workers, cid) 58 | for clientId, worker := range w.clientList { 59 | if cid == worker.Id() { 60 | delete(w.clientList, clientId) 61 | } 62 | } 63 | } 64 | 65 | /** 66 | 新增客户端,并且建立路由映射 67 | */ 68 | func (w *WorkerRouter) AddedClient(c network.Connect) { 69 | w.lock.Lock() 70 | defer w.lock.Unlock() 71 | ConnectionId := c.Id() 72 | if _, ok := w.Clients[ConnectionId]; ok { 73 | w.DeleteClient(ConnectionId) 74 | } 75 | 76 | w.Clients[ConnectionId] = c 77 | } 78 | 79 | func (w *WorkerRouter) GetClient(ConnectionId uint32) (network.Connect, error) { 80 | w.lock.Lock() 81 | defer w.lock.Unlock() 82 | c, ok := w.Clients[ConnectionId] 83 | if ok { 84 | return c, nil 85 | } 86 | 87 | return nil, errors.New("客户端不存在") 88 | } 89 | 90 | /** 91 | 删除 客户端 92 | */ 93 | func (w *WorkerRouter) DeleteClient(ConnectionId uint32) { 94 | w.lock.Lock() 95 | defer w.lock.Unlock() 96 | delete(w.clientList, ConnectionId) 97 | delete(w.Clients, ConnectionId) 98 | } 99 | -------------------------------------------------------------------------------- /lib/gateway/WorkerEvent.go: -------------------------------------------------------------------------------- 1 | package gateway 2 | 3 | import ( 4 | "github.com/ctfang/goworker/lib" 5 | "github.com/ctfang/network" 6 | "log" 7 | ) 8 | 9 | /* 10 | 接受worker发上来的数据 11 | */ 12 | type WorkerEvent struct { 13 | HandleFunc map[uint8]func(c network.Connect, message lib.GatewayMessage) 14 | } 15 | 16 | func (*WorkerEvent) OnError(listen network.ListenTcp, err error) { 17 | 18 | } 19 | 20 | func (w *WorkerEvent) OnStart(listen network.ListenTcp) { 21 | log.Println("worker server listening at: ", listen.Url().Origin) 22 | 23 | if w.HandleFunc == nil { 24 | w.HandleFunc = map[uint8]func(c network.Connect, message lib.GatewayMessage){} 25 | WorkerHandle := NewWorkerHandle() 26 | 27 | w.HandleFunc[lib.CMD_WORKER_CONNECT] = WorkerHandle.OnWorkerConnect 28 | w.HandleFunc[lib.CMD_GATEWAY_CLIENT_CONNECT] = WorkerHandle.OnGatewayClientConnect 29 | w.HandleFunc[lib.CMD_SEND_TO_ONE] = WorkerHandle.OnSendToOne 30 | w.HandleFunc[lib.CMD_KICK] = WorkerHandle.OnSendToOne 31 | w.HandleFunc[lib.CMD_DESTROY] = WorkerHandle.OnDestroy 32 | w.HandleFunc[lib.CMD_SEND_TO_ALL] = WorkerHandle.OnSendToAll 33 | w.HandleFunc[lib.CMD_SELECT] = WorkerHandle.OnSelect 34 | 35 | w.HandleFunc[lib.CMD_GET_GROUP_ID_LIST] = WorkerHandle.OnTodo 36 | w.HandleFunc[lib.CMD_SET_SESSION] = WorkerHandle.OnSetSession 37 | w.HandleFunc[lib.CMD_UPDATE_SESSION] = WorkerHandle.OnTodo 38 | w.HandleFunc[lib.CMD_GET_SESSION_BY_CLIENT_ID] = WorkerHandle.OnGetSessionByClientId 39 | w.HandleFunc[lib.CMD_GET_ALL_CLIENT_SESSIONS] = WorkerHandle.OnTodo 40 | w.HandleFunc[lib.CMD_IS_ONLINE] = WorkerHandle.OnTodo 41 | w.HandleFunc[lib.CMD_BIND_UID] = WorkerHandle.OnTodo 42 | w.HandleFunc[lib.CMD_SEND_TO_UID] = WorkerHandle.OnTodo 43 | w.HandleFunc[lib.CMD_JOIN_GROUP] = WorkerHandle.OnJoinGroup 44 | w.HandleFunc[lib.CMD_LEAVE_GROUP] = WorkerHandle.OnTodo 45 | w.HandleFunc[lib.CMD_UNGROUP] = WorkerHandle.OnTodo 46 | w.HandleFunc[lib.CMD_SEND_TO_GROUP] = WorkerHandle.OnSendToGroup 47 | w.HandleFunc[lib.CMD_GET_CLIENT_SESSIONS_BY_GROUP] = WorkerHandle.OnClientSessionsByGroup 48 | w.HandleFunc[lib.CMD_GET_CLIENT_COUNT_BY_GROUP] = WorkerHandle.OnTodo 49 | w.HandleFunc[lib.CMD_GET_CLIENT_ID_BY_UID] = WorkerHandle.OnTodo 50 | } 51 | } 52 | 53 | func (*WorkerEvent) OnConnect(c network.Connect) { 54 | 55 | } 56 | 57 | func (w *WorkerEvent) OnMessage(c network.Connect, message []byte) { 58 | msg := lib.ToGatewayMessage(message) 59 | log.Println("收到worker的数据:", string(msg.Body)) 60 | if handle, ok := w.HandleFunc[msg.Cmd]; ok { 61 | handle(c, msg) 62 | } else { 63 | log.Println("不认识的命令", msg.Cmd, c.GetCon().RemoteAddr().String()) 64 | } 65 | } 66 | 67 | func (*WorkerEvent) OnClose(c network.Connect) { 68 | c.Close() 69 | Router.DeleteWorker(c) 70 | } 71 | 72 | func NewWorkerEvent() network.Event { 73 | return &WorkerEvent{} 74 | } 75 | -------------------------------------------------------------------------------- /lib/gateway/WebSocketEvent.go: -------------------------------------------------------------------------------- 1 | package gateway 2 | 3 | import ( 4 | "github.com/ctfang/goworker/lib" 5 | "github.com/ctfang/network" 6 | "log" 7 | "unicode/utf8" 8 | ) 9 | 10 | /** 11 | 客户端信息 12 | */ 13 | type GatewayHeader struct { 14 | // 内部通讯地址 , 对应本机地址 15 | LocalIp uint32 16 | LocalPort uint16 17 | ClientIp uint32 18 | ClientPort uint16 19 | GatewayPort uint16 20 | ConnectionId uint32 21 | flag uint8 22 | } 23 | 24 | type WebSocketEvent struct { 25 | // 内部通讯地址 26 | WorkerServerIp string 27 | WorkerServerPort uint16 28 | } 29 | 30 | func (ws *WebSocketEvent) OnError(listen network.ListenTcp, err error) { 31 | 32 | } 33 | 34 | func (ws *WebSocketEvent) OnStart(listen network.ListenTcp) { 35 | ws.WorkerServerIp = lib.Config.Worker.Ip 36 | ws.WorkerServerPort = lib.Config.Worker.Port 37 | 38 | log.Println("ws server listening at: ", listen.Url().Origin) 39 | } 40 | 41 | func (ws *WebSocketEvent) GetClientId(client network.Connect) string { 42 | return network.Bin2hex(network.Ip2long(ws.WorkerServerIp), ws.WorkerServerPort, client.Id()) 43 | } 44 | 45 | func (ws *WebSocketEvent) OnConnect(client network.Connect) { 46 | client.SetUid(ws.GetClientId(client)) 47 | // 添加连接池 48 | Router.AddedClient(client) 49 | 50 | ws.SendToWorker(client, lib.CMD_ON_CONNECT, []byte(""), 1, "") 51 | } 52 | 53 | // 收到websocket信息 54 | func (ws *WebSocketEvent) OnMessage(c network.Connect, message []byte) { 55 | extData := c.ExtData() 56 | if extData == nil { 57 | ws.SendToWorker(c, lib.CMD_ON_MESSAGE, message, 1, "") 58 | } else { 59 | ws.SendToWorker(c, lib.CMD_ON_MESSAGE, message, 1, string(extData.([]byte))) 60 | } 61 | } 62 | 63 | func (ws *WebSocketEvent) OnClose(c network.Connect) { 64 | ws.SendToWorker(c, lib.CMD_ON_CLOSE, []byte(""), 1, "") 65 | Router.DeleteClient(c.Id()) 66 | } 67 | 68 | // 发送信息的worker 69 | func (ws *WebSocketEvent) SendToWorker(client network.Connect, cmd uint8, body []byte, flag uint8, ExtData string) { 70 | msg := lib.GatewayMessage{ 71 | PackageLen: 28 + uint32(len(body)), 72 | Cmd: cmd, 73 | LocalIp: network.Ip2long(ws.WorkerServerIp), 74 | LocalPort: ws.WorkerServerPort, 75 | ClientIp: client.GetIp(), 76 | ClientPort: client.GetPort(), 77 | ConnectionId: client.Id(), 78 | Flag: flag, 79 | GatewayPort: lib.Config.Gateway.Port, 80 | ExtLen: uint32(utf8.RuneCountInString(ExtData)), 81 | ExtData: ExtData, 82 | Body: body, 83 | } 84 | 85 | worker, err := Router.GetWorker(client) 86 | if err != nil { 87 | // worker 找不到 获取连接 88 | log.Println("主动断开客户端连接 err:", err) 89 | client.Close() 90 | Router.DeleteClient(client.Id()) 91 | return 92 | } 93 | log.Println("发信息给worker", string(msg.Body)) 94 | worker.SendByte(lib.GatewayMessageToByte(msg)) 95 | } 96 | 97 | func NewWebSocketEvent() network.Event { 98 | return &WebSocketEvent{} 99 | } 100 | -------------------------------------------------------------------------------- /lib/worker/GatewayEvent.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/ctfang/goworker/lib" 6 | "github.com/ctfang/network" 7 | "log" 8 | "strconv" 9 | ) 10 | 11 | type WorkerKey struct { 12 | Worker string `json:"worker_key"` 13 | Secret string `json:"secret_key"` 14 | } 15 | 16 | // 接受 lib 发来的数据 17 | type GatewayEvent struct { 18 | registerEvent *RegisterEvent 19 | gatewayAddresses *network.Url 20 | 21 | HandleFunc map[uint8]func(message lib.GatewayMessage) 22 | } 23 | 24 | func (g *GatewayEvent) OnStart(listen network.ListenTcp) { 25 | if g.HandleFunc == nil { 26 | handle := GatewayHandle{} 27 | g.HandleFunc = map[uint8]func(message lib.GatewayMessage){} 28 | 29 | g.HandleFunc[lib.CMD_ON_CONNECT] = handle.OnConnect 30 | g.HandleFunc[lib.CMD_ON_MESSAGE] = handle.OnMessage 31 | g.HandleFunc[lib.CMD_ON_CLOSE] = handle.OnClose 32 | g.HandleFunc[lib.CMD_ON_WEBSOCKET_CONNECT] = handle.onWebsocketConnect 33 | } 34 | } 35 | 36 | // gateway 连接 37 | func (g *GatewayEvent) OnConnect(gateway network.Connect) { 38 | g.registerEvent.UpdateGatewayConnections(g.GetGatewayAddress(), gateway) 39 | msg := WorkerKey{ 40 | Worker: "BussinessWorker:" + strconv.Itoa(int(gateway.Id())), 41 | Secret: lib.Config.SecretKey, 42 | } 43 | 44 | g.SendToGateway(gateway, lib.CMD_WORKER_CONNECT, msg) 45 | } 46 | 47 | // 接受 gateway 转发来的client数据 48 | func (g *GatewayEvent) OnMessage(c network.Connect, message []byte) { 49 | msg := lib.ToGatewayMessage(message) 50 | if handle, ok := g.HandleFunc[msg.Cmd]; ok { 51 | handle(msg) 52 | } else { 53 | log.Println("GatewayEvent 不认识的命令", msg.Cmd, message) 54 | } 55 | } 56 | 57 | func (g *GatewayEvent) OnClose(connect network.Connect) { 58 | g.registerEvent.UpdateGatewayConnections(g.GetGatewayAddress(), nil) 59 | } 60 | 61 | func (g *GatewayEvent) OnError(listen network.ListenTcp, err error) { 62 | g.registerEvent.UpdateGatewayConnections(g.GetGatewayAddress(), nil) 63 | } 64 | 65 | func (g *GatewayEvent) GetGatewayAddress() string { 66 | return g.gatewayAddresses.Ip + ":" + strconv.Itoa(int(g.gatewayAddresses.Port)) 67 | } 68 | 69 | // 发送数据到对应的客户端 70 | func (g *GatewayEvent) SendToClient(uid string, cmd uint8, msg interface{}) { 71 | 72 | } 73 | 74 | // 发送数据到对应的 gateway 进程 75 | func (g *GatewayEvent) SendToGateway(gatewayConnect network.Connect, cmd uint8, msg interface{}) { 76 | var body []byte 77 | switch msg.(type) { 78 | case []byte: 79 | body = msg.([]byte) 80 | case string: 81 | body = []byte(msg.(string)) 82 | default: 83 | // 未知类型,直接转json 84 | body, _ = json.Marshal(msg) 85 | } 86 | 87 | gm := lib.GatewayMessage{ 88 | PackageLen: 28 + uint32(len(body)), 89 | Cmd: cmd, 90 | LocalIp: 0, 91 | LocalPort: 0, 92 | ClientIp: gatewayConnect.GetIp(), 93 | ClientPort: gatewayConnect.GetPort(), 94 | ConnectionId: gatewayConnect.Id(), 95 | Flag: 1, 96 | GatewayPort: g.gatewayAddresses.Port, 97 | ExtLen: 0, 98 | ExtData: "", 99 | Body: body, 100 | } 101 | 102 | gatewayConnect.Send(lib.GatewayMessageToByte(gm)) 103 | } 104 | 105 | func NewGatewayEvent(r *RegisterEvent, address string) network.Event { 106 | return &GatewayEvent{ 107 | registerEvent: r, 108 | gatewayAddresses: network.NewUrl(address), 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /lib/register/RegisterEvent.go: -------------------------------------------------------------------------------- 1 | package register 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/ctfang/goworker/lib" 7 | "github.com/ctfang/network" 8 | "log" 9 | ) 10 | 11 | type RegisterMessage struct { 12 | Event string `json:"event"` 13 | Address string `json:"address"` 14 | SecretKey string `json:"secret_key"` 15 | } 16 | 17 | type RegisterEvent struct { 18 | // ID 地址保存 19 | gatewayConnections map[uint32]string 20 | workerConnections map[uint32]network.Connect 21 | } 22 | 23 | func (self *RegisterEvent) OnStart(listen network.ListenTcp) { 24 | log.Println("register server listening at: ", listen.Url().Origin) 25 | } 26 | 27 | func (*RegisterEvent) OnConnect(connect network.Connect) { 28 | 29 | } 30 | 31 | func (self *RegisterEvent) OnMessage(connect network.Connect, message []byte) { 32 | var data RegisterMessage 33 | err := json.Unmarshal(message, &data) 34 | if err != nil { 35 | fmt.Println(err) 36 | connect.Close() 37 | return 38 | } 39 | if lib.Config.SecretKey != "" { 40 | if data.SecretKey != lib.Config.SecretKey { 41 | fmt.Println("秘要不对") 42 | connect.Close() 43 | return 44 | } 45 | } 46 | switch data.Event { 47 | case "gateway_connect": 48 | self.gatewayConnect(connect, data) 49 | case "worker_connect": 50 | self.workerConnect(connect, data) 51 | case "ping": 52 | return 53 | default: 54 | fmt.Println("不认识的事件定义") 55 | connect.Close() 56 | } 57 | } 58 | 59 | func (self *RegisterEvent) OnClose(connect network.Connect) { 60 | _, hasG := self.gatewayConnections[connect.Id()] 61 | if hasG == true { 62 | delete(self.gatewayConnections, connect.Id()) 63 | self.broadcastAddresses(0) 64 | } 65 | 66 | _, hasW := self.workerConnections[connect.Id()] 67 | if hasW == true { 68 | delete(self.workerConnections, connect.Id()) 69 | } 70 | } 71 | 72 | 73 | func (*RegisterEvent) OnError(listen network.ListenTcp, err error) { 74 | log.Println("注册中心启动失败", err) 75 | } 76 | 77 | // gateway 链接 78 | func (self *RegisterEvent) gatewayConnect(c network.Connect, msg RegisterMessage) { 79 | if msg.Address == "" { 80 | println("address not found") 81 | c.Close() 82 | return 83 | } 84 | // 推入列表 85 | self.gatewayConnections[c.Id()] = msg.Address 86 | self.broadcastAddresses(0) 87 | } 88 | 89 | // worker 链接 90 | func (self *RegisterEvent) workerConnect(c network.Connect, msg RegisterMessage) { 91 | // 推入列表 92 | self.workerConnections[c.Id()] = c 93 | self.broadcastAddresses(0) 94 | } 95 | 96 | /* 97 | 向 BusinessWorker 广播 gateway 内部通讯地址 98 | 0 全部发生 99 | */ 100 | func (self *RegisterEvent) broadcastAddresses(id uint32) { 101 | type ConList struct { 102 | Event string `json:"event"` 103 | Addresses []string `json:"addresses"` 104 | } 105 | data := ConList{Event: "broadcast_addresses"} 106 | 107 | for _, address := range self.gatewayConnections { 108 | data.Addresses = append(data.Addresses, address) 109 | } 110 | 111 | jsonByte, _ := json.Marshal(data) 112 | 113 | if id != 0 { 114 | worker := self.workerConnections[id] 115 | worker.SendByte(jsonByte) 116 | return 117 | } 118 | 119 | for _, worker := range self.workerConnections { 120 | worker.SendByte(jsonByte) 121 | } 122 | } 123 | 124 | func NewRegisterEvent() network.Event { 125 | return &RegisterEvent{ 126 | gatewayConnections: make(map[uint32]string), 127 | workerConnections: make(map[uint32]network.Connect), 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /lib/GatewayProtocol.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "encoding/binary" 5 | "log" 6 | "reflect" 7 | ) 8 | 9 | // 发给worker,gateway有一个新的连接 10 | const CMD_ON_CONNECT = 1 11 | 12 | // 发给worker的,客户端有消息 13 | const CMD_ON_MESSAGE = 3 14 | 15 | // 发给worker上的关闭链接事件 16 | const CMD_ON_CLOSE = 4 17 | 18 | // 发给gateway的向单个用户发送数据 19 | const CMD_SEND_TO_ONE = 5 20 | 21 | // 发给gateway的向所有用户发送数据 22 | const CMD_SEND_TO_ALL = 6 23 | 24 | // 发给gateway的踢出用户 25 | // 1、如果有待发消息,将在发送完后立即销毁用户连接 26 | // 2、如果无待发消息,将立即销毁用户连接 27 | const CMD_KICK = 7 28 | 29 | // 发给gateway的立即销毁用户连接 30 | const CMD_DESTROY = 8 31 | 32 | // 发给gateway,通知用户session更新 33 | const CMD_UPDATE_SESSION = 9 34 | 35 | // 获取在线状态 36 | const CMD_GET_ALL_CLIENT_SESSIONS = 10 37 | 38 | // 判断是否在线 39 | const CMD_IS_ONLINE = 11 40 | 41 | // client_id绑定到uid 42 | const CMD_BIND_UID = 12 43 | 44 | // 解绑 45 | const CMD_UNBIND_UID = 13 46 | 47 | // 向uid发送数据 48 | const CMD_SEND_TO_UID = 14 49 | 50 | // 根据uid获取绑定的clientid 51 | const CMD_GET_CLIENT_ID_BY_UID = 15 52 | 53 | // 加入组 54 | const CMD_JOIN_GROUP = 20 55 | 56 | // 离开组 57 | const CMD_LEAVE_GROUP = 21 58 | 59 | // 向组成员发消息 60 | const CMD_SEND_TO_GROUP = 22 61 | 62 | // 获取组成员 63 | const CMD_GET_CLIENT_SESSIONS_BY_GROUP = 23 64 | 65 | // 获取组在线连接数 66 | const CMD_GET_CLIENT_COUNT_BY_GROUP = 24 67 | 68 | // 按照条件查找 69 | const CMD_SELECT = 25 70 | 71 | // 获取在线的群组ID 72 | const CMD_GET_GROUP_ID_LIST = 26 73 | 74 | // 取消分组 75 | const CMD_UNGROUP = 27 76 | 77 | // worker连接gateway事件 78 | const CMD_WORKER_CONNECT = 200 79 | 80 | // 心跳 81 | const CMD_PING = 201 82 | 83 | // GatewayClient连接gateway事件 84 | const CMD_GATEWAY_CLIENT_CONNECT = 202 85 | 86 | // 根据client_id获取session 87 | const CMD_GET_SESSION_BY_CLIENT_ID = 203 88 | 89 | // 发给gateway,覆盖session 90 | const CMD_SET_SESSION = 204 91 | 92 | // 当websocket握手时触发,只有websocket协议支持此命令字 93 | const CMD_ON_WEBSOCKET_CONNECT = 205 94 | 95 | // 包体是标量 96 | const FLAG_BODY_IS_SCALAR = 0x01 97 | 98 | // 通知gateway在send时不调用协议encode方法,在广播组播时提升性能 99 | const FLAG_NOT_CALL_ENCODE = 0x02 100 | 101 | // "Npack_len/Ccmd/Nlocal_ip/nlocal_port/Nclient_ip/nclient_port/Nconnection_id/Cflag/ngateway_port/Next_len" 102 | type GatewayMessage struct { 103 | PackageLen uint32 104 | Cmd uint8 105 | LocalIp uint32 106 | LocalPort uint16 107 | ClientIp uint32 108 | ClientPort uint16 109 | ConnectionId uint32 110 | Flag uint8 111 | GatewayPort uint16 112 | 113 | ExtLen uint32 114 | ExtData string 115 | Body []byte 116 | } 117 | 118 | func ToGatewayMessage(data []byte) GatewayMessage { 119 | Message := GatewayMessage{ 120 | PackageLen: uint32(len(data)), 121 | Cmd: data[0], 122 | LocalIp: uint32(binary.BigEndian.Uint32(data[1:5])), 123 | LocalPort: uint16(binary.BigEndian.Uint16(data[5:7])), 124 | ClientIp: uint32(binary.BigEndian.Uint32(data[7:11])), 125 | ClientPort: uint16(binary.BigEndian.Uint16(data[11:13])), 126 | ConnectionId: uint32(binary.BigEndian.Uint32(data[13:17])), 127 | Flag: data[17], 128 | GatewayPort: uint16(binary.BigEndian.Uint16(data[18:20])), 129 | ExtLen: uint32(binary.BigEndian.Uint32(data[20:24])), 130 | } 131 | Message.ExtData = string(data[24 : 24+Message.ExtLen]) 132 | Message.Body = data[(24 + Message.ExtLen):(Message.PackageLen)] 133 | Message.PackageLen += 4 134 | return Message 135 | } 136 | 137 | func GatewayMessageToByte(msg GatewayMessage) []byte { 138 | var msgByte []byte 139 | 140 | value := reflect.ValueOf(msg) 141 | for i := 0; i < value.NumField(); i++ { 142 | field := value.Field(i) 143 | switch field.Kind() { 144 | case reflect.String: 145 | var bufStr []byte 146 | bufStr = []byte(field.String()) 147 | msgByte = append(msgByte, bufStr...) 148 | case reflect.Uint8: 149 | msgByte = append(msgByte, uint8(field.Uint())) 150 | case reflect.Uint16: 151 | var buf16 = make([]byte, 2) 152 | binary.BigEndian.PutUint16(buf16, uint16(field.Uint())) 153 | msgByte = append(msgByte, buf16...) 154 | case reflect.Uint32: 155 | var buf32 = make([]byte, 4) 156 | binary.BigEndian.PutUint32(buf32, uint32(field.Uint())) 157 | msgByte = append(msgByte, buf32...) 158 | case reflect.Slice: 159 | msgByte = append(msgByte, field.Bytes()...) 160 | default: 161 | log.Println("GatewayProtocol 不知道的类型", field.Type(), msg) 162 | } 163 | } 164 | 165 | return msgByte[4:] 166 | } 167 | -------------------------------------------------------------------------------- /lib/gateway/WorkerHandle.go: -------------------------------------------------------------------------------- 1 | package gateway 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/ctfang/goworker/lib" 6 | "github.com/ctfang/goworker/lib/worker" 7 | "github.com/ctfang/network" 8 | Serialize "github.com/techleeone/gophp/serialize" 9 | "log" 10 | "strconv" 11 | ) 12 | 13 | // 处理worker发来的信息命令 14 | type WorkerHandle struct { 15 | // groupId=> 16 | groupConnections map[int]map[uint32]network.Connect 17 | } 18 | 19 | // 单个用户信息 20 | func (*WorkerHandle) OnSendToOne(c network.Connect, message lib.GatewayMessage) { 21 | client, err := Router.GetClient(message.ConnectionId) 22 | if err != nil { 23 | Router.DeleteClient(message.ConnectionId) 24 | return 25 | } 26 | client.Send(message.Body) 27 | } 28 | 29 | // 提出用户 30 | func (*WorkerHandle) OnKick(c network.Connect, message lib.GatewayMessage) { 31 | // todo 32 | } 33 | 34 | // 立即摧毁用户连接 35 | func (*WorkerHandle) OnDestroy(c network.Connect, message lib.GatewayMessage) { 36 | // todo 37 | } 38 | 39 | // 发给gateway的向所有用户发送数据 40 | func (*WorkerHandle) OnSendToAll(c network.Connect, message lib.GatewayMessage) { 41 | for _, client := range Router.Clients { 42 | client.Send(message.Body) 43 | } 44 | } 45 | 46 | func (*WorkerHandle) OnWorkerConnect(c network.Connect, message lib.GatewayMessage) { 47 | WorkerKey := &worker.WorkerKey{} 48 | err := json.Unmarshal(message.Body, WorkerKey) 49 | if err != nil || lib.Config.SecretKey != WorkerKey.Secret { 50 | c.Close() 51 | return 52 | } 53 | Router.AddedWorker(c) 54 | } 55 | 56 | func (*WorkerHandle) OnGatewayClientConnect(c network.Connect, message lib.GatewayMessage) { 57 | WorkerKey := &worker.WorkerKey{} 58 | err := json.Unmarshal(message.Body, WorkerKey) 59 | if err != nil || lib.Config.SecretKey != WorkerKey.Secret { 60 | c.Close() 61 | return 62 | } 63 | Router.AddedWorker(c) 64 | } 65 | 66 | // 获取组成员session 67 | func (self *WorkerHandle) OnClientSessionsByGroup(c network.Connect, message lib.GatewayMessage) { 68 | groupId, _ := strconv.Atoi(message.ExtData) 69 | if list, ok := self.groupConnections[groupId]; ok { 70 | clientArray := make(map[uint32][]byte) 71 | for clientId, client := range list { 72 | clientArray[clientId] = client.ExtData().([]byte) 73 | } 74 | buffer, _ := Serialize.Marshal(clientArray) 75 | c.SendByte(buffer) 76 | } else { 77 | buffer := "a:0:{}" 78 | c.SendString(buffer) 79 | } 80 | } 81 | 82 | // 向组成员发消息 83 | func (self *WorkerHandle) OnSendToGroup(c network.Connect, message lib.GatewayMessage) { 84 | groupList := struct { 85 | Group []int `json:"group"` 86 | Exclude []int `json:"exclude"` 87 | }{} 88 | err := json.Unmarshal([]byte(message.ExtData), &groupList) 89 | if err != nil { 90 | log.Println("向组成员发消息,格式错误,检查数据类型") 91 | return 92 | } 93 | 94 | for _, groupId := range groupList.Group { 95 | if list, ok := self.groupConnections[groupId]; ok { 96 | for _, clientConnect := range list { 97 | clientConnect.Send(message.Body) 98 | } 99 | } 100 | } 101 | } 102 | 103 | // 根据client_id获取session 104 | // const CMD_GET_SESSION_BY_CLIENT_ID = 203 105 | func (*WorkerHandle) OnGetSessionByClientId(c network.Connect, message lib.GatewayMessage) { 106 | client, err := Router.GetClient(message.ConnectionId) 107 | if err != nil { 108 | return 109 | } 110 | session := client.ExtData() 111 | if session == nil { 112 | c.SendString("N;") 113 | } else { 114 | c.SendByte(session.([]byte)) 115 | } 116 | } 117 | 118 | // 重新赋值 session 119 | func (*WorkerHandle) OnSetSession(c network.Connect, message lib.GatewayMessage) { 120 | client, err := Router.GetClient(message.ConnectionId) 121 | if err != nil { 122 | return 123 | } 124 | client.SetExtData([]byte(message.ExtData)) 125 | } 126 | 127 | // 加入组 128 | func (self *WorkerHandle) OnJoinGroup(c network.Connect, message lib.GatewayMessage) { 129 | groupId, _ := strconv.Atoi(message.ExtData) 130 | if groupId <= 0 { 131 | log.Println("join(group) group empty, group=" + message.ExtData) 132 | return 133 | } 134 | clientConnection, err := Router.GetClient(message.ConnectionId) 135 | if err != nil { 136 | return 137 | } 138 | if _, ok := self.groupConnections[groupId]; !ok { 139 | self.groupConnections[groupId] = map[uint32]network.Connect{} 140 | } 141 | self.groupConnections[groupId][message.ConnectionId] = clientConnection 142 | } 143 | 144 | // 按照条件查找 145 | func (*WorkerHandle) OnSelect(c network.Connect, message lib.GatewayMessage) { 146 | log.Println("按照条件查找") 147 | } 148 | 149 | // 按照条件查找 150 | func (*WorkerHandle) OnTodo(c network.Connect, message lib.GatewayMessage) { 151 | // todo 152 | log.Println("todo cmd= ", message.Cmd) 153 | } 154 | 155 | func NewWorkerHandle() *WorkerHandle { 156 | return &WorkerHandle{ 157 | groupConnections: map[int]map[uint32]network.Connect{}, 158 | } 159 | } 160 | --------------------------------------------------------------------------------