├── .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 | 
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 |
--------------------------------------------------------------------------------