├── .gitignore ├── LICENSE ├── README.md ├── conf.go ├── doc └── goserver_framework.png ├── example ├── client │ └── main.go ├── gate │ └── main.go ├── msg │ ├── msg.pb.go │ └── msg.proto └── user │ └── main.go ├── go.mod ├── go.sum ├── goserver.json ├── network ├── client.go ├── conn.go ├── mgr.go ├── processor.go ├── wsconn.go └── wsserver.go ├── rpc ├── client.go ├── processor.go ├── rpc.go ├── rpcmsg │ ├── rpc.pb.go │ └── rpc.proto ├── server.go └── util.go ├── server ├── gate.go └── server.go ├── service ├── ticker.go └── worker.go └── util ├── fun.go ├── goutine.go ├── print.go ├── protobuf.go ├── reflect.go └── string.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # goserver 2 | 基于消息队列(nats)的游戏服务器框架 3 | 4 | # 架构 5 | ![framework](doc/goserver_framework.png)
6 | 分布式服务器以nats为消息交换中心,客户端发送的消息统一由gate服进行路由转发 7 | 8 | 9 | ## 1,gate服 10 | 和客户端通信使用websocket,仅支持protobuf,数据结构:
11 | 12 | ------------------------- 13 | | id | protobuf message | 14 | ------------------------- 15 | id是消息名的Hash值,用于标记消息名,反解析数据
16 | 因为websocket协议已经支持iframe分帧处理,不需要处理粘包,故包结构中无需包长度字段
17 | 18 | ## 2,多服rpc通信 19 | 使用nats(消息队列)构建服务器间通信,支持send,request,call请求 20 | 21 | 更多技术细节: https://www.jianshu.com/p/74904ace2349 22 | 23 | ## 配置 24 | gate服: server.NewGate(serverId,listenAddr,goserver.Config{Nats: natsAddr})
25 | 其它服: server.NewServer(serverId,goserver.Config{Nats: natsAddr})
26 | 27 | 其中,每个服务器有个唯一serverId即可,natsAddr就是nats的地址,gate服多一个listenAddr代表监听端口
28 | # 示例 29 | 1,启动消息队列服务(https://github.com/nats-io/nats-streaming-server)
30 | 2,见example目录,依次启动user/main.go,gate/main.go,client/main.go
31 | 先启动user服,再启动gate服,gate向user服发送rpc消息,通知型:pb.ReqSend{},请求回应型:pb.ReqRequest{}
32 | 最后启动client,会模拟发送客户端消息pb.ReqHello,此消息会被gate转发到user服,模拟路由消息情况 33 | 34 | # 基于goserver的游戏服务器 35 | avatar-fight-server https://github.com/0990/avatar-fight-server 36 | 37 | 38 | -------------------------------------------------------------------------------- /conf.go: -------------------------------------------------------------------------------- 1 | package goserver 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/nats-io/nats.go" 6 | "github.com/sirupsen/logrus" 7 | "os" 8 | ) 9 | 10 | type Config struct { 11 | Nats string `json:"nats"` 12 | } 13 | 14 | func ReadConfig(filename string) (*Config, error) { 15 | natsUrl := os.Getenv("GOSERVER_NATS_URL") 16 | if natsUrl != "" { 17 | logrus.WithField("natsUrl", natsUrl).Info("goserver") 18 | return &Config{Nats: natsUrl}, nil 19 | } 20 | if filename == "" { 21 | return &Config{Nats: nats.DefaultURL}, nil 22 | } 23 | 24 | file, err := os.Open(filename) 25 | if err != nil { 26 | return nil, err 27 | } 28 | 29 | defer file.Close() 30 | 31 | p := &Config{} 32 | err = json.NewDecoder(file).Decode(p) 33 | if err != nil { 34 | return nil, err 35 | } 36 | return p, nil 37 | } 38 | 39 | func IsExists(path string) bool { 40 | _, err := os.Stat(path) //os.Stat获取文件信息 41 | if err != nil { 42 | if os.IsExist(err) { 43 | return true 44 | } 45 | return false 46 | } 47 | return true 48 | } 49 | -------------------------------------------------------------------------------- /doc/goserver_framework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0990/goserver/7771890b8d2386a17ea789dfaf7a5d966c8538ea/doc/goserver_framework.png -------------------------------------------------------------------------------- /example/client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | pb "github.com/0990/goserver/example/msg" 7 | "github.com/0990/goserver/network" 8 | "github.com/gorilla/websocket" 9 | "github.com/sirupsen/logrus" 10 | "net/url" 11 | "os" 12 | "os/signal" 13 | "time" 14 | ) 15 | 16 | var addr = flag.String("addr", "localhost:8080", "http service address") 17 | var processor = network.NewProcessor() 18 | 19 | func main() { 20 | flag.Parse() 21 | 22 | interrupt := make(chan os.Signal, 1) 23 | signal.Notify(interrupt, os.Interrupt) 24 | 25 | u := url.URL{Scheme: "ws", Host: *addr, Path: ""} 26 | logrus.Infoln("connecting to ", u.String()) 27 | 28 | c, _, err := websocket.DefaultDialer.Dial(u.String(), nil) 29 | if err != nil { 30 | logrus.WithError(err).Fatal("dial") 31 | } 32 | defer c.Close() 33 | 34 | done := make(chan struct{}) 35 | 36 | go func() { 37 | defer close(done) 38 | for { 39 | _, message, err := c.ReadMessage() 40 | if err != nil { 41 | logrus.WithError(err).Error("read") 42 | return 43 | } 44 | logrus.WithField("message", message).Debug("recv") 45 | } 46 | }() 47 | 48 | ticker := time.NewTicker(time.Second * 2) 49 | defer ticker.Stop() 50 | 51 | for { 52 | select { 53 | case <-done: 54 | return 55 | case <-ticker.C: 56 | req := &pb.ReqHello{ 57 | Name: "xujialong", 58 | } 59 | data, _ := processor.Marshal(req) 60 | err := c.WriteMessage(websocket.BinaryMessage, data) 61 | 62 | fmt.Println("客户端发送消息", req.Name) 63 | if err != nil { 64 | logrus.Println("write:", err) 65 | return 66 | } 67 | 68 | case <-interrupt: 69 | logrus.Println("interrupt") 70 | 71 | // Cleanly close the connection by sending a close message and then 72 | // waiting (with timeout) for the server to close the connection. 73 | err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) 74 | if err != nil { 75 | logrus.Println("write close:", err) 76 | return 77 | } 78 | select { 79 | case <-done: 80 | case <-time.After(time.Second): 81 | } 82 | return 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /example/gate/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "github.com/0990/goserver" 7 | pb "github.com/0990/goserver/example/msg" 8 | "github.com/0990/goserver/network" 9 | "github.com/0990/goserver/server" 10 | _ "net/http/pprof" 11 | "time" 12 | ) 13 | 14 | var addr = flag.String("addr", "0.0.0.0:8080", "http service address") 15 | 16 | type clientMgr struct { 17 | clients map[network.Session]struct{} 18 | } 19 | 20 | var BServerID int32 = 101 21 | 22 | func main() { 23 | 24 | mgr := &clientMgr{ 25 | clients: make(map[network.Session]struct{}), 26 | } 27 | 28 | g, err := server.NewGate(100, *addr, goserver.Config{Nats: "127.0.0.1:4222"}) 29 | if err != nil { 30 | fmt.Println(err) 31 | return 32 | } 33 | 34 | g.RegisterNetWorkEvent(func(conn network.Session) { 35 | mgr.clients[conn] = struct{}{} 36 | }, func(conn network.Session) { 37 | delete(mgr.clients, conn) 38 | }) 39 | g.RouteSessionMsg((*pb.ReqHello)(nil), BServerID) 40 | 41 | g.Run() 42 | 43 | //向B服务器发送消息 44 | g.GetServerById(BServerID).Notify(&pb.ReqSend{Name: "我是send消息"}) 45 | 46 | //向B服务器发送request请求 47 | g.GetServerById(BServerID).Request(&pb.ReqRequest{ 48 | Name: "我是request请求", 49 | }, func(resp *pb.RespRequest, err error) { 50 | if err != nil { 51 | return 52 | } 53 | fmt.Println("返回消息:", resp.Name) 54 | }) 55 | 56 | //向B服务器发送call请求 57 | resp := pb.RespCall{} 58 | err = g.GetServerById(BServerID).Call(&pb.ReqCall{Name: "我是call请求"}, &resp) 59 | if err != nil { 60 | return 61 | } 62 | fmt.Println("返回消息:", resp.Name) 63 | 64 | time.Sleep(time.Hour) 65 | } 66 | -------------------------------------------------------------------------------- /example/msg/msg.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: example/msg/msg.proto 3 | 4 | package pb 5 | 6 | import ( 7 | fmt "fmt" 8 | proto "github.com/golang/protobuf/proto" 9 | math "math" 10 | ) 11 | 12 | // Reference imports to suppress errors if they are not otherwise used. 13 | var _ = proto.Marshal 14 | var _ = fmt.Errorf 15 | var _ = math.Inf 16 | 17 | // This is a compile-time assertion to ensure that this generated file 18 | // is compatible with the proto package it is being compiled against. 19 | // A compilation error at this line likely means your copy of the 20 | // proto package needs to be updated. 21 | const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package 22 | 23 | type ReqHello struct { 24 | Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` 25 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 26 | XXX_unrecognized []byte `json:"-"` 27 | XXX_sizecache int32 `json:"-"` 28 | } 29 | 30 | func (m *ReqHello) Reset() { *m = ReqHello{} } 31 | func (m *ReqHello) String() string { return proto.CompactTextString(m) } 32 | func (*ReqHello) ProtoMessage() {} 33 | func (*ReqHello) Descriptor() ([]byte, []int) { 34 | return fileDescriptor_e6af7a2c9c40ad41, []int{0} 35 | } 36 | 37 | func (m *ReqHello) XXX_Unmarshal(b []byte) error { 38 | return xxx_messageInfo_ReqHello.Unmarshal(m, b) 39 | } 40 | func (m *ReqHello) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 41 | return xxx_messageInfo_ReqHello.Marshal(b, m, deterministic) 42 | } 43 | func (m *ReqHello) XXX_Merge(src proto.Message) { 44 | xxx_messageInfo_ReqHello.Merge(m, src) 45 | } 46 | func (m *ReqHello) XXX_Size() int { 47 | return xxx_messageInfo_ReqHello.Size(m) 48 | } 49 | func (m *ReqHello) XXX_DiscardUnknown() { 50 | xxx_messageInfo_ReqHello.DiscardUnknown(m) 51 | } 52 | 53 | var xxx_messageInfo_ReqHello proto.InternalMessageInfo 54 | 55 | func (m *ReqHello) GetName() string { 56 | if m != nil { 57 | return m.Name 58 | } 59 | return "" 60 | } 61 | 62 | type RespHello struct { 63 | Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` 64 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 65 | XXX_unrecognized []byte `json:"-"` 66 | XXX_sizecache int32 `json:"-"` 67 | } 68 | 69 | func (m *RespHello) Reset() { *m = RespHello{} } 70 | func (m *RespHello) String() string { return proto.CompactTextString(m) } 71 | func (*RespHello) ProtoMessage() {} 72 | func (*RespHello) Descriptor() ([]byte, []int) { 73 | return fileDescriptor_e6af7a2c9c40ad41, []int{1} 74 | } 75 | 76 | func (m *RespHello) XXX_Unmarshal(b []byte) error { 77 | return xxx_messageInfo_RespHello.Unmarshal(m, b) 78 | } 79 | func (m *RespHello) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 80 | return xxx_messageInfo_RespHello.Marshal(b, m, deterministic) 81 | } 82 | func (m *RespHello) XXX_Merge(src proto.Message) { 83 | xxx_messageInfo_RespHello.Merge(m, src) 84 | } 85 | func (m *RespHello) XXX_Size() int { 86 | return xxx_messageInfo_RespHello.Size(m) 87 | } 88 | func (m *RespHello) XXX_DiscardUnknown() { 89 | xxx_messageInfo_RespHello.DiscardUnknown(m) 90 | } 91 | 92 | var xxx_messageInfo_RespHello proto.InternalMessageInfo 93 | 94 | func (m *RespHello) GetName() string { 95 | if m != nil { 96 | return m.Name 97 | } 98 | return "" 99 | } 100 | 101 | type ReqSend struct { 102 | Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` 103 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 104 | XXX_unrecognized []byte `json:"-"` 105 | XXX_sizecache int32 `json:"-"` 106 | } 107 | 108 | func (m *ReqSend) Reset() { *m = ReqSend{} } 109 | func (m *ReqSend) String() string { return proto.CompactTextString(m) } 110 | func (*ReqSend) ProtoMessage() {} 111 | func (*ReqSend) Descriptor() ([]byte, []int) { 112 | return fileDescriptor_e6af7a2c9c40ad41, []int{2} 113 | } 114 | 115 | func (m *ReqSend) XXX_Unmarshal(b []byte) error { 116 | return xxx_messageInfo_ReqSend.Unmarshal(m, b) 117 | } 118 | func (m *ReqSend) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 119 | return xxx_messageInfo_ReqSend.Marshal(b, m, deterministic) 120 | } 121 | func (m *ReqSend) XXX_Merge(src proto.Message) { 122 | xxx_messageInfo_ReqSend.Merge(m, src) 123 | } 124 | func (m *ReqSend) XXX_Size() int { 125 | return xxx_messageInfo_ReqSend.Size(m) 126 | } 127 | func (m *ReqSend) XXX_DiscardUnknown() { 128 | xxx_messageInfo_ReqSend.DiscardUnknown(m) 129 | } 130 | 131 | var xxx_messageInfo_ReqSend proto.InternalMessageInfo 132 | 133 | func (m *ReqSend) GetName() string { 134 | if m != nil { 135 | return m.Name 136 | } 137 | return "" 138 | } 139 | 140 | type RespSend struct { 141 | Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` 142 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 143 | XXX_unrecognized []byte `json:"-"` 144 | XXX_sizecache int32 `json:"-"` 145 | } 146 | 147 | func (m *RespSend) Reset() { *m = RespSend{} } 148 | func (m *RespSend) String() string { return proto.CompactTextString(m) } 149 | func (*RespSend) ProtoMessage() {} 150 | func (*RespSend) Descriptor() ([]byte, []int) { 151 | return fileDescriptor_e6af7a2c9c40ad41, []int{3} 152 | } 153 | 154 | func (m *RespSend) XXX_Unmarshal(b []byte) error { 155 | return xxx_messageInfo_RespSend.Unmarshal(m, b) 156 | } 157 | func (m *RespSend) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 158 | return xxx_messageInfo_RespSend.Marshal(b, m, deterministic) 159 | } 160 | func (m *RespSend) XXX_Merge(src proto.Message) { 161 | xxx_messageInfo_RespSend.Merge(m, src) 162 | } 163 | func (m *RespSend) XXX_Size() int { 164 | return xxx_messageInfo_RespSend.Size(m) 165 | } 166 | func (m *RespSend) XXX_DiscardUnknown() { 167 | xxx_messageInfo_RespSend.DiscardUnknown(m) 168 | } 169 | 170 | var xxx_messageInfo_RespSend proto.InternalMessageInfo 171 | 172 | func (m *RespSend) GetName() string { 173 | if m != nil { 174 | return m.Name 175 | } 176 | return "" 177 | } 178 | 179 | type ReqRequest struct { 180 | Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` 181 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 182 | XXX_unrecognized []byte `json:"-"` 183 | XXX_sizecache int32 `json:"-"` 184 | } 185 | 186 | func (m *ReqRequest) Reset() { *m = ReqRequest{} } 187 | func (m *ReqRequest) String() string { return proto.CompactTextString(m) } 188 | func (*ReqRequest) ProtoMessage() {} 189 | func (*ReqRequest) Descriptor() ([]byte, []int) { 190 | return fileDescriptor_e6af7a2c9c40ad41, []int{4} 191 | } 192 | 193 | func (m *ReqRequest) XXX_Unmarshal(b []byte) error { 194 | return xxx_messageInfo_ReqRequest.Unmarshal(m, b) 195 | } 196 | func (m *ReqRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 197 | return xxx_messageInfo_ReqRequest.Marshal(b, m, deterministic) 198 | } 199 | func (m *ReqRequest) XXX_Merge(src proto.Message) { 200 | xxx_messageInfo_ReqRequest.Merge(m, src) 201 | } 202 | func (m *ReqRequest) XXX_Size() int { 203 | return xxx_messageInfo_ReqRequest.Size(m) 204 | } 205 | func (m *ReqRequest) XXX_DiscardUnknown() { 206 | xxx_messageInfo_ReqRequest.DiscardUnknown(m) 207 | } 208 | 209 | var xxx_messageInfo_ReqRequest proto.InternalMessageInfo 210 | 211 | func (m *ReqRequest) GetName() string { 212 | if m != nil { 213 | return m.Name 214 | } 215 | return "" 216 | } 217 | 218 | type RespRequest struct { 219 | Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` 220 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 221 | XXX_unrecognized []byte `json:"-"` 222 | XXX_sizecache int32 `json:"-"` 223 | } 224 | 225 | func (m *RespRequest) Reset() { *m = RespRequest{} } 226 | func (m *RespRequest) String() string { return proto.CompactTextString(m) } 227 | func (*RespRequest) ProtoMessage() {} 228 | func (*RespRequest) Descriptor() ([]byte, []int) { 229 | return fileDescriptor_e6af7a2c9c40ad41, []int{5} 230 | } 231 | 232 | func (m *RespRequest) XXX_Unmarshal(b []byte) error { 233 | return xxx_messageInfo_RespRequest.Unmarshal(m, b) 234 | } 235 | func (m *RespRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 236 | return xxx_messageInfo_RespRequest.Marshal(b, m, deterministic) 237 | } 238 | func (m *RespRequest) XXX_Merge(src proto.Message) { 239 | xxx_messageInfo_RespRequest.Merge(m, src) 240 | } 241 | func (m *RespRequest) XXX_Size() int { 242 | return xxx_messageInfo_RespRequest.Size(m) 243 | } 244 | func (m *RespRequest) XXX_DiscardUnknown() { 245 | xxx_messageInfo_RespRequest.DiscardUnknown(m) 246 | } 247 | 248 | var xxx_messageInfo_RespRequest proto.InternalMessageInfo 249 | 250 | func (m *RespRequest) GetName() string { 251 | if m != nil { 252 | return m.Name 253 | } 254 | return "" 255 | } 256 | 257 | type ReqCall struct { 258 | Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` 259 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 260 | XXX_unrecognized []byte `json:"-"` 261 | XXX_sizecache int32 `json:"-"` 262 | } 263 | 264 | func (m *ReqCall) Reset() { *m = ReqCall{} } 265 | func (m *ReqCall) String() string { return proto.CompactTextString(m) } 266 | func (*ReqCall) ProtoMessage() {} 267 | func (*ReqCall) Descriptor() ([]byte, []int) { 268 | return fileDescriptor_e6af7a2c9c40ad41, []int{6} 269 | } 270 | 271 | func (m *ReqCall) XXX_Unmarshal(b []byte) error { 272 | return xxx_messageInfo_ReqCall.Unmarshal(m, b) 273 | } 274 | func (m *ReqCall) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 275 | return xxx_messageInfo_ReqCall.Marshal(b, m, deterministic) 276 | } 277 | func (m *ReqCall) XXX_Merge(src proto.Message) { 278 | xxx_messageInfo_ReqCall.Merge(m, src) 279 | } 280 | func (m *ReqCall) XXX_Size() int { 281 | return xxx_messageInfo_ReqCall.Size(m) 282 | } 283 | func (m *ReqCall) XXX_DiscardUnknown() { 284 | xxx_messageInfo_ReqCall.DiscardUnknown(m) 285 | } 286 | 287 | var xxx_messageInfo_ReqCall proto.InternalMessageInfo 288 | 289 | func (m *ReqCall) GetName() string { 290 | if m != nil { 291 | return m.Name 292 | } 293 | return "" 294 | } 295 | 296 | type RespCall struct { 297 | Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` 298 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 299 | XXX_unrecognized []byte `json:"-"` 300 | XXX_sizecache int32 `json:"-"` 301 | } 302 | 303 | func (m *RespCall) Reset() { *m = RespCall{} } 304 | func (m *RespCall) String() string { return proto.CompactTextString(m) } 305 | func (*RespCall) ProtoMessage() {} 306 | func (*RespCall) Descriptor() ([]byte, []int) { 307 | return fileDescriptor_e6af7a2c9c40ad41, []int{7} 308 | } 309 | 310 | func (m *RespCall) XXX_Unmarshal(b []byte) error { 311 | return xxx_messageInfo_RespCall.Unmarshal(m, b) 312 | } 313 | func (m *RespCall) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 314 | return xxx_messageInfo_RespCall.Marshal(b, m, deterministic) 315 | } 316 | func (m *RespCall) XXX_Merge(src proto.Message) { 317 | xxx_messageInfo_RespCall.Merge(m, src) 318 | } 319 | func (m *RespCall) XXX_Size() int { 320 | return xxx_messageInfo_RespCall.Size(m) 321 | } 322 | func (m *RespCall) XXX_DiscardUnknown() { 323 | xxx_messageInfo_RespCall.DiscardUnknown(m) 324 | } 325 | 326 | var xxx_messageInfo_RespCall proto.InternalMessageInfo 327 | 328 | func (m *RespCall) GetName() string { 329 | if m != nil { 330 | return m.Name 331 | } 332 | return "" 333 | } 334 | 335 | func init() { 336 | proto.RegisterType((*ReqHello)(nil), "pb.ReqHello") 337 | proto.RegisterType((*RespHello)(nil), "pb.RespHello") 338 | proto.RegisterType((*ReqSend)(nil), "pb.ReqSend") 339 | proto.RegisterType((*RespSend)(nil), "pb.RespSend") 340 | proto.RegisterType((*ReqRequest)(nil), "pb.ReqRequest") 341 | proto.RegisterType((*RespRequest)(nil), "pb.RespRequest") 342 | proto.RegisterType((*ReqCall)(nil), "pb.ReqCall") 343 | proto.RegisterType((*RespCall)(nil), "pb.RespCall") 344 | } 345 | 346 | func init() { proto.RegisterFile("example/msg/msg.proto", fileDescriptor_e6af7a2c9c40ad41) } 347 | 348 | var fileDescriptor_e6af7a2c9c40ad41 = []byte{ 349 | // 145 bytes of a gzipped FileDescriptorProto 350 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4d, 0xad, 0x48, 0xcc, 351 | 0x2d, 0xc8, 0x49, 0xd5, 0xcf, 0x2d, 0x4e, 0x07, 0x61, 0xbd, 0x82, 0xa2, 0xfc, 0x92, 0x7c, 0x21, 352 | 0xa6, 0x82, 0x24, 0x25, 0x39, 0x2e, 0x8e, 0xa0, 0xd4, 0x42, 0x8f, 0xd4, 0x9c, 0x9c, 0x7c, 0x21, 353 | 0x21, 0x2e, 0x96, 0xbc, 0xc4, 0xdc, 0x54, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x30, 0x5b, 354 | 0x49, 0x9e, 0x8b, 0x33, 0x28, 0xb5, 0xb8, 0x00, 0xb7, 0x02, 0x59, 0x2e, 0xf6, 0xa0, 0xd4, 0xc2, 355 | 0xe0, 0xd4, 0xbc, 0x14, 0xac, 0xd2, 0x60, 0xf3, 0x8b, 0x0b, 0x70, 0xca, 0x2b, 0x70, 0x71, 0x05, 356 | 0xa5, 0x16, 0x06, 0xa5, 0x16, 0x96, 0xa6, 0x16, 0x97, 0x60, 0x55, 0xa1, 0xc8, 0xc5, 0x0d, 0x32, 357 | 0x01, 0x9f, 0x12, 0x88, 0x1b, 0x9c, 0x13, 0x73, 0x72, 0xf0, 0xb9, 0x01, 0x97, 0x7c, 0x12, 0x1b, 358 | 0x38, 0x38, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xf8, 0x28, 0x45, 0x35, 0x27, 0x01, 0x00, 359 | 0x00, 360 | } 361 | -------------------------------------------------------------------------------- /example/msg/msg.proto: -------------------------------------------------------------------------------- 1 | syntax="proto3"; 2 | package pb; 3 | 4 | message ReqHello{ 5 | string name = 1; 6 | } 7 | 8 | message RespHello{ 9 | string name = 1; 10 | } 11 | 12 | message ReqSend{ 13 | string name = 1; 14 | } 15 | 16 | message RespSend{ 17 | string name = 1; 18 | } 19 | 20 | message ReqRequest{ 21 | string name = 1; 22 | } 23 | 24 | message RespRequest{ 25 | string name = 1; 26 | } 27 | 28 | message ReqCall{ 29 | string name = 1; 30 | } 31 | 32 | message RespCall{ 33 | string name = 1; 34 | } -------------------------------------------------------------------------------- /example/user/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/0990/goserver" 6 | "github.com/0990/goserver/example/msg" 7 | "github.com/0990/goserver/rpc" 8 | "github.com/0990/goserver/server" 9 | "time" 10 | ) 11 | 12 | func main() { 13 | 14 | s, err := server.NewServer(101, goserver.Config{Nats: "127.0.0.1:4222"}) 15 | if err != nil { 16 | fmt.Println(err) 17 | return 18 | } 19 | 20 | //注册客户端消息事件handler 21 | s.RegisterSessionMsgHandler(func(client rpc.Session, req *pb.ReqHello) { 22 | resp := &pb.RespHello{Name: "回复您的请求"} 23 | fmt.Println("收到客户端来的消息:", req.Name) 24 | client.SendMsg(resp) 25 | }) 26 | 27 | //注册send事件handler 28 | s.RegisterServerHandler(func(server rpc.Server, req *pb.ReqSend) { 29 | fmt.Println("收到gate来的消息:", req.Name) 30 | }) 31 | 32 | //注册request事件handler 33 | s.RegisterRequestMsgHandler(func(server rpc.RequestServer, req *pb.ReqRequest) { 34 | resp := &pb.RespRequest{Name: "我是request返回消息"} 35 | fmt.Println("收到gate来的request消息:", req.Name) 36 | server.Answer(resp) 37 | }) 38 | 39 | //注册call事件handler 40 | s.RegisterRequestMsgHandler(func(server rpc.RequestServer, req *pb.ReqCall) { 41 | resp := &pb.RespCall{Name: "我是call返回消息"} 42 | fmt.Println("收到gate来的call消息:", req.Name) 43 | server.Answer(resp) 44 | }) 45 | 46 | s.Run() 47 | time.Sleep(time.Hour) 48 | } 49 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/0990/goserver 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/golang/protobuf v1.3.2 7 | github.com/gorilla/websocket v1.4.1 8 | github.com/nats-io/nats-server/v2 v2.1.2 // indirect 9 | github.com/nats-io/nats.go v1.13.0 10 | github.com/pkg/errors v0.8.1 11 | github.com/sirupsen/logrus v1.4.2 12 | golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 // indirect 13 | ) 14 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= 4 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 5 | github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= 6 | github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 7 | github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= 8 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 9 | github.com/nats-io/jwt v0.3.0 h1:xdnzwFETV++jNc4W1mw//qFyJGb2ABOombmZJQS4+Qo= 10 | github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= 11 | github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI= 12 | github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= 13 | github.com/nats-io/nats-server/v2 v2.1.2 h1:i2Ly0B+1+rzNZHHWtD4ZwKi+OU5l+uQo1iDHZ2PmiIc= 14 | github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= 15 | github.com/nats-io/nats.go v1.9.1 h1:ik3HbLhZ0YABLto7iX80pZLPw/6dx3T+++MZJwLnMrQ= 16 | github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= 17 | github.com/nats-io/nats.go v1.13.0 h1:LvYqRB5epIzZWQp6lmeltOOZNLqCvm4b+qfvzZO03HE= 18 | github.com/nats-io/nats.go v1.13.0/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= 19 | github.com/nats-io/nkeys v0.1.0 h1:qMd4+pRHgdr1nAClu+2h/2a5F2TmKcCzjCDazVgRoX4= 20 | github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= 21 | github.com/nats-io/nkeys v0.1.3 h1:6JrEfig+HzTH85yxzhSVbjHRJv9cn0p6n3IngIcM5/k= 22 | github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= 23 | github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8= 24 | github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= 25 | github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= 26 | github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 27 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 28 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 29 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 30 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 31 | github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= 32 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 33 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 34 | github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= 35 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 36 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 37 | golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= 38 | golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 39 | golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 40 | golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 h1:S25/rfnfsMVgORT4/J61MJ7rdyseOZOyvLIrZEZ7s6s= 41 | golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 42 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 43 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 44 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 45 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 46 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 47 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= 48 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 49 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e h1:D5TXcfTk7xF7hvieo4QErS3qqCB4teTffacDWr7CI+0= 50 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 51 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 52 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 53 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= 54 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 55 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 56 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 57 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 58 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 59 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 60 | -------------------------------------------------------------------------------- /goserver.json: -------------------------------------------------------------------------------- 1 | { 2 | "nats":"nats://127.0.0.1:4222" 3 | } -------------------------------------------------------------------------------- /network/client.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import ( 4 | "github.com/golang/protobuf/proto" 5 | "github.com/sirupsen/logrus" 6 | "reflect" 7 | ) 8 | 9 | type Session interface { 10 | SendMsg(msg proto.Message) 11 | SendRawMsg(msgID uint32, data []byte) 12 | ID() int32 13 | Close() 14 | } 15 | 16 | type Client struct { 17 | conn Conn 18 | mgr *Mgr 19 | } 20 | 21 | func NewClient(conn Conn, mgr *Mgr) *Client { 22 | p := &Client{ 23 | conn: conn, 24 | mgr: mgr, 25 | } 26 | return p 27 | } 28 | 29 | func (p *Client) ReadLoop() { 30 | for { 31 | data, err := p.conn.ReadMsg() 32 | if err != nil { 33 | logrus.WithError(err).Error("read message") 34 | break 35 | } 36 | 37 | msg, err := p.mgr.processor.Unmarshal(data) 38 | if err != nil { 39 | logrus.Errorf("unmarshal message error: %v", err) 40 | break 41 | } 42 | p.mgr.Post(func() { 43 | err = p.mgr.processor.Handle(msg, p) 44 | }) 45 | } 46 | } 47 | 48 | func (p *Client) OnNew() { 49 | p.mgr.Post(func() { 50 | p.mgr.sesID2Client[p.conn.ID()] = p 51 | p.mgr.onNew(p) 52 | }) 53 | } 54 | 55 | func (p *Client) OnClose() { 56 | p.mgr.Post(func() { 57 | delete(p.mgr.sesID2Client, p.conn.ID()) 58 | p.mgr.onClose(p) 59 | }) 60 | } 61 | 62 | func (p *Client) SendMsg(msg proto.Message) { 63 | data, err := p.mgr.processor.Marshal(msg) 64 | if err != nil { 65 | logrus.Errorf("marshal message %v error: %v", reflect.TypeOf(msg), err) 66 | return 67 | } 68 | err = p.conn.WriteMsg(data) 69 | if err != nil { 70 | logrus.Error("write message %v error: %v", reflect.TypeOf(msg), err) 71 | } 72 | } 73 | 74 | func (p *Client) SendRawMsg(msgID uint32, data []byte) { 75 | newData := p.mgr.processor.Encode(msgID, data) 76 | err := p.conn.WriteMsg(newData) 77 | if err != nil { 78 | logrus.Error("write message error: %v", err) 79 | } 80 | } 81 | 82 | func (p *Client) ID() int32 { 83 | return p.conn.ID() 84 | } 85 | 86 | func (p *Client) Close() { 87 | p.conn.Close() 88 | } 89 | -------------------------------------------------------------------------------- /network/conn.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import "net" 4 | 5 | type Conn interface { 6 | ReadMsg() ([]byte, error) 7 | WriteMsg(args []byte) error 8 | LocalAddr() net.Addr 9 | ID() int32 10 | Close() 11 | } 12 | -------------------------------------------------------------------------------- /network/mgr.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import ( 4 | "github.com/0990/goserver/service" 5 | "github.com/0990/goserver/util" 6 | "github.com/golang/protobuf/proto" 7 | "github.com/sirupsen/logrus" 8 | "net" 9 | "reflect" 10 | "sync" 11 | ) 12 | 13 | type Mgr struct { 14 | wsAddr string 15 | sesID2Client map[int32]*Client 16 | sesMutex sync.Mutex 17 | onNew, onClose func(conn Session) 18 | processor *Processor 19 | worker service.Worker 20 | wss *WSServer 21 | 22 | close func() 23 | } 24 | 25 | func NewMgr(wsAddr string, worker service.Worker) *Mgr { 26 | p := &Mgr{ 27 | wsAddr: wsAddr, 28 | sesID2Client: make(map[int32]*Client), 29 | worker: worker, 30 | processor: NewProcessor(), 31 | } 32 | return p 33 | } 34 | 35 | //func (p *Mgr) Init(wsAddr string, worker service.Worker) { 36 | // p.wsAddr = wsAddr 37 | // p.sesID2Client = make(map[int32]*Client) 38 | // p.worker = worker 39 | //} 40 | 41 | func (p *Mgr) Run() { 42 | //创建websocket server 43 | wss := NewWSServer(p.wsAddr, func(conn Conn) *Client { 44 | c := NewClient(conn, p) 45 | return c 46 | }) 47 | p.wss = wss 48 | wss.Start() 49 | p.close = wss.Close 50 | } 51 | 52 | func (p *Mgr) ListenAddr() *net.TCPAddr { 53 | return p.wss.ListenAddr() 54 | } 55 | 56 | func (p *Mgr) Close() { 57 | p.close() 58 | } 59 | 60 | func (p *Mgr) Post(f func()) { 61 | p.worker.Post(f) 62 | } 63 | 64 | func (p *Mgr) RegisterEvent(onNew, onClose func(conn Session)) { 65 | p.onNew = onNew 66 | p.onClose = onClose 67 | } 68 | 69 | func (p *Mgr) GetSession(sesID int32) (Session, bool) { 70 | p.sesMutex.Lock() 71 | defer p.sesMutex.Unlock() 72 | 73 | v, ok := p.sesID2Client[sesID] 74 | return v, ok 75 | } 76 | 77 | //func (p *Mgr) RegisterSessionMsgHandler(msg proto.Message, f func(Session, proto.Message)) { 78 | // p.processor.Register(msg) 79 | // p.processor.SetHandler(msg, f) 80 | //} 81 | 82 | func (p *Mgr) RegisterSessionMsgHandler(cb interface{}) { 83 | err, funValue, msgType := util.CheckArgs1MsgFun(cb) 84 | if err != nil { 85 | logrus.WithError(err).Error("RegisterServerMsgHandler") 86 | return 87 | } 88 | msg := reflect.New(msgType).Elem().Interface().(proto.Message) 89 | p.processor.RegisterSessionMsgHandler(msg, func(s Session, message proto.Message) { 90 | funValue.Call([]reflect.Value{reflect.ValueOf(s), reflect.ValueOf(message)}) 91 | }) 92 | } 93 | 94 | func (p *Mgr) RegisterRawSessionMsgHandler(msg proto.Message, handler MsgHandler) { 95 | p.processor.RegisterSessionMsgHandler(msg, handler) 96 | } 97 | -------------------------------------------------------------------------------- /network/processor.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "github.com/0990/goserver/util" 7 | "github.com/golang/protobuf/proto" 8 | "github.com/pkg/errors" 9 | "github.com/sirupsen/logrus" 10 | "reflect" 11 | ) 12 | 13 | type Processor struct { 14 | littleEndian bool 15 | msgID2Info map[uint32]*MsgInfo 16 | } 17 | 18 | type MsgInfo struct { 19 | msgType reflect.Type 20 | msgHandler MsgHandler 21 | } 22 | 23 | type MsgHandler func(client Session, msg proto.Message) 24 | 25 | func NewProcessor() *Processor { 26 | p := new(Processor) 27 | p.littleEndian = false 28 | p.msgID2Info = make(map[uint32]*MsgInfo) 29 | return p 30 | } 31 | 32 | func (p *Processor) SetByteOrder(littleEndian bool) { 33 | p.littleEndian = littleEndian 34 | } 35 | 36 | //func (p *Processor) Register(msg proto.Message) { 37 | // msgID, msgType := util.ProtoHash(msg) 38 | // if _, ok := p.msgID2Info[msgID]; ok { 39 | // logrus.Errorf("message %s is already registered", msgType) 40 | // return 41 | // } 42 | // 43 | // msgInfo := new(MsgInfo) 44 | // msgInfo.msgType = msgType 45 | // p.msgID2Info[msgID] = msgInfo 46 | // return 47 | //} 48 | // 49 | //func (p *Processor) SetHandler(msg proto.Message, msgHandler MsgHandler) { 50 | // msgID, msgType := util.ProtoHash(msg) 51 | // msgInfo, ok := p.msgID2Info[msgID] 52 | // if !ok { 53 | // logrus.Errorf("message %s not registered", msgType) 54 | // return 55 | // } 56 | // 57 | // msgInfo.msgHandler = msgHandler 58 | //} 59 | 60 | func (p *Processor) RegisterSessionMsgHandler(msg proto.Message, handler MsgHandler) { 61 | msgID, msgType := util.ProtoHash(msg) 62 | if _, ok := p.msgID2Info[msgID]; ok { 63 | logrus.Errorf("message %s is already registered", msgType) 64 | return 65 | } 66 | 67 | msgInfo := new(MsgInfo) 68 | msgInfo.msgType = msgType 69 | msgInfo.msgHandler = handler 70 | p.msgID2Info[msgID] = msgInfo 71 | } 72 | 73 | func (p *Processor) Handle(msg proto.Message, client Session) error { 74 | msgID, msgType := util.ProtoHash(msg) 75 | msgInfo, ok := p.msgID2Info[msgID] 76 | if !ok { 77 | logrus.Errorf("message %s not registered", msgType) 78 | return nil 79 | } 80 | 81 | if msgInfo.msgHandler != nil { 82 | msgInfo.msgHandler(client, msg) 83 | } 84 | 85 | return nil 86 | } 87 | 88 | func (p *Processor) Unmarshal(data []byte) (proto.Message, error) { 89 | if len(data) < 4 { 90 | return nil, errors.New("protobuf data too short") 91 | } 92 | 93 | var msgID uint32 94 | if p.littleEndian { 95 | msgID = binary.LittleEndian.Uint32(data) 96 | } else { 97 | msgID = binary.BigEndian.Uint32(data) 98 | } 99 | 100 | msgInfo, exist := p.msgID2Info[msgID] 101 | if !exist { 102 | return nil, errors.New(fmt.Sprintf("msgID:%d not registered", msgID)) 103 | } 104 | 105 | msg := reflect.New(msgInfo.msgType.Elem()).Interface().(proto.Message) 106 | return msg, proto.Unmarshal(data[4:], msg.(proto.Message)) 107 | } 108 | 109 | func (p *Processor) Marshal(msg proto.Message) ([]byte, error) { 110 | msgID, _ := util.ProtoHash(msg) 111 | 112 | data, err := proto.Marshal(msg) 113 | if err != nil { 114 | return nil, err 115 | } 116 | return p.Encode(msgID, data), nil 117 | //msgIDData := make([]byte, 2) 118 | //if p.littleEndian { 119 | // binary.LittleEndian.PutUint16(msgIDData, msgID) 120 | //} else { 121 | // binary.BigEndian.PutUint16(msgIDData, msgID) 122 | //} 123 | // 124 | ////TODO 性能优化 125 | //ret := append(msgIDData, data...) 126 | //return ret, nil 127 | } 128 | 129 | func (p *Processor) Encode(msgID uint32, data []byte) []byte { 130 | msgIDData := make([]byte, 4) 131 | if p.littleEndian { 132 | binary.LittleEndian.PutUint32(msgIDData, msgID) 133 | } else { 134 | binary.BigEndian.PutUint32(msgIDData, msgID) 135 | } 136 | 137 | //TODO 性能优化 138 | ret := append(msgIDData, data...) 139 | return ret 140 | } 141 | -------------------------------------------------------------------------------- /network/wsconn.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import ( 4 | "errors" 5 | "github.com/gorilla/websocket" 6 | "net" 7 | "sync" 8 | ) 9 | 10 | type WSConn struct { 11 | sync.Mutex 12 | conn *websocket.Conn 13 | 14 | // Buffered channel of outbound messages. 15 | send chan []byte 16 | 17 | closeFlag bool 18 | 19 | connid int32 20 | } 21 | 22 | func NewWSConn(conn *websocket.Conn, connid int32) *WSConn { 23 | wsc := new(WSConn) 24 | wsc.send = make(chan []byte, 256) 25 | wsc.conn = conn 26 | wsc.connid = connid 27 | return wsc 28 | } 29 | 30 | func (p *WSConn) writePump() { 31 | for data := range p.send { 32 | if data == nil { 33 | break 34 | } 35 | err := p.conn.WriteMessage(websocket.BinaryMessage, data) 36 | if err != nil { 37 | break 38 | } 39 | } 40 | p.conn.Close() 41 | p.Lock() 42 | p.closeFlag = true 43 | p.Unlock() 44 | } 45 | 46 | func (p *WSConn) WriteMsg(args []byte) error { 47 | p.Lock() 48 | defer p.Unlock() 49 | 50 | if p.closeFlag { 51 | return errors.New("socket closeFlag is true") 52 | } 53 | 54 | if len(p.send) == cap(p.send) { 55 | close(p.send) 56 | p.closeFlag = true 57 | return errors.New("send buffer full") 58 | } 59 | 60 | p.send <- args 61 | return nil 62 | } 63 | 64 | func (p *WSConn) doWrite(data []byte) { 65 | p.send <- data 66 | } 67 | 68 | func (p *WSConn) ReadMsg() ([]byte, error) { 69 | _, data, err := p.conn.ReadMessage() 70 | return data, err 71 | } 72 | 73 | func (p *WSConn) ID() int32 { 74 | return p.connid 75 | } 76 | 77 | func (p *WSConn) Close() { 78 | p.Lock() 79 | defer p.Unlock() 80 | if p.closeFlag { 81 | return 82 | } 83 | p.doWrite(nil) 84 | p.closeFlag = true 85 | } 86 | 87 | func (p *WSConn) LocalAddr() net.Addr { 88 | return p.conn.LocalAddr() 89 | } 90 | 91 | func (p *WSConn) RemoteAddr() net.Addr { 92 | return p.conn.RemoteAddr() 93 | } 94 | -------------------------------------------------------------------------------- /network/wsserver.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import ( 4 | "github.com/gorilla/websocket" 5 | "github.com/sirupsen/logrus" 6 | "net" 7 | "net/http" 8 | "sync" 9 | "sync/atomic" 10 | ) 11 | 12 | //这里可以定义handshake规则:超时时间等 13 | var upgrader = websocket.Upgrader{ 14 | CheckOrigin: func(r *http.Request) bool { 15 | return true 16 | }, 17 | Subprotocols: []string{"avatar-fight"}, 18 | } // use default options 19 | 20 | type WSServer struct { 21 | sync.Mutex 22 | addr string 23 | wg sync.WaitGroup 24 | conns map[*websocket.Conn]struct{} 25 | connid int32 26 | newClient func(conn Conn) *Client 27 | ln net.Listener 28 | 29 | close func() 30 | } 31 | 32 | func NewWSServer(addr string, newClient func(conn Conn) *Client) *WSServer { 33 | return &WSServer{ 34 | addr: addr, 35 | newClient: newClient, 36 | conns: make(map[*websocket.Conn]struct{}), 37 | } 38 | } 39 | 40 | func (p *WSServer) Start() error { 41 | ln, err := net.Listen("tcp", p.addr) 42 | if err != nil { 43 | logrus.WithField("addr", p.addr).Fatal("启动失败,端口被占用") 44 | return err 45 | } 46 | 47 | p.ln = ln 48 | httpSvr := &http.Server{ 49 | Addr: p.addr, 50 | Handler: p, 51 | } 52 | 53 | p.close = func() { 54 | httpSvr.Close() 55 | } 56 | go func() { 57 | err := httpSvr.Serve(ln) 58 | if err != nil && err != http.ErrServerClosed { 59 | logrus.WithError(err).Fatal("WSServer Serve") 60 | return 61 | } 62 | }() 63 | return nil 64 | } 65 | 66 | func (p *WSServer) Close() { 67 | p.close() 68 | } 69 | 70 | func (p *WSServer) ListenAddr() *net.TCPAddr { 71 | return p.ln.Addr().(*net.TCPAddr) 72 | } 73 | 74 | func (p *WSServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { 75 | conn, err := upgrader.Upgrade(w, r, nil) 76 | if err != nil { 77 | logrus.WithError(err).Error("ServerHttp upgrader.Upgrade") 78 | return 79 | } 80 | 81 | p.wg.Add(1) 82 | defer p.wg.Done() 83 | 84 | p.Lock() 85 | p.conns[conn] = struct{}{} 86 | p.Unlock() 87 | 88 | connid := p.NewConnID() 89 | wsc := NewWSConn(conn, connid) 90 | go wsc.writePump() 91 | 92 | c := p.newClient(wsc) 93 | c.OnNew() 94 | c.ReadLoop() 95 | 96 | wsc.Close() 97 | p.Lock() 98 | delete(p.conns, conn) 99 | p.Unlock() 100 | c.OnClose() 101 | } 102 | 103 | func (p *WSServer) NewConnID() int32 { 104 | return atomic.AddInt32(&p.connid, 1) 105 | } 106 | -------------------------------------------------------------------------------- /rpc/client.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "fmt" 5 | "github.com/0990/goserver/rpc/rpcmsg" 6 | "github.com/0990/goserver/service" 7 | "github.com/golang/protobuf/proto" 8 | "github.com/nats-io/nats.go" 9 | "github.com/pkg/errors" 10 | "github.com/sirupsen/logrus" 11 | "reflect" 12 | "time" 13 | ) 14 | 15 | var ErrTimeOut = errors.New("rpc: timeout") 16 | var ErrNoKnow = errors.New("rpc: unknow") 17 | 18 | const CALL_TIMEOUT = 10 * time.Second 19 | 20 | type Client struct { 21 | conn *nats.Conn 22 | serverTopic string 23 | serverID int32 24 | send2Session func(sesID int32, msgID uint32, data []byte) //gate服专用 25 | processor *Processor 26 | worker service.Worker 27 | close chan struct{} 28 | } 29 | 30 | func newClient(serverID int32, worker service.Worker, natsUrl string) (*Client, error) { 31 | name := fmt.Sprintf("%v", serverID) 32 | 33 | p := &Client{} 34 | conn, err := nats.Connect(natsUrl, nats.Name(name)) 35 | if err != nil { 36 | return nil, err 37 | } 38 | p.conn = conn 39 | p.serverID = serverID 40 | p.serverTopic = fmt.Sprintf("%v", serverID) 41 | p.processor = NewProcessor() 42 | p.worker = worker 43 | p.close = make(chan struct{}) 44 | return p, nil 45 | } 46 | 47 | //阻塞式 48 | func (p *Client) Call(serverTopic string, req proto.Message, resp proto.Message) error { 49 | ret := make(chan error) 50 | call := p.processor.RegisterCall(resp, func(err error) { 51 | ret <- err 52 | }) 53 | 54 | data := MakeRequestData(req, call.seqID, p.serverID) 55 | err := p.publish(serverTopic, data) 56 | if err != nil { 57 | return err 58 | } 59 | 60 | select { 61 | case err, ok := <-ret: 62 | if !ok { 63 | return errors.New("client closed") 64 | } 65 | return err 66 | case <-time.After(CALL_TIMEOUT): 67 | p.processor.GetCallWithDel(call.seqID) 68 | return ErrTimeOut 69 | } 70 | 71 | return ErrNoKnow 72 | } 73 | 74 | //不需要注册Response的Request请求 onRecv func(*msg.XXX,error) 75 | func (p *Client) Request(serverTopic string, msg proto.Message, cb interface{}) error { 76 | cbType := reflect.TypeOf(cb) 77 | if cbType.Kind() != reflect.Func { 78 | return errors.New("cb not a func") 79 | } 80 | cbValue := reflect.ValueOf(cb) 81 | numArgs := cbType.NumIn() 82 | if numArgs != 2 { 83 | return errors.New("cb param num args !=2") 84 | } 85 | args0 := cbType.In(0) 86 | if args0.Kind() != reflect.Ptr { 87 | return errors.New("cb param args0 not ptr") 88 | } 89 | //TODO 严格检查参数类型 90 | args1 := cbType.In(1) 91 | 92 | //TODO 如果出现error,resp==nil 93 | resp := reflect.New(args0.Elem()).Interface().(proto.Message) 94 | onRecv := func(err error) { 95 | oV := make([]reflect.Value, 2) 96 | oV[0] = reflect.ValueOf(resp) 97 | if err == nil { 98 | oV[1] = reflect.New(args1).Elem() 99 | } else { 100 | oV[1] = reflect.ValueOf(err) 101 | } 102 | cbValue.Call(oV) 103 | } 104 | 105 | call := p.processor.RegisterCall(resp, onRecv) 106 | data := MakeRequestData(msg, call.seqID, p.serverID) 107 | err := p.publish(serverTopic, data) 108 | if err != nil { 109 | return err 110 | } 111 | //util.PrintCurrNano("client request after") 112 | 113 | time.AfterFunc(CALL_TIMEOUT, func() { 114 | //TODO 放在主线程中工作 115 | if _, ok := p.processor.GetCallWithDel(call.seqID); ok { 116 | onRecv(ErrTimeOut) 117 | } 118 | }) 119 | return nil 120 | } 121 | 122 | //仅发送 123 | func (p *Client) SendMsg(serverTopic string, msg proto.Message) { 124 | data := MakeServer2ServerData(msg, p.serverID) 125 | p.publish(serverTopic, data) 126 | } 127 | 128 | func (p *Client) Answer(serverTopic string, seqid int32, msg proto.Message) { 129 | data := MakeResponseData(msg, seqid, p.serverID) 130 | p.publish(serverTopic, data) 131 | } 132 | 133 | //发送给gate,然后gate会发出去 134 | func (p *Client) RouteGate(gateTopic string, sesID int32, msg proto.Message) { 135 | data := MakeServer2SessionData(msg, sesID, p.serverID) 136 | p.publish(gateTopic, data) 137 | } 138 | 139 | func (p *Client) Run() { 140 | go p.ReadLoop() 141 | } 142 | 143 | func (p *Client) Close() (err error) { 144 | p.close <- struct{}{} 145 | return 146 | } 147 | 148 | func (p *Client) ReadLoop() error { 149 | sub, err := p.conn.SubscribeSync(p.serverTopic) 150 | if err != nil { 151 | return err 152 | } 153 | 154 | go func() { 155 | <-p.close 156 | sub.Unsubscribe() 157 | }() 158 | 159 | for { 160 | m, err := sub.NextMsg(time.Minute) 161 | if err != nil && err == nats.ErrTimeout { 162 | continue 163 | } else if err != nil { 164 | logrus.WithError(err).Error("ReadLoop NextMsg error") 165 | return err 166 | } 167 | rpcData := &rpcmsg.Data{} 168 | err = proto.Unmarshal(m.Data, rpcData) 169 | if err != nil { 170 | logrus.WithError(err) 171 | continue 172 | } 173 | p.worker.Post(func() { 174 | p.handle(rpcData) 175 | }) 176 | } 177 | } 178 | 179 | func (p *Client) handle(rpcData *rpcmsg.Data) { 180 | msgID := rpcData.Msgid 181 | seqID := rpcData.Seqid 182 | sesID := rpcData.Sesid 183 | senderID := rpcData.Senderid 184 | data := rpcData.Data 185 | 186 | switch rpcData.Type { 187 | case rpcmsg.Data_Request: 188 | s := NewRequestServer(p, senderID, seqID) 189 | err := p.processor.HandleRequest(s, msgID, data) 190 | if err != nil { 191 | logrus.WithError(err) 192 | return 193 | } 194 | case rpcmsg.Data_Response: 195 | err := p.processor.HandleResponse(seqID, data) 196 | if err != nil { 197 | logrus.WithError(err) 198 | return 199 | } 200 | case rpcmsg.Data_Session2Server: 201 | s := NewSession(p, senderID, sesID) 202 | err := p.processor.HandleSessionMsg(s, msgID, data) 203 | if err != nil { 204 | logrus.WithError(err) 205 | return 206 | } 207 | case rpcmsg.Data_Server2Session: 208 | p.send2Session(sesID, msgID, data) 209 | case rpcmsg.Data_Server2Server: 210 | s := NewServer(p, senderID) 211 | err := p.processor.HandleMsg(s, msgID, data) 212 | if err != nil { 213 | logrus.WithError(err) 214 | return 215 | } 216 | default: 217 | logrus.WithField("rpcType", rpcData.Type).Error("not support rpc type") 218 | } 219 | } 220 | 221 | func (p *Client) publish(topic string, data []byte) error { 222 | return p.conn.Publish(topic, data) 223 | } 224 | 225 | func (p *Client) RouteSession2Server(topic string, sesID int32, msg proto.Message) { 226 | data := MakeSession2ServerData(msg, sesID, p.serverID) 227 | p.publish(topic, data) 228 | } 229 | 230 | func (p *Client) RegisterSend2Session(send2Session func(sesID int32, msgID uint32, data []byte)) { 231 | p.send2Session = send2Session 232 | } 233 | -------------------------------------------------------------------------------- /rpc/processor.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "errors" 5 | "github.com/0990/goserver/util" 6 | "github.com/golang/protobuf/proto" 7 | "github.com/sirupsen/logrus" 8 | "reflect" 9 | "sync" 10 | "sync/atomic" 11 | ) 12 | 13 | type Processor struct { 14 | msgID2Request map[uint32]*RequestInfo 15 | msgID2ServerMsg map[uint32]*ServerMsgInfo 16 | msgID2SessionMsg map[uint32]*SessionMsgInfo 17 | 18 | seqID int32 19 | seqID2CallInfo sync.Map 20 | } 21 | 22 | type RequestInfo struct { 23 | msgType reflect.Type 24 | msgHandler RequestHandler 25 | } 26 | 27 | type ServerMsgInfo struct { 28 | msgType reflect.Type 29 | msgHandler ServerMsgHandler 30 | } 31 | 32 | type SessionMsgInfo struct { 33 | msgType reflect.Type 34 | msgHandler SessionMsgHandler 35 | } 36 | 37 | type RequestHandler func(RequestServer, proto.Message) 38 | type ServerMsgHandler func(Server, proto.Message) 39 | type SessionMsgHandler func(Session, proto.Message) 40 | 41 | func NewProcessor() *Processor { 42 | p := new(Processor) 43 | p.msgID2Request = make(map[uint32]*RequestInfo) 44 | p.msgID2ServerMsg = make(map[uint32]*ServerMsgInfo) 45 | p.msgID2SessionMsg = make(map[uint32]*SessionMsgInfo) 46 | 47 | return p 48 | } 49 | 50 | func (p *Processor) RegisterRequestMsgHandler(msg proto.Message, f RequestHandler) { 51 | msgID, msgType := util.ProtoHash(msg) 52 | if _, ok := p.msgID2Request[msgID]; ok { 53 | logrus.Errorf("message %s is already registered", msgType) 54 | return 55 | } 56 | 57 | msgInfo := new(RequestInfo) 58 | msgInfo.msgType = msgType 59 | msgInfo.msgHandler = f 60 | p.msgID2Request[msgID] = msgInfo 61 | } 62 | 63 | //func (p *Processor) RegisterRequestMsgHandler(cb interface{}) { 64 | // cbType := reflect.TypeOf(cb) 65 | // if cbType.Kind() != reflect.Func { 66 | // logrus.Error("cb not a func") 67 | // return 68 | // } 69 | // cbValue := reflect.ValueOf(cb) 70 | // numArgs := cbType.NumIn() 71 | // if numArgs != 2 { 72 | // logrus.Error("cb param num args !=2") 73 | // return 74 | // } 75 | // 76 | // //TODO 严格检查参数类型 77 | // //args0 := cbType.In(0) 78 | // args1 := cbType.In(1) 79 | // if args1.Kind() != reflect.Ptr { 80 | // logrus.Error("cb param args1 not ptr") 81 | // return 82 | // } 83 | // 84 | // msg := reflect.New(args1).Elem().Interface().(proto.Message) 85 | // p.registerRequestMsgHandler(msg, func(s RequestServer, message proto.Message) { 86 | // cbValue.Call([]reflect.Value{reflect.ValueOf(s), reflect.ValueOf(message)}) 87 | // }) 88 | //} 89 | 90 | func (p *Processor) RegisterServerMsgHandler(msg proto.Message, f ServerMsgHandler) { 91 | msgID, msgType := util.ProtoHash(msg) 92 | if _, ok := p.msgID2ServerMsg[msgID]; ok { 93 | logrus.Errorf("message %s is already registered", msgType) 94 | return 95 | } 96 | 97 | msgInfo := new(ServerMsgInfo) 98 | msgInfo.msgType = msgType 99 | msgInfo.msgHandler = f 100 | p.msgID2ServerMsg[msgID] = msgInfo 101 | } 102 | 103 | //func (p *Processor) RegisterServerMsgHandler(cb interface{}) { 104 | // cbType := reflect.TypeOf(cb) 105 | // if cbType.Kind() != reflect.Func { 106 | // logrus.Error("cb not a func") 107 | // return 108 | // } 109 | // cbValue := reflect.ValueOf(cb) 110 | // numArgs := cbType.NumIn() 111 | // if numArgs != 2 { 112 | // logrus.Error("cb param num args !=2") 113 | // return 114 | // } 115 | // 116 | // //TODO 严格检查参数类型 117 | // //args0 := cbType.In(0) 118 | // args1 := cbType.In(1) 119 | // if args1.Kind() != reflect.Ptr { 120 | // logrus.Error("cb param args1 not ptr") 121 | // return 122 | // } 123 | // 124 | // msg := reflect.New(args1).Elem().Interface().(proto.Message) 125 | // p.registerServerMsgHandler(msg, func(s Server, message proto.Message) { 126 | // cbValue.Call([]reflect.Value{reflect.ValueOf(s), reflect.ValueOf(message)}) 127 | // }) 128 | // 129 | //} 130 | 131 | func (p *Processor) RegisterSessionMsgHandler(msg proto.Message, f SessionMsgHandler) { 132 | msgID, msgType := util.ProtoHash(msg) 133 | if _, ok := p.msgID2SessionMsg[msgID]; ok { 134 | logrus.Errorf("message %s is already registered", msgType) 135 | return 136 | } 137 | 138 | msgInfo := new(SessionMsgInfo) 139 | msgInfo.msgType = msgType 140 | msgInfo.msgHandler = f 141 | p.msgID2SessionMsg[msgID] = msgInfo 142 | } 143 | 144 | //func (p *Processor) RegisterSessionMsgHandler(cb interface{}) { 145 | // cbType := reflect.TypeOf(cb) 146 | // if cbType.Kind() != reflect.Func { 147 | // logrus.Error("cb not a func") 148 | // return 149 | // } 150 | // cbValue := reflect.ValueOf(cb) 151 | // numArgs := cbType.NumIn() 152 | // if numArgs != 2 { 153 | // logrus.Error("cb param num args !=2") 154 | // return 155 | // } 156 | // 157 | // //TODO 严格检查参数类型 158 | // //args0 := cbType.In(0) 159 | // args1 := cbType.In(1) 160 | // if args1.Kind() != reflect.Ptr { 161 | // logrus.Error("cb param args1 not ptr") 162 | // return 163 | // } 164 | // 165 | // msg := reflect.New(args1).Elem().Interface().(proto.Message) 166 | // p.registerSessionMsgHandler(msg, func(s Session, message proto.Message) { 167 | // cbValue.Call([]reflect.Value{reflect.ValueOf(s), reflect.ValueOf(message)}) 168 | // }) 169 | //} 170 | 171 | func (p *Processor) HandleRequest(server RequestServer, msgID uint32, data []byte) error { 172 | msgInfo, ok := p.msgID2Request[msgID] 173 | if !ok { 174 | logrus.Errorf("message %d not registered", msgID) 175 | return errors.New("msgID not registered") 176 | } 177 | 178 | msg := reflect.New(msgInfo.msgType.Elem()).Interface().(proto.Message) 179 | err := proto.Unmarshal(data, msg) 180 | if err != nil { 181 | logrus.WithError(err).Error("HandleRequest") 182 | return err 183 | } 184 | if msgInfo.msgHandler != nil { 185 | msgInfo.msgHandler(server, msg) 186 | } 187 | return nil 188 | } 189 | 190 | func (p *Processor) HandleMsg(server Server, msgID uint32, data []byte) error { 191 | msgInfo, ok := p.msgID2ServerMsg[msgID] 192 | if !ok { 193 | logrus.Errorf("message %d not registered", msgID) 194 | return errors.New("msgID not registered") 195 | } 196 | 197 | msg := reflect.New(msgInfo.msgType.Elem()).Interface().(proto.Message) 198 | err := proto.Unmarshal(data, msg) 199 | if err != nil { 200 | logrus.WithError(err).Error("HandleRequest") 201 | return err 202 | } 203 | if msgInfo.msgHandler != nil { 204 | msgInfo.msgHandler(server, msg) 205 | } 206 | return nil 207 | } 208 | 209 | func (p *Processor) HandleSessionMsg(session Session, msgID uint32, data []byte) error { 210 | msgInfo, ok := p.msgID2SessionMsg[msgID] 211 | if !ok { 212 | logrus.Errorf("message %d not registered", msgID) 213 | return errors.New("msgID not registered") 214 | } 215 | 216 | msg := reflect.New(msgInfo.msgType.Elem()).Interface().(proto.Message) 217 | err := proto.Unmarshal(data, msg) 218 | if err != nil { 219 | logrus.WithError(err).Error("HandleRequest") 220 | return err 221 | } 222 | if msgInfo.msgHandler != nil { 223 | msgInfo.msgHandler(session, msg) 224 | } 225 | return nil 226 | } 227 | 228 | func (p *Processor) NewSeqID() int32 { 229 | return atomic.AddInt32(&p.seqID, 1) 230 | } 231 | 232 | type Call struct { 233 | seqID int32 234 | onRecv func(error) 235 | resp proto.Message 236 | } 237 | 238 | func (p *Processor) RegisterCall(resp proto.Message, onRecv func(error)) *Call { 239 | seqID := p.NewSeqID() 240 | call := &Call{ 241 | seqID: seqID, 242 | onRecv: onRecv, 243 | resp: resp, 244 | } 245 | p.seqID2CallInfo.Store(seqID, call) 246 | return call 247 | } 248 | 249 | func (p *Processor) GetCallWithDel(seqID int32) (*Call, bool) { 250 | if v, ok := p.seqID2CallInfo.Load(seqID); ok { 251 | p.seqID2CallInfo.Delete(seqID) 252 | return v.(*Call), true 253 | } 254 | return nil, false 255 | } 256 | 257 | func (p *Processor) HandleResponse(seqID int32, data []byte) error { 258 | call, ok := p.GetCallWithDel(seqID) 259 | if !ok { 260 | return errors.New("seqID not existed") 261 | } 262 | err := proto.Unmarshal(data, call.resp) 263 | if err != nil { 264 | logrus.WithError(err).Error("HandleRequest") 265 | call.onRecv(err) 266 | return err 267 | } 268 | 269 | call.onRecv(nil) 270 | return nil 271 | } 272 | -------------------------------------------------------------------------------- /rpc/rpc.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "github.com/0990/goserver/service" 5 | "github.com/0990/goserver/util" 6 | "github.com/golang/protobuf/proto" 7 | "github.com/sirupsen/logrus" 8 | "reflect" 9 | "sync" 10 | ) 11 | 12 | type RPC struct { 13 | sync.Mutex 14 | sid2server map[int32]Server 15 | client *Client 16 | serverID int32 17 | worker service.Worker 18 | } 19 | 20 | func NewRPC(serverID int32, worker service.Worker, natsUrl string) (*RPC, error) { 21 | rpcClient, err := newClient(serverID, worker, natsUrl) 22 | if err != nil { 23 | return nil, err 24 | } 25 | p := new(RPC) 26 | p.worker = worker 27 | p.serverID = serverID 28 | p.client = rpcClient 29 | p.sid2server = make(map[int32]Server) 30 | return p, nil 31 | } 32 | 33 | //func (p *RPC) Init(serverID int32, worker service.Worker) error { 34 | // rpcClient, err := newClient(serverID) 35 | // if err != nil { 36 | // return err 37 | // } 38 | // p.worker = worker 39 | // p.serverID = serverID 40 | // p.client = rpcClient 41 | // return nil 42 | //} 43 | 44 | func (p *RPC) Run() { 45 | p.client.Run() 46 | //p.worker.Run() 47 | } 48 | 49 | func (p *RPC) Close() { 50 | p.client.Close() 51 | } 52 | 53 | //func (p *RPC) RegisterServerMsg(msg proto.Message, f ServerMsgHandler) { 54 | // p.client.processor.RegisterMsg(msg, f) 55 | //} 56 | 57 | func (p *RPC) RegisterServerMsgHandler(cb interface{}) { 58 | err, funValue, msgType := util.CheckArgs1MsgFun(cb) 59 | if err != nil { 60 | logrus.WithError(err).Error("RegisterServerMsgHandler") 61 | return 62 | } 63 | msg := reflect.New(msgType).Elem().Interface().(proto.Message) 64 | p.client.processor.RegisterServerMsgHandler(msg, func(s Server, message proto.Message) { 65 | funValue.Call([]reflect.Value{reflect.ValueOf(s), reflect.ValueOf(message)}) 66 | }) 67 | } 68 | 69 | func (p *RPC) RegisterSessionMsgHandler(cb interface{}) { 70 | err, funValue, msgType := util.CheckArgs1MsgFun(cb) 71 | if err != nil { 72 | logrus.WithError(err).Error("RegisterServerMsgHandler") 73 | return 74 | } 75 | msg := reflect.New(msgType).Elem().Interface().(proto.Message) 76 | p.client.processor.RegisterSessionMsgHandler(msg, func(s Session, message proto.Message) { 77 | funValue.Call([]reflect.Value{reflect.ValueOf(s), reflect.ValueOf(message)}) 78 | }) 79 | } 80 | 81 | func (p *RPC) RegisterRequestMsgHandler(cb interface{}) { 82 | err, funValue, msgType := util.CheckArgs1MsgFun(cb) 83 | if err != nil { 84 | logrus.WithError(err).Error("RegisterServerMsgHandler") 85 | return 86 | } 87 | msg := reflect.New(msgType).Elem().Interface().(proto.Message) 88 | p.client.processor.RegisterRequestMsgHandler(msg, func(s RequestServer, message proto.Message) { 89 | funValue.Call([]reflect.Value{reflect.ValueOf(s), reflect.ValueOf(message)}) 90 | }) 91 | } 92 | 93 | func (p *RPC) GetServerById(serverID int32) Server { 94 | p.Lock() 95 | defer p.Unlock() 96 | if v, ok := p.sid2server[serverID]; ok { 97 | return v 98 | } 99 | s := NewServer(p.client, serverID) 100 | p.sid2server[serverID] = s 101 | return s 102 | } 103 | 104 | //TODO add 105 | func (p *RPC) GetServerByType(serverType ServerType) Server { 106 | return nil 107 | } 108 | 109 | func (p *RPC) RegisterSend2Session(send2Session func(sesID int32, msgID uint32, data []byte)) { 110 | p.client.RegisterSend2Session(send2Session) 111 | } 112 | 113 | func (p *RPC) Session(gateID, sesID int32) Session { 114 | return NewSession(p.client, gateID, sesID) 115 | } 116 | -------------------------------------------------------------------------------- /rpc/rpcmsg/rpc.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: rpc/rpcmsg/rpc.proto 3 | 4 | /* 5 | Package rpcmsg is a generated protocol buffer package. 6 | 7 | It is generated from these files: 8 | rpc/rpcmsg/rpc.proto 9 | 10 | It has these top-level messages: 11 | Data 12 | */ 13 | package rpcmsg 14 | 15 | import proto "github.com/golang/protobuf/proto" 16 | import fmt "fmt" 17 | import math "math" 18 | 19 | // Reference imports to suppress errors if they are not otherwise used. 20 | var _ = proto.Marshal 21 | var _ = fmt.Errorf 22 | var _ = math.Inf 23 | 24 | // This is a compile-time assertion to ensure that this generated file 25 | // is compatible with the proto package it is being compiled against. 26 | // A compilation error at this line likely means your copy of the 27 | // proto package needs to be updated. 28 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 29 | 30 | type Data_Type int32 31 | 32 | const ( 33 | Data_Invalid Data_Type = 0 34 | Data_Request Data_Type = 1 35 | Data_Response Data_Type = 2 36 | Data_Session2Server Data_Type = 3 37 | Data_Server2Session Data_Type = 4 38 | Data_Server2Server Data_Type = 5 39 | ) 40 | 41 | var Data_Type_name = map[int32]string{ 42 | 0: "Invalid", 43 | 1: "Request", 44 | 2: "Response", 45 | 3: "Session2Server", 46 | 4: "Server2Session", 47 | 5: "Server2Server", 48 | } 49 | var Data_Type_value = map[string]int32{ 50 | "Invalid": 0, 51 | "Request": 1, 52 | "Response": 2, 53 | "Session2Server": 3, 54 | "Server2Session": 4, 55 | "Server2Server": 5, 56 | } 57 | 58 | func (x Data_Type) String() string { 59 | return proto.EnumName(Data_Type_name, int32(x)) 60 | } 61 | func (Data_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} } 62 | 63 | type Data struct { 64 | Type Data_Type `protobuf:"varint,1,opt,name=type,enum=rpcmsg.Data_Type" json:"type,omitempty"` 65 | Seqid int32 `protobuf:"varint,2,opt,name=seqid" json:"seqid,omitempty"` 66 | Sesid int32 `protobuf:"varint,3,opt,name=sesid" json:"sesid,omitempty"` 67 | Senderid int32 `protobuf:"varint,4,opt,name=senderid" json:"senderid,omitempty"` 68 | Msgid uint32 `protobuf:"varint,5,opt,name=msgid" json:"msgid,omitempty"` 69 | Data []byte `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"` 70 | } 71 | 72 | func (m *Data) Reset() { *m = Data{} } 73 | func (m *Data) String() string { return proto.CompactTextString(m) } 74 | func (*Data) ProtoMessage() {} 75 | func (*Data) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 76 | 77 | func (m *Data) GetType() Data_Type { 78 | if m != nil { 79 | return m.Type 80 | } 81 | return Data_Invalid 82 | } 83 | 84 | func (m *Data) GetSeqid() int32 { 85 | if m != nil { 86 | return m.Seqid 87 | } 88 | return 0 89 | } 90 | 91 | func (m *Data) GetSesid() int32 { 92 | if m != nil { 93 | return m.Sesid 94 | } 95 | return 0 96 | } 97 | 98 | func (m *Data) GetSenderid() int32 { 99 | if m != nil { 100 | return m.Senderid 101 | } 102 | return 0 103 | } 104 | 105 | func (m *Data) GetMsgid() uint32 { 106 | if m != nil { 107 | return m.Msgid 108 | } 109 | return 0 110 | } 111 | 112 | func (m *Data) GetData() []byte { 113 | if m != nil { 114 | return m.Data 115 | } 116 | return nil 117 | } 118 | 119 | func init() { 120 | proto.RegisterType((*Data)(nil), "rpcmsg.Data") 121 | proto.RegisterEnum("rpcmsg.Data_Type", Data_Type_name, Data_Type_value) 122 | } 123 | 124 | func init() { proto.RegisterFile("rpc/rpcmsg/rpc.proto", fileDescriptor0) } 125 | 126 | var fileDescriptor0 = []byte{ 127 | // 236 bytes of a gzipped FileDescriptorProto 128 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x3c, 0x90, 0x41, 0x6a, 0xeb, 0x30, 129 | 0x10, 0x40, 0xbf, 0x1c, 0xd9, 0x3f, 0x4c, 0x93, 0xe0, 0x0c, 0x59, 0x88, 0xae, 0x4c, 0xa0, 0xe0, 130 | 0x95, 0x0b, 0xee, 0x15, 0xba, 0xe9, 0x56, 0xe9, 0x05, 0xd4, 0x68, 0x08, 0x82, 0xc6, 0x56, 0x34, 131 | 0x6a, 0x20, 0x57, 0xe8, 0xa9, 0x8b, 0xa4, 0x36, 0x2b, 0xcd, 0x7b, 0x4f, 0x42, 0x30, 0xb0, 0x0b, 132 | 0xfe, 0xf8, 0x1c, 0xfc, 0xf1, 0xcc, 0xa7, 0x74, 0x0c, 0x3e, 0xcc, 0x71, 0xc6, 0xa6, 0x98, 0xfd, 133 | 0x77, 0x05, 0xf2, 0xd5, 0x44, 0x83, 0x4f, 0x20, 0xe3, 0xcd, 0x93, 0x12, 0x9d, 0xe8, 0x37, 0xe3, 134 | 0x76, 0x28, 0x7d, 0x48, 0x6d, 0x78, 0xbf, 0x79, 0xd2, 0x39, 0xe3, 0x0e, 0x6a, 0xa6, 0x8b, 0xb3, 135 | 0xaa, 0xea, 0x44, 0x5f, 0xeb, 0x02, 0xc5, 0xb2, 0xb3, 0x6a, 0xf1, 0x67, 0xd9, 0x59, 0x7c, 0x84, 136 | 0x25, 0xd3, 0x64, 0x29, 0x38, 0xab, 0x64, 0x0e, 0x77, 0x4e, 0x2f, 0xce, 0x7c, 0x72, 0x56, 0xd5, 137 | 0x9d, 0xe8, 0xd7, 0xba, 0x00, 0x22, 0x48, 0x6b, 0xa2, 0x51, 0x4d, 0x27, 0xfa, 0x95, 0xce, 0xf3, 138 | 0xde, 0x81, 0x4c, 0xff, 0xe3, 0x03, 0xfc, 0x7f, 0x9b, 0xae, 0xe6, 0xd3, 0xd9, 0xf6, 0x5f, 0x02, 139 | 0x4d, 0x97, 0x2f, 0xe2, 0xd8, 0x0a, 0x5c, 0xc1, 0x52, 0x13, 0xfb, 0x79, 0x62, 0x6a, 0x2b, 0x44, 140 | 0xd8, 0x1c, 0x88, 0xd9, 0xcd, 0xd3, 0x78, 0xa0, 0x70, 0xa5, 0xd0, 0x2e, 0x8a, 0x4b, 0xf3, 0xf8, 141 | 0x9b, 0x5a, 0x89, 0x5b, 0x58, 0xdf, 0x5d, 0xbe, 0x56, 0x7f, 0x34, 0x79, 0x37, 0x2f, 0x3f, 0x01, 142 | 0x00, 0x00, 0xff, 0xff, 0xa9, 0x17, 0x9c, 0xe0, 0x33, 0x01, 0x00, 0x00, 143 | } 144 | -------------------------------------------------------------------------------- /rpc/rpcmsg/rpc.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package rpcmsg; 3 | 4 | message Data{ 5 | enum Type{ 6 | Invalid = 0; 7 | Request = 1; 8 | Response = 2; 9 | Session2Server = 3; 10 | Server2Session = 4; 11 | Server2Server = 5; 12 | } 13 | Type type = 1;//数据类型 14 | int32 seqid = 2; //rpc相关时有用 15 | int32 sesid = 3; //ses相关时有用 16 | int32 senderid = 4;//发送方serverid 17 | uint32 msgid = 5; 18 | bytes data = 6; 19 | } -------------------------------------------------------------------------------- /rpc/server.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "fmt" 5 | "github.com/golang/protobuf/proto" 6 | ) 7 | 8 | type ServerType int 9 | 10 | const ( 11 | _ ServerType = iota 12 | Gate 13 | Center 14 | Game 15 | Users 16 | ) 17 | 18 | type Server interface { 19 | Notify(proto.Message) 20 | Call(proto.Message, proto.Message) error 21 | RouteSession2Server(sesID int32, msg proto.Message) 22 | 23 | Request(proto.Message, interface{}) error 24 | 25 | ID() int32 26 | } 27 | 28 | type server struct { 29 | rpcClient *Client 30 | serverid int32 31 | serverTopic string //目标服务器nats的topic,暂为服务器id 32 | } 33 | 34 | func NewServer(client *Client, serverid int32) Server { 35 | return &server{ 36 | rpcClient: client, 37 | serverid: serverid, 38 | serverTopic: fmt.Sprintf("%v", serverid), 39 | } 40 | } 41 | 42 | func (p *server) Notify(msg proto.Message) { 43 | p.rpcClient.SendMsg(p.serverTopic, msg) 44 | } 45 | 46 | func (p *server) ID() int32 { 47 | return p.serverid 48 | } 49 | 50 | func (p *server) Request(msg proto.Message, f interface{}) error { 51 | p.rpcClient.Request(p.serverTopic, msg, f) 52 | return nil 53 | } 54 | 55 | func (p *server) Call(req proto.Message, resp proto.Message) error { 56 | return p.rpcClient.Call(p.serverTopic, req, resp) 57 | } 58 | 59 | //gate服使用较多,把消息路由到对应服务器 60 | func (p *server) RouteSession2Server(sesid int32, msg proto.Message) { 61 | p.rpcClient.RouteSession2Server(p.serverTopic, sesid, msg) 62 | } 63 | 64 | type RequestServer interface { 65 | Answer(proto.Message) 66 | Server 67 | } 68 | 69 | func NewRequestServer(client *Client, serverid int32, seqid int32) RequestServer { 70 | s := &server{ 71 | rpcClient: client, 72 | serverid: serverid, 73 | serverTopic: fmt.Sprintf("%v", serverid), 74 | } 75 | return &requestserver{ 76 | server: s, 77 | seqid: seqid, 78 | } 79 | } 80 | 81 | type requestserver struct { 82 | *server 83 | seqid int32 84 | } 85 | 86 | func (p *requestserver) Answer(msg proto.Message) { 87 | p.server.rpcClient.Answer(p.serverTopic, p.seqid, msg) 88 | } 89 | 90 | func (p *requestserver) ID() int32 { 91 | return p.serverid 92 | } 93 | 94 | type Session interface { 95 | SendMsg(msg proto.Message) 96 | SendRawMsg(msgID uint16, data []byte) 97 | GateSessionID() GateSessionID 98 | } 99 | 100 | type GateSessionID struct { 101 | GateID int32 102 | SesID int32 103 | } 104 | 105 | type session struct { 106 | gsID GateSessionID 107 | rpcClient *Client 108 | gateTopic string 109 | } 110 | 111 | func NewSession(client *Client, gateID int32, sesID int32) Session { 112 | g := GateSessionID{GateID: gateID, SesID: sesID} 113 | 114 | return &session{ 115 | gsID: g, 116 | rpcClient: client, 117 | gateTopic: fmt.Sprintf("%v", gateID), 118 | } 119 | } 120 | 121 | func (p *session) SendMsg(msg proto.Message) { 122 | p.rpcClient.RouteGate(p.gateTopic, p.gsID.SesID, msg) 123 | } 124 | 125 | func (p *session) SendRawMsg(msgID uint16, data []byte) { 126 | 127 | } 128 | 129 | func (p *session) GateSessionID() GateSessionID { 130 | return p.gsID 131 | } 132 | -------------------------------------------------------------------------------- /rpc/util.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "github.com/0990/goserver/rpc/rpcmsg" 5 | "github.com/0990/goserver/util" 6 | "github.com/golang/protobuf/proto" 7 | ) 8 | 9 | func MakeRequestData(msg proto.Message, seqID int32, senderID int32) []byte { 10 | msgID, _ := util.ProtoHash(msg) 11 | msgData, _ := proto.Marshal(msg) 12 | rpc := &rpcmsg.Data{ 13 | Type: rpcmsg.Data_Request, 14 | Msgid: msgID, 15 | Seqid: seqID, 16 | Senderid: senderID, 17 | Data: msgData, 18 | } 19 | 20 | data, _ := proto.Marshal(rpc) 21 | return data 22 | } 23 | 24 | func MakeServer2ServerData(msg proto.Message, senderID int32) []byte { 25 | msgID, _ := util.ProtoHash(msg) 26 | msgData, _ := proto.Marshal(msg) 27 | rpc := &rpcmsg.Data{ 28 | Type: rpcmsg.Data_Server2Server, 29 | Msgid: msgID, 30 | Senderid: senderID, 31 | Data: msgData, 32 | } 33 | 34 | data, _ := proto.Marshal(rpc) 35 | return data 36 | } 37 | 38 | func MakeResponseData(msg proto.Message, seqID int32, senderID int32) []byte { 39 | msgID, _ := util.ProtoHash(msg) 40 | msgData, _ := proto.Marshal(msg) 41 | rpc := &rpcmsg.Data{ 42 | Type: rpcmsg.Data_Response, 43 | Msgid: msgID, 44 | Senderid: senderID, 45 | Data: msgData, 46 | Seqid: seqID, 47 | } 48 | 49 | data, _ := proto.Marshal(rpc) 50 | return data 51 | } 52 | 53 | func MakeServer2SessionData(msg proto.Message, sesID int32, senderID int32) []byte { 54 | msgID, _ := util.ProtoHash(msg) 55 | msgData, _ := proto.Marshal(msg) 56 | rpc := &rpcmsg.Data{ 57 | Type: rpcmsg.Data_Server2Session, 58 | Msgid: msgID, 59 | Senderid: senderID, 60 | Data: msgData, 61 | Sesid: sesID, 62 | } 63 | 64 | data, _ := proto.Marshal(rpc) 65 | return data 66 | } 67 | 68 | func MakeSession2ServerData(msg proto.Message, sesID int32, senderID int32) []byte { 69 | msgID, _ := util.ProtoHash(msg) 70 | msgData, _ := proto.Marshal(msg) 71 | rpc := &rpcmsg.Data{ 72 | Type: rpcmsg.Data_Session2Server, 73 | Msgid: msgID, 74 | Senderid: senderID, 75 | Data: msgData, 76 | Sesid: sesID, 77 | } 78 | 79 | data, _ := proto.Marshal(rpc) 80 | return data 81 | } 82 | -------------------------------------------------------------------------------- /server/gate.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "github.com/0990/goserver" 5 | "github.com/0990/goserver/network" 6 | "github.com/0990/goserver/rpc" 7 | "github.com/0990/goserver/service" 8 | "github.com/golang/protobuf/proto" 9 | "time" 10 | ) 11 | 12 | type Gate struct { 13 | worker service.Worker 14 | rpc *rpc.RPC 15 | networkMgr *network.Mgr 16 | onCloseFuns []func() 17 | } 18 | 19 | func NewGate(serverID int32, addr string, config goserver.Config) (*Gate, error) { 20 | p := new(Gate) 21 | p.worker = service.NewWorker() 22 | p.networkMgr = network.NewMgr(addr, p.worker) 23 | rpc, err := rpc.NewRPC(serverID, p.worker, config.Nats) 24 | if err != nil { 25 | return nil, err 26 | } 27 | p.rpc = rpc 28 | p.rpc.RegisterSend2Session(func(sesID int32, msgID uint32, data []byte) { 29 | if ses, ok := p.GetSession(sesID); ok { 30 | ses.SendRawMsg(msgID, data) 31 | } 32 | }) 33 | return p, nil 34 | } 35 | 36 | //TODO 添加关闭信号 37 | func (p *Gate) Run() { 38 | p.worker.Run() 39 | p.rpc.Run() 40 | p.networkMgr.Run() 41 | } 42 | 43 | func (p *Gate) Close() { 44 | for _, v := range p.onCloseFuns { 45 | v() 46 | } 47 | p.rpc.Close() 48 | p.worker.Close() 49 | } 50 | 51 | //注册关闭事件 worker线程外 52 | func (p *Gate) RegisterCloseFunc(f func()) { 53 | p.onCloseFuns = append(p.onCloseFuns, f) 54 | } 55 | 56 | func (p *Gate) Post(f func()) { 57 | p.worker.Post(f) 58 | } 59 | 60 | func (p *Gate) AfterPost(duration time.Duration, f func()) { 61 | p.worker.AfterPost(duration, f) 62 | } 63 | 64 | func (p *Gate) RegisterNetWorkEvent(onNew, onClose func(conn network.Session)) { 65 | p.networkMgr.RegisterEvent(onNew, onClose) 66 | } 67 | 68 | func (p *Gate) RegisterSessionMsgHandler(cb interface{}) { 69 | p.networkMgr.RegisterSessionMsgHandler(cb) 70 | } 71 | 72 | func (p *Gate) RegisterRequestMsgHandler(cb interface{}) { 73 | p.rpc.RegisterRequestMsgHandler(cb) 74 | } 75 | 76 | func (p *Gate) RegisterServerHandler(cb interface{}) { 77 | p.rpc.RegisterServerMsgHandler(cb) 78 | } 79 | 80 | func (p *Gate) GetServerById(serverID int32) rpc.Server { 81 | return p.rpc.GetServerById(serverID) 82 | } 83 | 84 | func (p *Gate) GetSession(sesID int32) (network.Session, bool) { 85 | return p.networkMgr.GetSession(sesID) 86 | } 87 | 88 | func (p *Gate) RouteSessionMsg(msg proto.Message, serverID int32) { 89 | p.networkMgr.RegisterRawSessionMsgHandler(msg, func(s network.Session, msg proto.Message) { 90 | p.GetServerById(serverID).RouteSession2Server(s.ID(), msg) 91 | }) 92 | } 93 | 94 | func (p *Gate) RegisterRawSessionMsgHandler(msg proto.Message, f func(s network.Session, message proto.Message)) { 95 | p.networkMgr.RegisterRawSessionMsgHandler(msg, f) 96 | } 97 | -------------------------------------------------------------------------------- /server/server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "github.com/0990/goserver" 5 | "github.com/0990/goserver/rpc" 6 | "github.com/0990/goserver/service" 7 | ) 8 | 9 | type Server struct { 10 | worker service.Worker 11 | rpc *rpc.RPC 12 | serverID int32 13 | } 14 | 15 | func NewServer(serverID int32, config goserver.Config) (*Server, error) { 16 | p := new(Server) 17 | p.worker = service.NewWorker() 18 | rpc, err := rpc.NewRPC(serverID, p.worker, config.Nats) 19 | if err != nil { 20 | return nil, err 21 | } 22 | p.rpc = rpc 23 | p.serverID = serverID 24 | return p, nil 25 | } 26 | 27 | //TODO 添加关闭信号 28 | func (p *Server) Run() { 29 | p.worker.Run() 30 | p.rpc.Run() 31 | } 32 | 33 | func (p *Server) Worker() service.Worker { 34 | return p.worker 35 | } 36 | 37 | func (p *Server) Post(f func()) { 38 | p.worker.Post(f) 39 | } 40 | 41 | func (p *Server) RegisterRequestMsgHandler(cb interface{}) { 42 | p.rpc.RegisterRequestMsgHandler(cb) 43 | } 44 | 45 | func (p *Server) GetServerById(serverID int32) rpc.Server { 46 | return p.rpc.GetServerById(serverID) 47 | } 48 | 49 | // 50 | //func (p *Server) RegisterServerMsg(msg proto.Message, f func(rpc.Server, proto.Message)) { 51 | // p.rpc.RegisterServerMsg(msg, f) 52 | //} 53 | 54 | func (p *Server) RegisterSessionMsgHandler(cb interface{}) { 55 | p.rpc.RegisterSessionMsgHandler(cb) 56 | } 57 | 58 | func (p *Server) RegisterServerHandler(cb interface{}) { 59 | p.rpc.RegisterServerMsgHandler(cb) 60 | } 61 | 62 | func (p *Server) ID() int32 { 63 | return p.serverID 64 | } 65 | 66 | func (p *Server) RPCSession(s rpc.GateSessionID) rpc.Session { 67 | return p.rpc.Session(s.GateID, s.SesID) 68 | } 69 | -------------------------------------------------------------------------------- /service/ticker.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import "time" 4 | 5 | type workTicker struct { 6 | done chan struct{} 7 | worker Worker 8 | duration time.Duration 9 | f func() 10 | } 11 | 12 | func newWorkTicker(worker Worker, d time.Duration, f func()) *workTicker { 13 | return &workTicker{ 14 | done: make(chan struct{}, 1), 15 | worker: worker, 16 | duration: d, 17 | f: f, 18 | } 19 | } 20 | 21 | func (p *workTicker) run() { 22 | go func() { 23 | ticker := time.NewTicker(p.duration) 24 | defer ticker.Stop() 25 | for { 26 | select { 27 | case <-ticker.C: 28 | p.worker.Post(p.f) 29 | case <-p.done: 30 | return 31 | } 32 | } 33 | }() 34 | } 35 | 36 | func (p *workTicker) Close() error { 37 | close(p.done) 38 | return nil 39 | } 40 | -------------------------------------------------------------------------------- /service/worker.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/0990/goserver/util" 5 | "github.com/sirupsen/logrus" 6 | "io" 7 | "runtime/debug" 8 | "sync/atomic" 9 | "time" 10 | ) 11 | 12 | type Worker interface { 13 | Post(f func()) 14 | Run() 15 | Close() 16 | AfterPost(duration time.Duration, f func()) *time.Timer 17 | NewTicker(d time.Duration, f func()) io.Closer 18 | Len() int 19 | } 20 | 21 | //TODO 这里的实现 chan如果塞满会阻塞进程,可对比参照github.com/davyxu/cellnet EventQueue实现,选方案 22 | type Work struct { 23 | funChan chan func() 24 | 25 | closed int32 26 | } 27 | 28 | func NewWorker() Worker { 29 | p := new(Work) 30 | p.funChan = make(chan func(), 10240) 31 | return p 32 | } 33 | 34 | func (p *Work) Post(f func()) { 35 | if atomic.LoadInt32(&p.closed) == 0 { 36 | p.funChan <- f 37 | } 38 | } 39 | 40 | func (p *Work) TryPost(f func(), maxLen int) { 41 | if maxLen != 0 && len(p.funChan) > maxLen { 42 | logrus.WithFields(logrus.Fields{ 43 | "maxLen": maxLen, 44 | "workerLen": len(p.funChan), 45 | }).Warn("tryPost over maxLen") 46 | return 47 | } 48 | 49 | select { 50 | case p.funChan <- f: 51 | default: 52 | logrus.WithFields(logrus.Fields{ 53 | "workerLen": len(p.funChan), 54 | }).Warn("worker tryPost,discard") 55 | } 56 | } 57 | 58 | func (p *Work) Run() { 59 | go func() { 60 | for f := range p.funChan { 61 | util.ProtectedFun(f) 62 | } 63 | }() 64 | } 65 | 66 | func (p *Work) Close() { 67 | if atomic.CompareAndSwapInt32(&p.closed, 0, 1) { 68 | close(p.funChan) 69 | } 70 | } 71 | 72 | func (p *Work) Len() int { 73 | return len(p.funChan) 74 | } 75 | func (p *Work) protectedFun(callback func()) { 76 | //TODO 每个函数都包装了defer,性能怎样? 77 | defer func() { 78 | if err := recover(); err != nil { 79 | debug.PrintStack() 80 | } 81 | }() 82 | callback() 83 | } 84 | 85 | func (p *Work) AfterPost(d time.Duration, f func()) *time.Timer { 86 | return time.AfterFunc(d, func() { 87 | p.Post(f) 88 | }) 89 | } 90 | 91 | func (p *Work) NewTicker(d time.Duration, f func()) io.Closer { 92 | t := newWorkTicker(p, d, f) 93 | t.run() 94 | return t 95 | } 96 | 97 | //worker长度超过maxLen就丢弃f 98 | func (p *Work) NewTryTicker(d time.Duration, maxLen int, f func()) *time.Ticker { 99 | ticker := time.NewTicker(d) 100 | go func() { 101 | for range ticker.C { 102 | p.TryPost(f, maxLen) 103 | } 104 | }() 105 | return ticker 106 | } 107 | -------------------------------------------------------------------------------- /util/fun.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "runtime/debug" 4 | 5 | func ProtectedFun(f func()) { 6 | //TODO 每个函数都包装了defer,性能怎样? 7 | defer func() { 8 | if err := recover(); err != nil { 9 | debug.PrintStack() 10 | } 11 | }() 12 | f() 13 | } 14 | -------------------------------------------------------------------------------- /util/goutine.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "bytes" 5 | "runtime" 6 | "strconv" 7 | ) 8 | 9 | func GetGoroutineID() uint64 { 10 | b := make([]byte, 64) 11 | b = b[:runtime.Stack(b, false)] 12 | b = bytes.TrimPrefix(b, []byte("goroutine ")) 13 | b = b[:bytes.IndexByte(b, ' ')] 14 | n, _ := strconv.ParseUint(string(b), 10, 64) 15 | return n 16 | } 17 | -------------------------------------------------------------------------------- /util/print.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func PrintCurrNano(title string) { 9 | fmt.Println(title, ":", time.Now().UnixNano()/1000, time.Now().Unix()) 10 | } 11 | 12 | func PrintGoroutineID(title string) { 13 | fmt.Println(title, "goroutineID:", GetGoroutineID()) 14 | } 15 | -------------------------------------------------------------------------------- /util/protobuf.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "github.com/golang/protobuf/proto" 5 | "reflect" 6 | ) 7 | 8 | //TODO 比较msgType.String()和msgType.Elem().Name()区别 9 | //func ProtoHash(msg proto.Message) (uint16, reflect.Type) { 10 | // msgType := reflect.TypeOf(msg) 11 | // return StringHash(msgType.String()), reflect.TypeOf(msg) 12 | //} 13 | 14 | func ProtoHash(msg proto.Message) (uint32, reflect.Type) { 15 | //msgType := reflect.TypeOf(msg) 16 | msgName := proto.MessageName(msg) 17 | return CRC32Hash(msgName), reflect.TypeOf(msg) 18 | } 19 | -------------------------------------------------------------------------------- /util/reflect.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "errors" 5 | "reflect" 6 | ) 7 | 8 | //检查形如 func(args0 xx,args1 proto.Message)这种的func 9 | func CheckArgs1MsgFun(cb interface{}) (err error, funValue reflect.Value, msgType reflect.Type) { 10 | cbType := reflect.TypeOf(cb) 11 | if cbType.Kind() != reflect.Func { 12 | err = errors.New("cb not a func") 13 | return 14 | } 15 | 16 | numArgs := cbType.NumIn() 17 | if numArgs != 2 { 18 | err = errors.New("cb param num args !=2") 19 | return 20 | } 21 | 22 | //TODO 严格检查参数类型 23 | //args0 := cbType.In(0) 24 | msgType = cbType.In(1) 25 | if msgType.Kind() != reflect.Ptr { 26 | err = errors.New("cb param args1 not ptr") 27 | return 28 | } 29 | 30 | funValue = reflect.ValueOf(cb) 31 | return 32 | } 33 | -------------------------------------------------------------------------------- /util/string.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "hash/crc32" 4 | 5 | // 字符串转为16位整形哈希 6 | func StringHash(s string) (hash uint16) { 7 | for _, c := range s { 8 | 9 | ch := uint16(c) 10 | 11 | hash = hash + ((hash) << 5) + ch + (ch << 7) 12 | } 13 | 14 | return 15 | } 16 | 17 | func CRC32Hash(s string) uint32 { 18 | return crc32.ChecksumIEEE([]byte(s)) 19 | } 20 | --------------------------------------------------------------------------------