├── .idea
├── .gitignore
├── deployment.xml
├── go-gateway.iml
├── modules.xml
├── sshConfigs.xml
├── vcs.xml
└── webServers.xml
├── README.md
├── app
└── MainEvent.go
├── config.yaml
├── go.mod
├── go.sum
├── lib
├── Config.go
├── Gateway.go
├── GatewayProtocol.go
├── Interface.go
├── gateway
│ ├── ConnectionGroup.go
│ ├── RegisterEvent.go
│ ├── WebSocketEvent.go
│ ├── WorkerEvent.go
│ └── WorkerHandle.go
├── register
│ └── RegisterEvent.go
└── worker
│ ├── GatewayEvent.go
│ ├── GatewayHandle.go
│ └── RegisterEvent.go
├── main.go
├── network
├── Func.go
├── Interface.go
├── Url.go
├── error
│ └── Errors.go
├── protocol
│ ├── PackageLenProtocol.go
│ ├── TextProtocol.go
│ ├── WsClientProtocol.go
│ ├── WstServerProtocol.go
│ └── lib
│ │ └── Header.go
├── tcp
│ ├── Build.go
│ ├── Client.go
│ ├── Connect.go
│ ├── ConnectTcp.go
│ ├── Listen.go
│ └── Server.go
└── tcpclient
│ └── Tcpclient.go
├── register.log
└── utils
├── Config.go
└── Process.go
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # 默认忽略的文件
2 | /shelf/
3 | /workspace.xml
4 | # 基于编辑器的 HTTP 客户端请求
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/deployment.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/go-gateway.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/sshConfigs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/webServers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # go-gateway
2 | go实现的长链接网关,可以运用于im或者游戏服务等开发
3 | 
4 |
--------------------------------------------------------------------------------
/app/MainEvent.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "goworker/lib"
5 | "log"
6 | )
7 |
8 | // MainEvent 此文件实现自己的业务逻辑
9 | type MainEvent struct {
10 | }
11 |
12 | func (*MainEvent) OnWebSocketConnect(clientId string, header []byte) {
13 | }
14 |
15 | func (*MainEvent) OnStart() {
16 | log.Println("OnStart ")
17 | }
18 |
19 | func (*MainEvent) OnConnect(clientId string) {
20 | log.Println("OnConnect ", clientId)
21 | }
22 |
23 | func (*MainEvent) OnMessage(clientId string, body []byte) {
24 | log.Println("OnMessage ", clientId, string(body))
25 | lib.SendToAll([]byte(clientId + "中文"))
26 | }
27 |
28 | func (*MainEvent) OnClose(clientId string) {
29 | log.Println("OnClose ", clientId)
30 | }
31 |
--------------------------------------------------------------------------------
/config.yaml:
--------------------------------------------------------------------------------
1 | # 调试模式
2 | debug: true
3 | # 网关地址websocket 对外暴露
4 | gateway: "0.0.0.0:7272"
5 | # 内部通讯地址 Gateway所在服务器的内网IP 本机ip,分布式部署时使用内网ip
6 | gatewayInternal: "127.0.0.1:7273"
7 | # 注册中心
8 | register: "127.0.0.1:7274"
9 | # 通讯秘钥
10 | secret: ""
11 |
12 |
13 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module goworker
2 |
3 | go 1.19
4 |
5 | require (
6 | github.com/fsnotify/fsnotify v1.6.0
7 | github.com/gogf/gf v1.16.9
8 | github.com/spf13/viper v1.7.0
9 | )
10 |
11 | require (
12 | github.com/hashicorp/hcl v1.0.0 // indirect
13 | github.com/magiconair/properties v1.8.1 // indirect
14 | github.com/mitchellh/mapstructure v1.1.2 // indirect
15 | github.com/pelletier/go-toml v1.2.0 // indirect
16 | github.com/spf13/afero v1.1.2 // indirect
17 | github.com/spf13/cast v1.3.0 // indirect
18 | github.com/spf13/jwalterweatherman v1.0.0 // indirect
19 | github.com/spf13/pflag v1.0.3 // indirect
20 | github.com/subosito/gotenv v1.2.0 // indirect
21 | golang.org/x/sys v0.0.0-20220908164124-27713097b956 // indirect
22 | golang.org/x/text v0.3.6 // indirect
23 | gopkg.in/ini.v1 v1.51.0 // indirect
24 | gopkg.in/yaml.v2 v2.2.4 // indirect
25 | )
26 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
8 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
9 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
10 | cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
11 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
12 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
13 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
14 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
15 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
16 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
17 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
18 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
19 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
20 | github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
21 | github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
22 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
23 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
24 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
25 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
26 | github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
27 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
28 | github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 h1:LdXxtjzvZYhhUaonAaAKArG3pyC67kGL3YY+6hGG8G4=
29 | github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
30 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
31 | github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
32 | github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
33 | github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
34 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
35 | github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
36 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
37 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
38 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
39 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
40 | github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
41 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
42 | github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
43 | github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
44 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
45 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
46 | github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
47 | github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
48 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
49 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
50 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
51 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
52 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
53 | github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
54 | github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
55 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
56 | github.com/gogf/gf v1.16.9 h1:Q803UmmRo59+Ws08sMVFOcd8oNpkSWL9vS33hlo/Cyk=
57 | github.com/gogf/gf v1.16.9/go.mod h1:8Q/kw05nlVRp+4vv7XASBsMe9L1tsVKiGoeP2AHnlkk=
58 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
59 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
60 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
61 | github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
62 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
63 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
64 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
65 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
66 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
67 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
68 | github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc=
69 | github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
70 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
71 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
72 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
73 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
74 | github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
75 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
76 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
77 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
78 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
79 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
80 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
81 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
82 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
83 | github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
84 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
85 | github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0=
86 | github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
87 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
88 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
89 | github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
90 | github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
91 | github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
92 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
93 | github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
94 | github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
95 | github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
96 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
97 | github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
98 | github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
99 | github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
100 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
101 | github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
102 | github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
103 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
104 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
105 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
106 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
107 | github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
108 | github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
109 | github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
110 | github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
111 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
112 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
113 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
114 | github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
115 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
116 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
117 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
118 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
119 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
120 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
121 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
122 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
123 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
124 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
125 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
126 | github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
127 | github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
128 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
129 | github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
130 | github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
131 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
132 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
133 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
134 | github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
135 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
136 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
137 | github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
138 | github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
139 | github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
140 | github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
141 | github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
142 | github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
143 | github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
144 | github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
145 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
146 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
147 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
148 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
149 | github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
150 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
151 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
152 | github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
153 | github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
154 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
155 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
156 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
157 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
158 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
159 | github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
160 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
161 | github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
162 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
163 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
164 | github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
165 | github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
166 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
167 | github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
168 | github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
169 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
170 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
171 | github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
172 | github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
173 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
174 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
175 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
176 | github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
177 | github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
178 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
179 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
180 | github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
181 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
182 | github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
183 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
184 | github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
185 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
186 | github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
187 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
188 | github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
189 | github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
190 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
191 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
192 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
193 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
194 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
195 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
196 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
197 | github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
198 | github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
199 | github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
200 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
201 | go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
202 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
203 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
204 | go.opentelemetry.io/otel v1.0.0 h1:qTTn6x71GVBvoafHK/yaRUmFzI4LcONZD0/kXxl5PHI=
205 | go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg=
206 | go.opentelemetry.io/otel/trace v1.0.0 h1:TSBr8GTEtKevYMG/2d21M989r5WJYVimhTHBKVEZuh4=
207 | go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs=
208 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
209 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
210 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
211 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
212 | golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
213 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
214 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
215 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
216 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
217 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
218 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
219 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
220 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
221 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
222 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
223 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
224 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
225 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
226 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
227 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
228 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
229 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
230 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
231 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
232 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
233 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
234 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
235 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
236 | golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
237 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
238 | golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
239 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
240 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
241 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
242 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
243 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
244 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
245 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
246 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
247 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
248 | golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE=
249 | golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
250 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
251 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
252 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
253 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
254 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
255 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
256 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
257 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
258 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
259 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
260 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
261 | golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
262 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
263 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
264 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
265 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
266 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
267 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
268 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
269 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
270 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
271 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
272 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
273 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
274 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
275 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
276 | golang.org/x/sys v0.0.0-20220908164124-27713097b956 h1:XeJjHH1KiLpKGb6lvMiksZ9l0fVUh+AmGcm0nOMEBOY=
277 | golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
278 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
279 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
280 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
281 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
282 | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
283 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
284 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
285 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
286 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
287 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
288 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
289 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
290 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
291 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
292 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
293 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
294 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
295 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
296 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
297 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
298 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
299 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
300 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
301 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
302 | golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
303 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
304 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
305 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
306 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
307 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
308 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
309 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
310 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
311 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
312 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
313 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
314 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
315 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
316 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
317 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
318 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
319 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
320 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
321 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
322 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
323 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
324 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
325 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
326 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
327 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
328 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
329 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
330 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
331 | gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
332 | gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
333 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
334 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
335 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
336 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
337 | gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
338 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
339 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
340 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
341 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
342 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
343 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
344 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
345 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
346 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
347 |
--------------------------------------------------------------------------------
/lib/Config.go:
--------------------------------------------------------------------------------
1 | package lib
2 |
3 | import (
4 | "goworker/network"
5 | c "goworker/utils"
6 | )
7 |
8 | var BussinessEvent LogicEvent
9 |
10 | var Config = config{}
11 |
12 | type config struct {
13 | Gateway *network.Url // 网关对外暴露的
14 | Worker *network.Url // 网关对内业务处理(内部通讯)地址
15 | Register *network.Url // 注册中心
16 | SecretKey string
17 | }
18 |
19 | func (self *config) SetInput() {
20 |
21 | if c.GlobalConfig.Register != "" {
22 | self.Register = network.NewUrl("text://" + c.GlobalConfig.Register)
23 | }
24 |
25 | if c.GlobalConfig.Gateway != "" {
26 | self.Gateway = network.NewUrl("ws://" + c.GlobalConfig.Gateway)
27 | }
28 |
29 | if c.GlobalConfig.GatewayInternal != "" {
30 | self.Worker = network.NewUrl("pack://" + c.GlobalConfig.GatewayInternal)
31 | }
32 |
33 | self.SecretKey = c.GlobalConfig.Secret
34 | }
35 |
--------------------------------------------------------------------------------
/lib/Gateway.go:
--------------------------------------------------------------------------------
1 | package lib
2 |
3 | import (
4 | "encoding/json"
5 | "errors"
6 | "goworker/network"
7 | "goworker/network/tcpclient"
8 | "strconv"
9 | "strings"
10 | "sync"
11 | "sync/atomic"
12 | )
13 |
14 | var GatewayList = &gatewayList{
15 | GatewayCons: map[string]network.Connect{},
16 | //worker进程主动推送进程
17 | ConnectionPool: map[string]tcpclient.Client{},
18 | }
19 |
20 | var emptyGatewayMessage = GatewayMessage{
21 | PackageLen: 0,
22 | Cmd: 0,
23 | LocalIp: 0,
24 | LocalPort: 0,
25 | ClientIp: 0,
26 | ClientPort: 0,
27 | ConnectionId: 0,
28 | Flag: 1,
29 | GatewayPort: 0,
30 | ExtLen: 0,
31 | ExtData: "",
32 | Body: []byte(""),
33 | }
34 |
35 | type gatewayList struct {
36 | GatewayCons map[string]network.Connect
37 | ConnectionPool map[string]tcpclient.Client
38 | }
39 |
40 | func (g *gatewayList) SendToGateway(address string, msg GatewayMessage) error {
41 | con, ok := g.GatewayCons[address]
42 | msg.PackageLen = 28 + uint32(len(msg.Body))
43 | if ok {
44 | msgByte := GatewayMessageToByte(msg)
45 | return con.SendByte(msgByte)
46 | }
47 | return errors.New("无效的链接")
48 | }
49 |
50 | func (g *gatewayList) SendToGatewayByClientId(clientId string, msg GatewayMessage) error {
51 | ip, port, id := network.DecodeBin2hex(clientId)
52 | msg.ConnectionId = id
53 | address := network.Long2Ip(ip) + ":" + strconv.Itoa(int(port))
54 | return GatewayList.SendToGateway(address, msg)
55 | }
56 |
57 | func (g *gatewayList) SendAndRecvByClientId(clientId string, msg GatewayMessage) ([]byte, error) {
58 | ip, port, id := network.DecodeBin2hex(clientId)
59 | msg.ConnectionId = id
60 | address := network.Long2Ip(ip) + ":" + strconv.Itoa(int(port))
61 | return GatewayList.SendAndRecv(address, msg)
62 | }
63 |
64 | // SendAndRecv 发送数据并返回 ,这里不能复用上面的链接
65 | func (g *gatewayList) SendAndRecv(address string, msg GatewayMessage) ([]byte, error) {
66 | msg.PackageLen = 28 + uint32(len(msg.Body))
67 | msgByte := GatewayMessageToByte(msg)
68 | if client, ok := g.ConnectionPool[address]; ok {
69 | return client.Send(msgByte)
70 | }
71 | return nil, errors.New("链接不存在")
72 | }
73 |
74 | // SendToAllGatewayAndRecv 批量发送请求
75 | func (g *gatewayList) SendToAllGatewayAndRecv(msg GatewayMessage, call func(addr string, data []byte) error) (err error) {
76 | var wg sync.WaitGroup
77 | var reMap map[string][]byte
78 | for addr, _ := range GatewayList.GatewayCons {
79 | wg.Add(1)
80 | addr := addr
81 | go func() {
82 | var reData []byte
83 | reData, err = GatewayList.SendAndRecv(addr, msg)
84 | reMap[addr] = reData
85 | defer wg.Done()
86 | }()
87 | }
88 | wg.Wait()
89 | if err != nil {
90 | return err
91 | }
92 | for addr, data := range reMap {
93 | err := call(addr, data)
94 | if err != nil {
95 | return err
96 | }
97 | }
98 | return nil
99 | }
100 |
101 | func (g *gatewayList) SendToAllGateway(msg GatewayMessage) error {
102 | msg.PackageLen = 28 + uint32(len(msg.Body))
103 | msgByte := GatewayMessageToByte(msg)
104 | for _, con := range g.GatewayCons {
105 | err := con.SendByte(msgByte)
106 | if err != nil {
107 | return err
108 | }
109 | }
110 | return nil
111 | }
112 |
113 | func ToClientId(addr, cid string) (string, error) {
114 | contInt, err := strconv.Atoi(cid)
115 | if err != nil {
116 | return "", err
117 | }
118 | addrSplit := strings.Split(addr, ":")
119 | if len(addrSplit) != 2 {
120 | return "", errors.New("数据解析错误")
121 | }
122 | ipInt, err := strconv.Atoi(addrSplit[0])
123 | if err != nil {
124 | return "", err
125 | }
126 | portInt, err := strconv.Atoi(addrSplit[1])
127 | if err != nil {
128 | return "", err
129 | }
130 | return network.Bin2hex(uint32(ipInt), uint16(portInt), uint32(contInt)), nil
131 | }
132 |
133 | // SendToAll 发送消息给所有网关(用户)
134 | func SendToAll(body []byte) error {
135 | msg := emptyGatewayMessage
136 | msg.Cmd = CMD_SEND_TO_ALL
137 | msg.Body = body
138 | return GatewayList.SendToAllGateway(msg)
139 | }
140 |
141 | // SendToClient 向客户端client_id发送数据
142 | func SendToClient(clientId string, body []byte) error {
143 | msg := emptyGatewayMessage
144 | msg.Cmd = CMD_SEND_TO_ONE
145 | msg.Body = body
146 | return GatewayList.SendToGatewayByClientId(clientId, msg)
147 | }
148 |
149 | // CloseClient 断开与client_id对应的客户端的连接
150 | func CloseClient(clientId string) error {
151 | msg := emptyGatewayMessage
152 | msg.Cmd = CMD_KICK
153 | return GatewayList.SendToGatewayByClientId(clientId, msg)
154 | }
155 |
156 | // IsOnline 判断设备是否有设备在线
157 | func IsOnline(clientId string) (bool, error) {
158 | msg := emptyGatewayMessage
159 | msg.Cmd = CMD_IS_ONLINE
160 | recv, err := GatewayList.SendAndRecvByClientId(clientId, msg)
161 | if err != nil {
162 | return false, err
163 | }
164 | var isOnlineMap map[string]bool
165 | err = json.Unmarshal(recv, &isOnlineMap)
166 | if err != nil {
167 | return false, err
168 | }
169 | return isOnlineMap["isOnline"], nil
170 | }
171 |
172 | func BindUid(clientId, uid string) error {
173 | msg := emptyGatewayMessage
174 | msg.Cmd = CMD_BIND_UID
175 | msg.ExtData = uid
176 | return GatewayList.SendToGatewayByClientId(clientId, msg)
177 | }
178 |
179 | func UnBindUid(clientId, uid string) error {
180 | msg := emptyGatewayMessage
181 | msg.Cmd = CMD_UNBIND_UID
182 | msg.ExtData = uid
183 | return GatewayList.SendToGatewayByClientId(clientId, msg)
184 | }
185 |
186 | // IsUidOnline 判断用户是否有设备在线
187 | func IsUidOnline(uid string) (bool, error) {
188 | uids, err := GetClientIdByUid(uid)
189 | if err != nil {
190 | return false, err
191 | }
192 | if len(uids) > 0 {
193 | return true, nil
194 | }
195 | return false, nil
196 | }
197 |
198 | func GetClientIdByUid(uid string) ([]string, error) {
199 | msg := emptyGatewayMessage
200 | msg.Cmd = CMD_GET_CLIENT_ID_BY_UID
201 | msg.ExtData = uid
202 | var uids []string
203 | err := GatewayList.SendToAllGatewayAndRecv(msg, func(addr string, data []byte) error {
204 | clientId, err := ToClientId(addr, string(data))
205 | if err != nil {
206 | return err
207 | }
208 | uids = append(uids, clientId)
209 | return nil
210 | })
211 | return uids, err
212 | }
213 |
214 | func SendToUid(uid string, body []byte) error {
215 | msg := emptyGatewayMessage
216 | msg.Cmd = CMD_SEND_TO_UID
217 | msg.Body = body
218 | msg.ExtData = uid
219 | return GatewayList.SendToAllGateway(msg)
220 | }
221 |
222 | func JoinGroup(clientId, group string) error {
223 | msg := emptyGatewayMessage
224 | msg.Cmd = CMD_JOIN_GROUP
225 | msg.ExtData = group
226 | return GatewayList.SendToGatewayByClientId(clientId, msg)
227 | }
228 |
229 | func LeaveGroup(clientId, group string) error {
230 | msg := emptyGatewayMessage
231 | msg.Cmd = CMD_LEAVE_GROUP
232 | msg.ExtData = group
233 | return GatewayList.SendToGatewayByClientId(clientId, msg)
234 | }
235 |
236 | func Ungroup(group string) error {
237 | msg := emptyGatewayMessage
238 | msg.Cmd = CMD_UNGROUP
239 | msg.ExtData = group
240 | return GatewayList.SendToAllGateway(msg)
241 | }
242 |
243 | func SendToGroup(group string, body []byte) error {
244 | msg := emptyGatewayMessage
245 | msg.Cmd = CMD_SEND_TO_GROUP
246 | msg.Body = body
247 | msg.ExtData = group
248 | return GatewayList.SendToAllGateway(msg)
249 | }
250 |
251 | func GetClientCountByGroup(group string) (int64, error) {
252 | msg := emptyGatewayMessage
253 | msg.Cmd = CMD_GET_CLIENT_COUNT_BY_GROUP
254 | msg.ExtData = group
255 | var x int64
256 | err := GatewayList.SendToAllGatewayAndRecv(msg, func(addr string, data []byte) error {
257 | count, err := strconv.Atoi(string(data))
258 | if err != nil {
259 | return err
260 | }
261 | atomic.AddInt64(&x, int64(count))
262 | return nil
263 | })
264 | return x, err
265 | }
266 |
267 | func DestroyAddress(clientId string) error {
268 | msg := emptyGatewayMessage
269 | msg.Cmd = CMD_DESTROY
270 | return GatewayList.SendToGatewayByClientId(clientId, msg)
271 | }
272 |
273 | func SetSession(clientId, session string) error {
274 | msg := emptyGatewayMessage
275 | msg.Cmd = CMD_SET_SESSION
276 | msg.ExtData = session
277 | return GatewayList.SendToGatewayByClientId(clientId, msg)
278 | }
279 |
280 | func GetSession(clientId, session string) ([]byte, error) {
281 | msg := emptyGatewayMessage
282 | msg.Cmd = CMD_GET_SESSION_BY_CLIENT_ID
283 | msg.ExtData = session
284 | return GatewayList.SendAndRecvByClientId(clientId, msg)
285 | }
286 |
287 | func UpdateSession(clientId, session string) error {
288 | msg := emptyGatewayMessage
289 | msg.Cmd = CMD_UPDATE_SESSION
290 | msg.ExtData = session
291 | return GatewayList.SendToGatewayByClientId(clientId, msg)
292 | }
293 |
294 | func GetAllClientSessions() (session map[string]map[string]string, err error) {
295 | return GetClientSessionsByGroup("")
296 | }
297 |
298 | func GetClientSessionsByGroup(groupId string) (session map[string]map[string]string, err error) {
299 | msg := emptyGatewayMessage
300 | if groupId == "" {
301 | msg.Cmd = CMD_GET_ALL_CLIENT_SESSIONS
302 | } else {
303 | msg.Cmd = CMD_GET_CLIENT_SESSIONS_BY_GROUP
304 | msg.ExtData = groupId
305 | }
306 | var tempSession map[string]map[string]string
307 | err = GatewayList.SendToAllGatewayAndRecv(msg, func(addr string, data []byte) error {
308 | err := json.Unmarshal(data, &tempSession)
309 | if err != nil {
310 | return err
311 | }
312 | for conId, tempData := range tempSession {
313 | data := tempData
314 | clientId, err := ToClientId(addr, conId)
315 | if err != nil {
316 | return err
317 | }
318 | session[clientId] = data
319 | }
320 | return nil
321 | })
322 | return session, err
323 | }
324 |
325 | func GetGroupIdList() (groupsId []string, err error) {
326 | msg := emptyGatewayMessage
327 | msg.Cmd = CMD_GET_GROUP_ID_LIST
328 | err = GatewayList.SendToAllGatewayAndRecv(msg, func(addr string, data []byte) error {
329 | var temp []string
330 | err := json.Unmarshal(data, &temp)
331 | if err != nil {
332 | return err
333 | }
334 | groupsId = append(groupsId, temp...)
335 | return nil
336 | })
337 | return groupsId, err
338 | }
339 |
340 | //CMD_GET_ALL_CLIENT_SESSIONS
341 |
342 | //CMD_GATEWAY_CLIENT_CONNECT
343 | //CMD_ON_WEBSOCKET_CONNECT
344 | //CMD_ON_WEBSOCKET_CONNECT
345 | //FLAG_BODY_IS_SCALAR
346 | //// 通知gateway在send时不调用协议encode方法,在广播组播时提升性能
347 | //FLAG_NOT_CALL_ENCODE
348 |
--------------------------------------------------------------------------------
/lib/GatewayProtocol.go:
--------------------------------------------------------------------------------
1 | package lib
2 |
3 | import (
4 | "encoding/binary"
5 | "log"
6 | "reflect"
7 | )
8 |
9 | // 发给worker,gateway有一个新的连接
10 | const CMD_ON_CONNECT = 1
11 |
12 | // 发给worker的,客户端有消息
13 | const CMD_ON_MESSAGE = 3
14 |
15 | // 发给worker上的关闭链接事件
16 | const CMD_ON_CLOSE = 4
17 |
18 | // 发给gateway的向单个用户发送数据
19 | const CMD_SEND_TO_ONE = 5
20 |
21 | // 发给gateway的向所有用户发送数据
22 | const CMD_SEND_TO_ALL = 6
23 |
24 | // 发给gateway的踢出用户
25 | // 1、如果有待发消息,将在发送完后立即销毁用户连接
26 | // 2、如果无待发消息,将立即销毁用户连接
27 | const CMD_KICK = 7
28 |
29 | // 发给gateway的立即销毁用户连接
30 | const CMD_DESTROY = 8
31 |
32 | // 发给gateway,通知用户session更新
33 | const CMD_UPDATE_SESSION = 9
34 |
35 | // 获取所有在线client_id的session,client_id为 key
36 | const CMD_GET_ALL_CLIENT_SESSIONS = 10
37 |
38 | // 判断是否在线
39 | const CMD_IS_ONLINE = 11
40 |
41 | // client_id绑定到uid
42 | const CMD_BIND_UID = 12
43 |
44 | // 解绑
45 | const CMD_UNBIND_UID = 13
46 |
47 | // 向uid发送数据
48 | const CMD_SEND_TO_UID = 14
49 |
50 | // 根据uid获取绑定的clientid
51 | const CMD_GET_CLIENT_ID_BY_UID = 15
52 |
53 | // 加入组
54 | const CMD_JOIN_GROUP = 20
55 |
56 | // 离开组
57 | const CMD_LEAVE_GROUP = 21
58 |
59 | // 向组成员发消息
60 | const CMD_SEND_TO_GROUP = 22
61 |
62 | // 获取组成员所有在线client_id的session
63 | const CMD_GET_CLIENT_SESSIONS_BY_GROUP = 23
64 |
65 | // 获取组在线连接数
66 | const CMD_GET_CLIENT_COUNT_BY_GROUP = 24
67 |
68 | // 按照条件查找
69 | const CMD_SELECT = 25
70 |
71 | // 获取在线的群组ID
72 | const CMD_GET_GROUP_ID_LIST = 26
73 |
74 | // 取消分组
75 | const CMD_UNGROUP = 27
76 |
77 | // worker连接gateway事件
78 | const CMD_WORKER_CONNECT = 200
79 |
80 | // 心跳
81 | const CMD_PING = 201
82 |
83 | // GatewayClient连接gateway事件
84 | const CMD_GATEWAY_CLIENT_CONNECT = 202
85 |
86 | // 根据client_id获取session
87 | const CMD_GET_SESSION_BY_CLIENT_ID = 203
88 |
89 | // 发给gateway,覆盖session
90 | const CMD_SET_SESSION = 204
91 |
92 | // 当websocket握手时触发,只有websocket协议支持此命令字
93 | const CMD_ON_WEBSOCKET_CONNECT = 205
94 |
95 | // 包体是标量
96 | const FLAG_BODY_IS_SCALAR = 0x01
97 |
98 | // 通知gateway在send时不调用协议encode方法,在广播组播时提升性能
99 | const FLAG_NOT_CALL_ENCODE = 0x02
100 |
101 | // "Npack_len/Ccmd/Nlocal_ip/nlocal_port/Nclient_ip/nclient_port/Nconnection_id/Cflag/ngateway_port/Next_len"
102 | type GatewayMessage struct {
103 | PackageLen uint32
104 | Cmd uint8
105 | LocalIp uint32
106 | LocalPort uint16
107 | ClientIp uint32
108 | ClientPort uint16
109 | ConnectionId uint32
110 | Flag uint8
111 | GatewayPort uint16
112 | ExtLen uint32
113 | ExtData string
114 | Body []byte
115 | }
116 |
117 | func ToGatewayMessage(data []byte) GatewayMessage {
118 | Message := GatewayMessage{
119 | PackageLen: uint32(len(data)),
120 | Cmd: data[0],
121 | LocalIp: uint32(binary.BigEndian.Uint32(data[1:5])),
122 | LocalPort: uint16(binary.BigEndian.Uint16(data[5:7])),
123 | ClientIp: uint32(binary.BigEndian.Uint32(data[7:11])),
124 | ClientPort: uint16(binary.BigEndian.Uint16(data[11:13])),
125 | ConnectionId: uint32(binary.BigEndian.Uint32(data[13:17])),
126 | Flag: data[17],
127 | GatewayPort: uint16(binary.BigEndian.Uint16(data[18:20])),
128 | ExtLen: uint32(binary.BigEndian.Uint32(data[20:24])),
129 | }
130 | Message.ExtData = string(data[24 : 24+Message.ExtLen])
131 | Message.Body = data[(24 + Message.ExtLen):(Message.PackageLen)]
132 | Message.PackageLen += 4
133 | return Message
134 | }
135 |
136 | func GatewayMessageToByte(msg GatewayMessage) []byte {
137 | var msgByte []byte
138 | value := reflect.ValueOf(msg)
139 | for i := 0; i < value.NumField(); i++ {
140 | field := value.Field(i)
141 | switch field.Kind() {
142 | case reflect.String:
143 | var bufStr []byte
144 | bufStr = []byte(field.String())
145 | msgByte = append(msgByte, bufStr...)
146 | case reflect.Uint8:
147 | msgByte = append(msgByte, uint8(field.Uint()))
148 | case reflect.Uint16:
149 | var buf16 = make([]byte, 2)
150 | binary.BigEndian.PutUint16(buf16, uint16(field.Uint()))
151 | msgByte = append(msgByte, buf16...)
152 | case reflect.Uint32:
153 | var buf32 = make([]byte, 4)
154 | binary.BigEndian.PutUint32(buf32, uint32(field.Uint()))
155 | msgByte = append(msgByte, buf32...)
156 | case reflect.Slice:
157 | msgByte = append(msgByte, field.Bytes()...)
158 | default:
159 | log.Println("GatewayProtocol 不知道的类型", field.Type(), msg)
160 | }
161 | }
162 | return msgByte[4:]
163 | }
164 |
--------------------------------------------------------------------------------
/lib/Interface.go:
--------------------------------------------------------------------------------
1 | package lib
2 |
3 | type LogicEvent interface {
4 | OnStart()
5 | // 新链接
6 | OnConnect(clientId string)
7 | // 当客户端连接上gateway完成websocket握手时触发的回调函数。
8 | OnWebSocketConnect(clientId string, header []byte)
9 | // 新信息
10 | OnMessage(clientId string, body []byte)
11 | // 链接关闭
12 | OnClose(clientId string)
13 | }
14 |
--------------------------------------------------------------------------------
/lib/gateway/ConnectionGroup.go:
--------------------------------------------------------------------------------
1 | package gateway
2 |
3 | import (
4 | "errors"
5 | "goworker/network"
6 | "sync"
7 | )
8 |
9 | var CG = &ConnectionGroup{
10 | lock: &sync.RWMutex{},
11 | workers: map[uint32]network.Connect{},
12 | Clients: map[uint32]network.Connect{},
13 | clientList: map[uint32]network.Connect{},
14 | //GroupId/ConnectId
15 | GroupConnections: map[uint64]map[uint32]network.Connect{},
16 | //UserId/ConnectId
17 | UserIdConnections: map[uint64]map[uint32]network.Connect{},
18 | }
19 |
20 | type ConnectionGroup struct {
21 | lock *sync.RWMutex
22 | // worker ConnectionId 映射 worker
23 | workers map[uint32]network.Connect
24 | // client ConnectionId 映射 client
25 | Clients map[uint32]network.Connect
26 | // client ConnectionId 映射 worker ,记录已经通讯过的通道 client => worker
27 | clientList map[uint32]network.Connect
28 | // groupId/connection_id 群组集合
29 | GroupConnections map[uint64]map[uint32]network.Connect
30 | //userid/connection_id 用户设备集合
31 | UserIdConnections map[uint64]map[uint32]network.Connect
32 | }
33 |
34 | func (cg *ConnectionGroup) GetWorker(c network.Connect) (network.Connect, error) {
35 | cg.lock.Lock()
36 | defer cg.lock.Unlock()
37 | cid := c.Id()
38 | if worker, ok := cg.clientList[cid]; ok {
39 | // 已经通信过的通道
40 | return worker, nil
41 | } else {
42 | // 随机分配一个worker
43 | for _, worker := range cg.workers {
44 | cg.clientList[cid] = worker
45 | return worker, nil
46 | }
47 | }
48 | // 不存在
49 | return nil, errors.New("找不到worker")
50 | }
51 |
52 | func (cg *ConnectionGroup) AddedWorker(worker network.Connect) {
53 | cg.lock.Lock()
54 | defer cg.lock.Unlock()
55 | cg.workers[worker.Id()] = worker
56 | }
57 |
58 | // DeleteWorker worker 断开
59 | func (cg *ConnectionGroup) DeleteWorker(worker network.Connect) {
60 | cg.lock.Lock()
61 | defer cg.lock.Unlock()
62 | cid := worker.Id()
63 | delete(cg.workers, cid)
64 | for clientId, worker := range cg.clientList {
65 | if cid == worker.Id() {
66 | delete(cg.clientList, clientId)
67 | }
68 | }
69 | }
70 |
71 | // AddedClient 新增客户端,并且建立路由映射 ,用户浏览器 或者手机句柄
72 | func (cg *ConnectionGroup) AddedClient(c network.Connect) {
73 | cg.lock.Lock()
74 | defer cg.lock.Unlock()
75 | ConnectionId := c.Id()
76 | if _, ok := cg.Clients[ConnectionId]; ok {
77 | cg.DeleteClient(ConnectionId)
78 | }
79 | cg.Clients[ConnectionId] = c
80 | }
81 |
82 | func (cg *ConnectionGroup) GetClient(ConnectionId uint32) (network.Connect, error) {
83 | cg.lock.Lock()
84 | defer cg.lock.Unlock()
85 | c, ok := cg.Clients[ConnectionId]
86 | if ok {
87 | return c, nil
88 | }
89 | return nil, errors.New("客户端不存在")
90 | }
91 |
92 | // DeleteClient 删除 客户端
93 | func (cg *ConnectionGroup) DeleteClient(ConnectionId uint32) {
94 | cg.lock.Lock()
95 | defer cg.lock.Unlock()
96 | delete(cg.clientList, ConnectionId)
97 | client, err := cg.GetClient(ConnectionId)
98 | if err == nil {
99 | userId := client.UserId()
100 | if userId != 0 {
101 | delete(CG.UserIdConnections[userId], ConnectionId)
102 | }
103 | for k, _ := range client.GroupsId() {
104 | delete(CG.GroupConnections[k], ConnectionId)
105 | }
106 | }
107 | client.Close()
108 | delete(cg.Clients, ConnectionId)
109 | }
110 |
--------------------------------------------------------------------------------
/lib/gateway/RegisterEvent.go:
--------------------------------------------------------------------------------
1 | package gateway
2 |
3 | import (
4 | "encoding/json"
5 | "goworker/lib"
6 | "goworker/network"
7 | "log"
8 | "time"
9 | )
10 |
11 | type RegisterMessage struct {
12 | Event string `json:"event"`
13 | Address string `json:"address"`
14 | SecretKey string `json:"secret_key"`
15 | }
16 |
17 | type RegisterEvent struct {
18 | retry int16
19 | listen network.ListenTcp
20 | }
21 |
22 | // 连接注册中心
23 | func NewRegisterEvent() network.Event {
24 | return &RegisterEvent{}
25 | }
26 |
27 | // @error
28 | func (r *RegisterEvent) OnError(listen network.ListenTcp, err error) {
29 | r.retry++
30 | log.Println("注册中心连接失败,2秒后重试", r.retry)
31 | ticker := time.NewTicker(time.Second * 2)
32 | select {
33 | case <-ticker.C:
34 | listen.ListenAndServe()
35 | break
36 | }
37 | }
38 |
39 | func (r *RegisterEvent) OnStart(listen network.ListenTcp) {
40 | log.Println("connect the register to: ", listen.Url().Origin)
41 | r.listen = listen
42 | }
43 |
44 | func (*RegisterEvent) OnConnect(c network.Connect) {
45 | // 发送内部通讯地址到注册中心
46 | conData := RegisterMessage{
47 | Event: "gateway_connect",
48 | Address: lib.Config.Worker.Host,
49 | SecretKey: lib.Config.SecretKey,
50 | }
51 | byteStr, _ := json.Marshal(conData)
52 | go c.SendByte(byteStr)
53 | }
54 |
55 | func (*RegisterEvent) OnMessage(c network.Connect, message []byte) {
56 | log.Println("gateway 收到注册中心的信息 ", string(message))
57 | }
58 |
59 | func (r *RegisterEvent) OnClose(c network.Connect) {
60 | // 注册中心 关闭,定时检查
61 | log.Print("注册中心断开连接,2秒后重连 ", r.retry)
62 | ticker := time.NewTicker(time.Second * 2)
63 | select {
64 | case <-ticker.C:
65 | r.listen.ListenAndServe()
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/lib/gateway/WebSocketEvent.go:
--------------------------------------------------------------------------------
1 | package gateway
2 |
3 | import (
4 | "goworker/lib"
5 | "goworker/network"
6 | "log"
7 | "unicode/utf8"
8 | )
9 |
10 | /*
11 | 客户端信息
12 | */
13 | type GatewayHeader struct {
14 | // 内部通讯地址 , 对应本机地址
15 | LocalIp uint32
16 | LocalPort uint16
17 | ClientIp uint32
18 | ClientPort uint16
19 | GatewayPort uint16
20 | ConnectionId uint32
21 | flag uint8
22 | }
23 |
24 | func NewWebSocketEvent() network.Event {
25 | return &WebSocketEvent{}
26 | }
27 |
28 | type WebSocketEvent struct {
29 | // 内部通讯地址
30 | WorkerServerIp string
31 | WorkerServerPort uint16
32 | }
33 |
34 | func (ws *WebSocketEvent) OnError(listen network.ListenTcp, err error) {
35 |
36 | }
37 |
38 | func (ws *WebSocketEvent) OnStart(listen network.ListenTcp) {
39 | ws.WorkerServerIp = lib.Config.Worker.Ip
40 | ws.WorkerServerPort = lib.Config.Worker.Port
41 | log.Println("ws server listening at: ", listen.Url().Origin)
42 | }
43 |
44 | //func (ws *WebSocketEvent) GetClientId(client network.Connect) string {
45 | // return network.Bin2hex(network.Ip2long(ws.WorkerServerIp), ws.WorkerServerPort, client.Id())
46 | //}
47 |
48 | func (ws *WebSocketEvent) OnConnect(client network.Connect) {
49 | //client.SetClientId(ws.GetClientId(client))
50 | // 添加连接池
51 | CG.AddedClient(client)
52 | ws.SendToWorker(client, lib.CMD_ON_CONNECT, []byte(""), 1, "")
53 | }
54 |
55 | // 收到websocket信息
56 | func (ws *WebSocketEvent) OnMessage(c network.Connect, message []byte) {
57 | extData := c.ExtData()
58 | if extData == nil {
59 | ws.SendToWorker(c, lib.CMD_ON_MESSAGE, message, 1, "")
60 | } else {
61 | ws.SendToWorker(c, lib.CMD_ON_MESSAGE, message, 1, string(extData))
62 | }
63 | }
64 |
65 | func (ws *WebSocketEvent) OnClose(c network.Connect) {
66 | ws.SendToWorker(c, lib.CMD_ON_CLOSE, []byte(""), 1, "")
67 | CG.DeleteClient(c.Id())
68 | }
69 |
70 | // SendToWorker 发送信息的worker
71 | func (ws *WebSocketEvent) SendToWorker(client network.Connect, cmd uint8, body []byte, flag uint8, ExtData string) {
72 | msg := lib.GatewayMessage{
73 | PackageLen: 28 + uint32(len(body)),
74 | Cmd: cmd,
75 | LocalIp: network.Ip2long(ws.WorkerServerIp),
76 | LocalPort: ws.WorkerServerPort,
77 | ClientIp: client.GetIp(),
78 | ClientPort: client.GetPort(),
79 | ConnectionId: client.Id(),
80 | Flag: flag,
81 | GatewayPort: lib.Config.Gateway.Port,
82 | ExtLen: uint32(utf8.RuneCountInString(ExtData)),
83 | ExtData: ExtData,
84 | Body: body,
85 | }
86 | worker, err := CG.GetWorker(client)
87 | if err != nil { // worker 找不到 获取连接
88 | log.Println("主动断开客户端连接 err:", err)
89 | client.Close()
90 | CG.DeleteClient(client.Id())
91 | return
92 | }
93 | log.Println("发信息给worker", string(msg.Body))
94 | err = worker.SendByte(lib.GatewayMessageToByte(msg))
95 | if err != nil {
96 | log.Println("发信息给worker", err)
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/lib/gateway/WorkerEvent.go:
--------------------------------------------------------------------------------
1 | package gateway
2 |
3 | import (
4 | "goworker/lib"
5 | "goworker/network"
6 | "log"
7 | )
8 |
9 | func NewWorkerEvent() network.Event {
10 | return &WorkerEvent{}
11 | }
12 |
13 | /*
14 | 接受worker发上来的数据
15 | */
16 | type WorkerEvent struct {
17 | HandleFunc map[uint8]func(c network.Connect, message lib.GatewayMessage)
18 | }
19 |
20 | func (*WorkerEvent) OnError(listen network.ListenTcp, err error) {
21 |
22 | }
23 |
24 | func (w *WorkerEvent) OnStart(listen network.ListenTcp) {
25 | log.Println("worker server listening at: ", listen.Url().Origin)
26 | if w.HandleFunc == nil {
27 | w.HandleFunc = map[uint8]func(c network.Connect, message lib.GatewayMessage){}
28 | WorkerHandle := NewWorkerHandle()
29 | w.HandleFunc[lib.CMD_WORKER_CONNECT] = WorkerHandle.OnWorkerConnect
30 | w.HandleFunc[lib.CMD_GATEWAY_CLIENT_CONNECT] = WorkerHandle.OnGatewayClientConnect
31 | w.HandleFunc[lib.CMD_SEND_TO_ONE] = WorkerHandle.OnSendToOne
32 | w.HandleFunc[lib.CMD_KICK] = WorkerHandle.OnKick
33 | w.HandleFunc[lib.CMD_DESTROY] = WorkerHandle.OnDestroy
34 | w.HandleFunc[lib.CMD_SEND_TO_ALL] = WorkerHandle.OnSendToAll
35 | w.HandleFunc[lib.CMD_SELECT] = WorkerHandle.OnSelect
36 | w.HandleFunc[lib.CMD_GET_GROUP_ID_LIST] = WorkerHandle.OnGetGroupIdList
37 | w.HandleFunc[lib.CMD_SET_SESSION] = WorkerHandle.OnSetSession
38 | w.HandleFunc[lib.CMD_UPDATE_SESSION] = WorkerHandle.OnUpdateSession
39 | w.HandleFunc[lib.CMD_GET_SESSION_BY_CLIENT_ID] = WorkerHandle.OnGetSessionByClientId
40 | w.HandleFunc[lib.CMD_IS_ONLINE] = WorkerHandle.OnIsOnline
41 | w.HandleFunc[lib.CMD_BIND_UID] = WorkerHandle.OnBindUid
42 | w.HandleFunc[lib.CMD_UNBIND_UID] = WorkerHandle.OnUnBindUid
43 | w.HandleFunc[lib.CMD_SEND_TO_UID] = WorkerHandle.OnSendToUid
44 | w.HandleFunc[lib.CMD_JOIN_GROUP] = WorkerHandle.OnJoinGroup
45 | w.HandleFunc[lib.CMD_LEAVE_GROUP] = WorkerHandle.OnLeaveGroup
46 | w.HandleFunc[lib.CMD_UNGROUP] = WorkerHandle.OnUnGroup
47 | w.HandleFunc[lib.CMD_SEND_TO_GROUP] = WorkerHandle.OnSendToGroup
48 | w.HandleFunc[lib.CMD_GET_CLIENT_SESSIONS_BY_GROUP] = WorkerHandle.OnClientSessionsByGroup
49 | w.HandleFunc[lib.CMD_GET_ALL_CLIENT_SESSIONS] = WorkerHandle.OnGetAllClientSessions
50 | w.HandleFunc[lib.CMD_GET_CLIENT_COUNT_BY_GROUP] = WorkerHandle.OnGetClientCountByGroup
51 | w.HandleFunc[lib.CMD_GET_CLIENT_ID_BY_UID] = WorkerHandle.OnGetClientIdByUid
52 | }
53 | }
54 |
55 | func (*WorkerEvent) OnConnect(c network.Connect) {
56 |
57 | }
58 |
59 | func (w *WorkerEvent) OnMessage(c network.Connect, message []byte) {
60 | msg := lib.ToGatewayMessage(message)
61 | log.Println("收到worker的数据:", string(msg.Body))
62 | if handle, ok := w.HandleFunc[msg.Cmd]; ok {
63 | handle(c, msg)
64 | } else {
65 | log.Println("不认识的命令", msg.Cmd, c.GetCon().RemoteAddr().String())
66 | }
67 | }
68 |
69 | func (*WorkerEvent) OnClose(c network.Connect) {
70 | c.Close()
71 | CG.DeleteWorker(c)
72 | }
73 |
--------------------------------------------------------------------------------
/lib/gateway/WorkerHandle.go:
--------------------------------------------------------------------------------
1 | package gateway
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "goworker/lib"
7 | "goworker/lib/worker"
8 | "goworker/network"
9 | "log"
10 | "strconv"
11 | )
12 |
13 | func NewWorkerHandle() *WorkerHandle {
14 | return &WorkerHandle{}
15 | }
16 |
17 | // WorkerHandle 处理worker发来的信息命令
18 | type WorkerHandle struct {
19 | }
20 |
21 | // OnSendToOne 单个用户信息
22 | func (w *WorkerHandle) OnSendToOne(c network.Connect, message lib.GatewayMessage) {
23 | client, err := CG.GetClient(message.ConnectionId)
24 | if err != nil {
25 | CG.DeleteClient(message.ConnectionId)
26 | return
27 | }
28 | err = client.Send(message.Body)
29 | if err != nil {
30 | log.Println("数据发送异常", err)
31 | CG.DeleteClient(client.Id())
32 | return
33 | }
34 | }
35 |
36 | // OnKick 提出用户
37 | func (w *WorkerHandle) OnKick(c network.Connect, message lib.GatewayMessage) {
38 | client, _ := CG.GetClient(message.ConnectionId)
39 | err := client.Send(message.Body)
40 | if err != nil {
41 | log.Println("数据发送异常", err)
42 | }
43 | CG.DeleteClient(message.ConnectionId)
44 | }
45 |
46 | // OnDestroy 立即摧毁用户连接
47 | func (w *WorkerHandle) OnDestroy(c network.Connect, message lib.GatewayMessage) {
48 | CG.DeleteClient(message.ConnectionId)
49 | }
50 |
51 | // 发给gateway的向所有用户发送数据
52 | func (w *WorkerHandle) OnSendToAll(c network.Connect, message lib.GatewayMessage) {
53 | for _, client := range CG.Clients {
54 | err := client.Send(message.Body)
55 | if err != nil {
56 | log.Println("数据发送异常", err)
57 | CG.DeleteClient(client.Id())
58 | return
59 | }
60 | }
61 | }
62 |
63 | func (w *WorkerHandle) OnWorkerConnect(c network.Connect, message lib.GatewayMessage) {
64 | WorkerKey := &worker.WorkerKey{}
65 | if lib.Config.SecretKey != WorkerKey.Secret {
66 | log.Println("链接秘钥错误")
67 | c.Close()
68 | return
69 | }
70 | err := json.Unmarshal(message.Body, WorkerKey)
71 | if err != nil {
72 | log.Println("数据解析异常", err)
73 | c.Close()
74 | return
75 | }
76 | CG.AddedWorker(c)
77 | }
78 |
79 | func (w *WorkerHandle) OnGatewayClientConnect(c network.Connect, message lib.GatewayMessage) {
80 | WorkerKey := &worker.WorkerKey{}
81 | if lib.Config.SecretKey != WorkerKey.Secret {
82 | log.Println("链接秘钥错误")
83 | c.Close()
84 | return
85 | }
86 | err := json.Unmarshal(message.Body, WorkerKey)
87 | if err != nil {
88 | log.Println("数据解析异常", err)
89 | c.Close()
90 | return
91 | }
92 | CG.AddedWorker(c)
93 | }
94 |
95 | func (w *WorkerHandle) OnGetAllClientSessions(c network.Connect, message lib.GatewayMessage) {
96 | allClientSessions := make(map[uint32][]byte)
97 | for _, client := range CG.Clients {
98 | allClientSessions[client.Id()] = client.ExtData()
99 | }
100 | allClientSessionsByte, err := json.Marshal(allClientSessions)
101 | if err != nil {
102 | return
103 | }
104 | err = c.SendByte(allClientSessionsByte)
105 | if err != nil {
106 | log.Println("发送数据异常", err)
107 | }
108 | }
109 |
110 | // OnClientSessionsByGroup 获取组成员session
111 | func (w *WorkerHandle) OnClientSessionsByGroup(c network.Connect, message lib.GatewayMessage) {
112 | intNum, _ := strconv.Atoi(message.ExtData)
113 | groupId := uint64(intNum)
114 | if list, ok := CG.GroupConnections[groupId]; ok {
115 | clientArray := make(map[uint32][]byte)
116 | for clientId, client := range list {
117 | clientArray[clientId] = client.ExtData()
118 | }
119 | buffer, err := json.Marshal(clientArray)
120 | if err != nil {
121 | log.Println("解析数据异常")
122 | return
123 | }
124 | err = c.SendByte(buffer)
125 | if err != nil {
126 | c.Close()
127 | log.Println("发送数据异常", err)
128 | }
129 | } else {
130 | err := c.SendString("[]")
131 | if err != nil {
132 | c.Close()
133 | log.Println("发送数据异常", err)
134 | }
135 | }
136 | }
137 |
138 | // OnSendToGroup 向组成员发消息
139 | func (w *WorkerHandle) OnSendToGroup(c network.Connect, message lib.GatewayMessage) {
140 | groupList := struct {
141 | Group []uint64 `json:"group"`
142 | Exclude []uint64 `json:"exclude"`
143 | }{}
144 | err := json.Unmarshal([]byte(message.ExtData), &groupList)
145 | if err != nil {
146 | log.Println("向组成员发消息,格式错误,检查数据类型")
147 | return
148 | }
149 | for _, groupId := range groupList.Group {
150 | if list, ok := CG.GroupConnections[groupId]; ok {
151 | for _, clientConnect := range list {
152 | err := clientConnect.Send(message.Body)
153 | if err != nil {
154 | log.Println("发送数据异常", err)
155 | }
156 | }
157 | }
158 | }
159 | }
160 |
161 | // OnGetSessionByClientId 根据client_id获取session
162 | func (w *WorkerHandle) OnGetSessionByClientId(c network.Connect, message lib.GatewayMessage) {
163 | client, err := CG.GetClient(message.ConnectionId)
164 | if err != nil {
165 | CG.DeleteClient(message.ConnectionId)
166 | return
167 | }
168 | session := client.ExtData()
169 | if session == nil {
170 | err := c.SendString("Nil")
171 | if err != nil {
172 | log.Println("发送数据异常", err)
173 | }
174 | } else {
175 | err := c.SendByte(session)
176 | if err != nil {
177 | log.Println("发送数据异常", err)
178 | }
179 | }
180 | }
181 |
182 | // OnSetSession 重新赋值 session
183 | func (w *WorkerHandle) OnSetSession(c network.Connect, message lib.GatewayMessage) {
184 | client, err := CG.GetClient(message.ConnectionId)
185 | if err != nil {
186 | CG.DeleteClient(message.ConnectionId)
187 | return
188 | }
189 | client.SetExtData([]byte(message.ExtData))
190 | }
191 |
192 | // OnJoinGroup 加入组
193 | func (w *WorkerHandle) OnJoinGroup(c network.Connect, message lib.GatewayMessage) {
194 | intNum, _ := strconv.Atoi(message.ExtData)
195 | groupId := uint64(intNum)
196 | if groupId <= 0 {
197 | log.Println("群组id错误" + message.ExtData)
198 | return
199 | }
200 | client, err := CG.GetClient(message.ConnectionId)
201 | if err != nil {
202 | log.Println("用户不存在", err)
203 | return
204 | }
205 | if _, ok := CG.GroupConnections[groupId]; !ok {
206 | CG.GroupConnections[groupId] = map[uint32]network.Connect{}
207 | }
208 | client.SetGroupId(groupId)
209 | CG.GroupConnections[groupId][message.ConnectionId] = client
210 | }
211 |
212 | // OnSelect 按照条件查找
213 | func (w *WorkerHandle) OnSelect(c network.Connect, message lib.GatewayMessage) {
214 | //todo
215 | log.Println("按照条件查找")
216 | }
217 |
218 | func (w *WorkerHandle) OnGetGroupIdList(c network.Connect, message lib.GatewayMessage) {
219 | keys := make([]uint64, 0, len(CG.GroupConnections))
220 | for key, _ := range CG.GroupConnections {
221 | keys = append(keys, key)
222 | }
223 | jsonByte, err := json.Marshal(keys)
224 | if err != nil {
225 | return
226 | }
227 | err = c.SendByte(jsonByte)
228 | if err != nil {
229 | log.Println("发送数据异常", err)
230 | }
231 | }
232 |
233 | func (w *WorkerHandle) OnUpdateSession(c network.Connect, message lib.GatewayMessage) {
234 | client, err := CG.GetClient(message.ConnectionId)
235 | if err != nil {
236 | CG.DeleteClient(message.ConnectionId)
237 | return
238 | }
239 | var oldData map[string]string
240 | err = json.Unmarshal(client.ExtData(), &oldData)
241 | if err != nil {
242 | log.Println("数据解析异常", err)
243 | return
244 | }
245 | var extData map[string]string
246 | err = json.Unmarshal([]byte(message.ExtData), &extData)
247 | if err != nil {
248 | log.Println("数据解析异常", err)
249 | return
250 | }
251 | for k, v := range extData {
252 | oldData[k] = v
253 | }
254 | bytes, err := json.Marshal(oldData)
255 | if err != nil {
256 | return
257 | }
258 | client.SetExtData(bytes)
259 | }
260 |
261 | func (w *WorkerHandle) OnIsOnline(c network.Connect, message lib.GatewayMessage) {
262 | online := `{"false"}`
263 | _, err := CG.GetClient(message.ConnectionId)
264 | if err == nil {
265 | online = `{"true"}`
266 | }
267 | err = c.SendString(online)
268 | if err != nil {
269 | log.Println("发送数据异常", err)
270 | }
271 | }
272 |
273 | func (w *WorkerHandle) OnUnBindUid(c network.Connect, message lib.GatewayMessage) {
274 | client, err := CG.GetClient(message.ConnectionId)
275 | if err != nil {
276 | log.Println(err)
277 | return
278 | }
279 | if client.UserId() != 0 {
280 | delete(CG.UserIdConnections[client.UserId()], client.Id())
281 | if len(CG.UserIdConnections[client.UserId()]) == 0 {
282 | delete(CG.UserIdConnections, client.UserId())
283 | }
284 | client.SetUserId(0)
285 | }
286 | }
287 |
288 | func (w *WorkerHandle) OnBindUid(c network.Connect, message lib.GatewayMessage) {
289 | intNum, err := strconv.Atoi(message.ExtData)
290 | if err != nil {
291 | log.Println("数据转换异常", err)
292 | return
293 | }
294 | uId := uint64(intNum)
295 | client, err := CG.GetClient(message.ConnectionId)
296 | if err != nil {
297 | log.Println(err)
298 | return
299 | }
300 | if client.UserId() != 0 {
301 | delete(CG.UserIdConnections[client.UserId()], client.Id())
302 | if len(CG.UserIdConnections[client.UserId()]) == 0 {
303 | delete(CG.UserIdConnections, client.UserId())
304 | }
305 | }
306 | client.SetUserId(uId)
307 | CG.UserIdConnections[client.UserId()][client.Id()] = client
308 | }
309 |
310 | func (w *WorkerHandle) OnSendToUid(c network.Connect, message lib.GatewayMessage) {
311 | intNum, err := strconv.Atoi(message.ExtData)
312 | if err != nil {
313 | log.Println("数据转换异常", err)
314 | return
315 | }
316 | uId := uint64(intNum)
317 | for _, client := range CG.UserIdConnections[uId] {
318 | err = client.SendByte(message.Body)
319 | if err != nil {
320 | log.Println("发送数据异常", err)
321 | }
322 | }
323 | }
324 |
325 | func (w *WorkerHandle) OnLeaveGroup(c network.Connect, message lib.GatewayMessage) {
326 | intNum, err := strconv.Atoi(message.ExtData)
327 | if err != nil {
328 | log.Println("数据转换异常", err)
329 | return
330 | }
331 | groupId := uint64(intNum)
332 | client, err := CG.GetClient(message.ConnectionId)
333 | if err != nil {
334 | CG.DeleteClient(message.ConnectionId)
335 | return
336 | }
337 | delete(CG.GroupConnections[groupId], client.Id())
338 | client.DeleteGroupId(groupId)
339 | if len(CG.GroupConnections[groupId]) == 0 {
340 | delete(CG.GroupConnections, groupId)
341 | }
342 | }
343 |
344 | func (w *WorkerHandle) OnUnGroup(c network.Connect, message lib.GatewayMessage) {
345 | intNum, err := strconv.Atoi(message.ExtData)
346 | if err != nil {
347 | log.Println("数据转换异常", err)
348 | return
349 | }
350 | groupId := uint64(intNum)
351 | for _, client := range CG.GroupConnections[groupId] {
352 | client.DeleteGroupId(groupId)
353 | }
354 | delete(CG.GroupConnections, groupId)
355 | }
356 |
357 | // OnGetClientCountByGroup 获取群的成员数量 或者在线用户数量
358 | func (w *WorkerHandle) OnGetClientCountByGroup(c network.Connect, message lib.GatewayMessage) {
359 | var count int
360 | if message.ExtData == "" {
361 | count = len(CG.Clients)
362 | } else {
363 | intNum, err := strconv.Atoi(message.ExtData)
364 | if err != nil {
365 | log.Println("数据转换异常", err)
366 | return
367 | }
368 | groupId := uint64(intNum)
369 | count = len(CG.GroupConnections[groupId])
370 | }
371 | err := c.SendString(fmt.Sprintf("{\"count\":$v}", count))
372 | if err != nil {
373 | log.Println("发送数据异常", err)
374 | }
375 | }
376 |
377 | func (w *WorkerHandle) OnGetClientIdByUid(c network.Connect, message lib.GatewayMessage) {
378 | intNum, err := strconv.Atoi(message.ExtData)
379 | if err != nil {
380 | log.Println("数据转换异常", err)
381 | return
382 | }
383 | uId := uint64(intNum)
384 | keys := make([]uint32, 0, len(CG.UserIdConnections[uId]))
385 | for key, _ := range CG.UserIdConnections[uId] {
386 | keys = append(keys, key)
387 | }
388 | jsonByte, err := json.Marshal(keys)
389 | if err != nil {
390 | log.Println("数据转换异常", err)
391 | return
392 | }
393 | err = c.SendByte(jsonByte)
394 | if err != nil {
395 | log.Println("发送数据异常", err)
396 | }
397 | }
398 |
--------------------------------------------------------------------------------
/lib/register/RegisterEvent.go:
--------------------------------------------------------------------------------
1 | package register
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "goworker/lib"
7 | "goworker/network"
8 | "log"
9 | )
10 |
11 | type RegisterMessage struct {
12 | Event string `json:"event"`
13 | Address string `json:"address"`
14 | SecretKey string `json:"secret_key"`
15 | }
16 |
17 | type RegisterEvent struct {
18 | // ID 地址保存
19 | gatewayConnections map[uint32]string
20 | workerConnections map[uint32]network.Connect
21 | }
22 |
23 | func NewRegisterEvent() network.Event {
24 | return &RegisterEvent{
25 | gatewayConnections: make(map[uint32]string),
26 | workerConnections: make(map[uint32]network.Connect),
27 | }
28 | }
29 | func (r *RegisterEvent) OnStart(listen network.ListenTcp) {
30 | log.Println("register server listening at: ", listen.Url().Origin)
31 | }
32 |
33 | func (r *RegisterEvent) OnConnect(connect network.Connect) {
34 | log.Println("connect: ", connect.GetIp(), connect.GetPort())
35 | }
36 |
37 | func (r *RegisterEvent) OnMessage(connect network.Connect, message []byte) {
38 | var data RegisterMessage
39 | err := json.Unmarshal(message, &data)
40 | if err != nil {
41 | fmt.Println(err)
42 | connect.Close()
43 | return
44 | }
45 | if lib.Config.SecretKey != "" {
46 | if data.SecretKey != lib.Config.SecretKey {
47 | fmt.Println("秘要不对")
48 | connect.Close()
49 | return
50 | }
51 | }
52 | log.Printf("Register OnMessage:%s:%v Data:%s ", network.Long2Ip(connect.GetIp()), connect.GetPort(), string(message))
53 | switch data.Event {
54 | case "gateway_connect":
55 | r.gatewayConnect(connect, data)
56 | case "worker_connect":
57 | r.workerConnect(connect, data)
58 | case "ping":
59 | return
60 | default:
61 | fmt.Println("不认识的事件定义")
62 | connect.Close()
63 | }
64 | }
65 |
66 | func (r *RegisterEvent) OnClose(connect network.Connect) {
67 | _, hasG := r.gatewayConnections[connect.Id()]
68 | if hasG == true {
69 | delete(r.gatewayConnections, connect.Id())
70 | r.broadcastAddresses(0)
71 | }
72 | _, hasW := r.workerConnections[connect.Id()]
73 | if hasW == true {
74 | delete(r.workerConnections, connect.Id())
75 | }
76 | }
77 |
78 | func (r *RegisterEvent) OnError(listen network.ListenTcp, err error) {
79 | log.Println("注册中心启动失败", err)
80 | }
81 |
82 | // gateway 链接
83 | func (r *RegisterEvent) gatewayConnect(c network.Connect, msg RegisterMessage) {
84 | if msg.Address == "" {
85 | println("address not found")
86 | c.Close()
87 | return
88 | }
89 | // 推入列表
90 | r.gatewayConnections[c.Id()] = msg.Address
91 | r.broadcastAddresses(0)
92 | }
93 |
94 | // worker 链接
95 | func (r *RegisterEvent) workerConnect(c network.Connect, msg RegisterMessage) {
96 | // 推入列表
97 | r.workerConnections[c.Id()] = c
98 | r.broadcastAddresses(0)
99 | }
100 |
101 | /*
102 | 向 BusinessWorker 广播 gateway 内部通讯地址
103 | 0 全部发生
104 | */
105 | func (r *RegisterEvent) broadcastAddresses(id uint32) {
106 | type ConList struct {
107 | Event string `json:"event"`
108 | Addresses []string `json:"addresses"`
109 | }
110 | data := ConList{Event: "broadcast_addresses"}
111 | for _, address := range r.gatewayConnections {
112 | data.Addresses = append(data.Addresses, address)
113 | }
114 | jsonByte, _ := json.Marshal(data)
115 | if id != 0 {
116 | worker := r.workerConnections[id]
117 | _ = worker.SendByte(jsonByte)
118 | return
119 | }
120 | for _, worker := range r.workerConnections {
121 | _ = worker.SendByte(jsonByte)
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/lib/worker/GatewayEvent.go:
--------------------------------------------------------------------------------
1 | package worker
2 |
3 | import (
4 | "encoding/json"
5 | "goworker/lib"
6 | "goworker/network"
7 | "log"
8 | "strconv"
9 | )
10 |
11 | type WorkerKey struct {
12 | Worker string `json:"worker_key"`
13 | Secret string `json:"secret_key"`
14 | }
15 |
16 | // 接受 lib 发来的数据
17 | type GatewayEvent struct {
18 | registerEvent *RegisterEvent
19 | gatewayAddresses *network.Url
20 |
21 | HandleFunc map[uint8]func(message lib.GatewayMessage)
22 | }
23 |
24 | func NewGatewayEvent(r *RegisterEvent, address string) network.Event {
25 | return &GatewayEvent{
26 | registerEvent: r,
27 | gatewayAddresses: network.NewUrl(address),
28 | }
29 | }
30 |
31 | func (g *GatewayEvent) OnStart(listen network.ListenTcp) {
32 | if g.HandleFunc == nil {
33 | handle := GatewayHandle{}
34 | g.HandleFunc = map[uint8]func(message lib.GatewayMessage){}
35 | g.HandleFunc[lib.CMD_ON_CONNECT] = handle.OnConnect
36 | g.HandleFunc[lib.CMD_ON_MESSAGE] = handle.OnMessage
37 | g.HandleFunc[lib.CMD_ON_CLOSE] = handle.OnClose
38 | g.HandleFunc[lib.CMD_ON_WEBSOCKET_CONNECT] = handle.onWebsocketConnect
39 | }
40 | }
41 |
42 | // OnConnect gateway 连接
43 | func (g *GatewayEvent) OnConnect(gateway network.Connect) {
44 | g.registerEvent.UpdateGatewayConnections(g.GetGatewayAddress(), gateway)
45 | msg := WorkerKey{
46 | Worker: "BussinessWorker:" + strconv.Itoa(int(gateway.Id())),
47 | Secret: lib.Config.SecretKey,
48 | }
49 | g.SendToGateway(gateway, lib.CMD_WORKER_CONNECT, msg)
50 | }
51 |
52 | // 接受 gateway 转发来的client数据
53 | func (g *GatewayEvent) OnMessage(c network.Connect, message []byte) {
54 | msg := lib.ToGatewayMessage(message)
55 | if handle, ok := g.HandleFunc[msg.Cmd]; ok {
56 | handle(msg)
57 | } else {
58 | log.Println("GatewayEvent 不认识的命令", msg.Cmd, message)
59 | }
60 | }
61 |
62 | func (g *GatewayEvent) OnClose(connect network.Connect) {
63 | g.registerEvent.UpdateGatewayConnections(g.GetGatewayAddress(), nil)
64 | }
65 |
66 | func (g *GatewayEvent) OnError(listen network.ListenTcp, err error) {
67 | g.registerEvent.UpdateGatewayConnections(g.GetGatewayAddress(), nil)
68 | }
69 |
70 | func (g *GatewayEvent) GetGatewayAddress() string {
71 | return g.gatewayAddresses.Ip + ":" + strconv.Itoa(int(g.gatewayAddresses.Port))
72 | }
73 |
74 | // 发送数据到对应的客户端
75 | func (g *GatewayEvent) SendToClient(uid string, cmd uint8, msg interface{}) {
76 |
77 | }
78 |
79 | // 发送数据到对应的 gateway 进程
80 | func (g *GatewayEvent) SendToGateway(gatewayConnect network.Connect, cmd uint8, msg interface{}) {
81 | var body []byte
82 | switch msg.(type) {
83 | case []byte:
84 | body = msg.([]byte)
85 | case string:
86 | body = []byte(msg.(string))
87 | default:
88 | // 未知类型,直接转json
89 | body, _ = json.Marshal(msg)
90 | }
91 |
92 | gm := lib.GatewayMessage{
93 | PackageLen: 28 + uint32(len(body)),
94 | Cmd: cmd,
95 | LocalIp: 0,
96 | LocalPort: 0,
97 | ClientIp: gatewayConnect.GetIp(),
98 | ClientPort: gatewayConnect.GetPort(),
99 | ConnectionId: gatewayConnect.Id(),
100 | Flag: 1,
101 | GatewayPort: g.gatewayAddresses.Port,
102 | ExtLen: 0,
103 | ExtData: "",
104 | Body: body,
105 | }
106 | gatewayConnect.Send(lib.GatewayMessageToByte(gm))
107 | }
108 |
--------------------------------------------------------------------------------
/lib/worker/GatewayHandle.go:
--------------------------------------------------------------------------------
1 | package worker
2 |
3 | import (
4 | "goworker/lib"
5 | "goworker/network"
6 | "log"
7 | )
8 |
9 | type GatewayHandle struct {
10 | }
11 |
12 | func (g *GatewayHandle) OnConnect(message lib.GatewayMessage) {
13 | clientId := network.Bin2hex(message.LocalIp, message.LocalPort, message.ConnectionId)
14 | lib.BussinessEvent.OnConnect(clientId)
15 | }
16 |
17 | func (*GatewayHandle) OnMessage(message lib.GatewayMessage) {
18 | clientId := network.Bin2hex(message.LocalIp, message.LocalPort, message.ConnectionId)
19 | lib.BussinessEvent.OnMessage(clientId, message.Body)
20 | }
21 |
22 | func (*GatewayHandle) OnClose(message lib.GatewayMessage) {
23 | clientId := network.Bin2hex(message.LocalIp, message.LocalPort, message.ConnectionId)
24 | lib.BussinessEvent.OnClose(clientId)
25 | }
26 |
27 | func (*GatewayHandle) onWebsocketConnect(message lib.GatewayMessage) {
28 | clientId := network.Bin2hex(message.LocalIp, message.LocalPort, message.ConnectionId)
29 | lib.BussinessEvent.OnWebSocketConnect(clientId, message.Body)
30 | }
31 |
32 | func (*GatewayHandle) OnTodo(message lib.GatewayMessage) {
33 | log.Println("todo ", message)
34 | }
35 |
--------------------------------------------------------------------------------
/lib/worker/RegisterEvent.go:
--------------------------------------------------------------------------------
1 | package worker
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "goworker/lib"
7 | "goworker/network"
8 | "goworker/network/tcp"
9 | "goworker/network/tcpclient"
10 | "log"
11 | "time"
12 | )
13 |
14 | type WorkerConnect struct {
15 | Event string `json:"event"`
16 | SecretKey string `json:"secret_key"`
17 | }
18 | type BroadcastAddresses struct {
19 | Event string `json:"event"`
20 | Addresses []string `json:"addresses"`
21 | }
22 |
23 | type RegisterEvent struct {
24 | listen network.ListenTcp
25 | }
26 |
27 | /*
28 | 连接注册中心
29 | */
30 | func NewRegisterEvent() network.Event {
31 | return &RegisterEvent{}
32 | }
33 |
34 | func (r *RegisterEvent) OnStart(listen network.ListenTcp) {
35 | log.Println("connect the register to: ", listen.Url().Origin)
36 | r.listen = listen
37 | }
38 |
39 | func (*RegisterEvent) OnConnect(c network.Connect) {
40 | conData := WorkerConnect{
41 | Event: "worker_connect",
42 | SecretKey: lib.Config.SecretKey,
43 | }
44 | byteStr, _ := json.Marshal(conData)
45 | go c.SendByte(byteStr)
46 | }
47 |
48 | func (r *RegisterEvent) OnMessage(c network.Connect, message []byte) {
49 | strMsg := string(message)
50 | fmt.Println(strMsg)
51 | msgBA := BroadcastAddresses{}
52 | log.Printf("worker Register OnMessage:%s:%v Data:%s ", network.Long2Ip(c.GetIp()), c.GetPort(), string(message))
53 | err := json.Unmarshal([]byte(strMsg), &msgBA)
54 | if err != nil {
55 | return
56 | }
57 | switch msgBA.Event {
58 | case "broadcast_addresses":
59 | for _, addr := range msgBA.Addresses {
60 | if _, ok := lib.GatewayList.GatewayCons[addr]; !ok {
61 | lib.GatewayList.GatewayCons[addr] = nil
62 | }
63 | }
64 | r.checkGatewayConnections()
65 | default:
66 | log.Println("不认识的事件", msgBA)
67 | }
68 | }
69 |
70 | func (*RegisterEvent) OnClose(c network.Connect) {
71 |
72 | }
73 |
74 | func (*RegisterEvent) OnError(listen network.ListenTcp, err error) {
75 |
76 | }
77 |
78 | func (r *RegisterEvent) checkGatewayConnections() {
79 | for addr, con := range lib.GatewayList.GatewayCons {
80 | if con == nil {
81 | address := "pack://" + addr
82 | worker := tcp.NewClient(address)
83 | worker.SetEvent(NewGatewayEvent(r, address))
84 | go worker.ListenAndServe()
85 | }
86 | }
87 | }
88 |
89 | // UpdateGatewayConnections 连接成功 or 失败
90 | func (r *RegisterEvent) UpdateGatewayConnections(addr string, con network.Connect) {
91 | if con != nil {
92 | lib.GatewayList.GatewayCons[addr] = con
93 | client, err := tcpclient.NewClient(addr, 1, 10, 100*time.Millisecond, 10*time.Millisecond, time.Second)
94 | if err != nil {
95 | log.Fatal(err)
96 | }
97 | lib.GatewayList.ConnectionPool[addr] = client
98 | } else {
99 | delete(lib.GatewayList.GatewayCons, addr)
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "goworker/app"
6 | "goworker/lib"
7 | "goworker/lib/gateway"
8 | "goworker/lib/register"
9 | "goworker/lib/worker"
10 | "goworker/network/tcp"
11 | "goworker/utils"
12 | "os"
13 | "time"
14 | )
15 |
16 | func main() {
17 | //logFile, _ := os.OpenFile("register.log", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
18 | //log.SetOutput(logFile)
19 | argsLen := len(os.Args)
20 | fmt.Println(argsLen)
21 | if argsLen < 2 {
22 | panic("参数长度错误")
23 | } else {
24 | switch os.Args[1] {
25 | case "registerStart":
26 | registerStart()
27 | case "registerStop":
28 | registerStop()
29 | case "workerStart":
30 | workerStart()
31 | case "gatewayStart":
32 | gatewayStart()
33 | case "gatewayStop":
34 | gatewayStop()
35 | default:
36 | fmt.Println("不存在的命令:" + os.Args[1])
37 | }
38 | }
39 | }
40 |
41 | func registerStart() {
42 | utils.SavePidToFile("register")
43 | utils.ListenStopSignal(func(sig os.Signal) {
44 | utils.DeleteSavePidToFile("register")
45 | os.Exit(0)
46 | })
47 | lib.Config.SetInput()
48 | server := tcp.NewServer(lib.Config.Register.Origin)
49 | server.SetEvent(register.NewRegisterEvent())
50 | server.ListenAndServe()
51 | }
52 |
53 | func registerStop() {
54 | err := utils.StopSignal("register")
55 | if err != nil {
56 | fmt.Println("停止失败")
57 | return
58 | }
59 | fmt.Println("停止成功")
60 | }
61 |
62 | func workerStart() {
63 | lib.Config.SetInput()
64 | lib.BussinessEvent = &app.MainEvent{}
65 | // 连接到注册中心
66 | r := tcp.NewClient(lib.Config.Register.Origin)
67 | r.SetEvent(worker.NewRegisterEvent())
68 | r.ListenAndServe()
69 | // 断线重连
70 | for {
71 | ticker := time.NewTicker(time.Second * 2)
72 | select {
73 | case <-ticker.C:
74 | r.ListenAndServe()
75 | }
76 | }
77 | }
78 |
79 | func gatewayStart() {
80 | lib.Config.SetInput()
81 | // 启动一个内部通讯tcp server
82 | w := tcp.NewServer(lib.Config.Worker.Origin)
83 | w.SetEvent(gateway.NewWorkerEvent())
84 | go w.ListenAndServe()
85 | // 连接到注册中心
86 | r := tcp.NewClient(lib.Config.Register.Origin)
87 | r.SetEvent(gateway.NewRegisterEvent())
88 | go r.ListenAndServe()
89 | // 启动对客户端的websocket连接
90 | // network.WebsocketMessageType = network.BinaryMessage
91 | server := tcp.NewServer(lib.Config.Gateway.Origin)
92 | server.SetEvent(gateway.NewWebSocketEvent())
93 | server.ListenAndServe()
94 | }
95 |
96 | func gatewayStop() {
97 | err := utils.StopSignal("gateway")
98 | if err != nil {
99 | fmt.Println("停止失败")
100 | return
101 | }
102 | fmt.Println("停止成功")
103 | }
104 |
--------------------------------------------------------------------------------
/network/Func.go:
--------------------------------------------------------------------------------
1 | package network
2 |
3 | import (
4 | "encoding/binary"
5 | "encoding/hex"
6 | "net"
7 | "regexp"
8 | "strconv"
9 | )
10 |
11 | // 构建分布式唯一id
12 | func Bin2hex(ip uint32, port uint16, id uint32) string {
13 | var msgByte []byte
14 | var buf32 = make([]byte, 4)
15 | var bug16 = make([]byte, 2)
16 | binary.BigEndian.PutUint32(buf32, ip)
17 | msgByte = append(msgByte, buf32...)
18 | binary.BigEndian.PutUint16(bug16, port)
19 | msgByte = append(msgByte, bug16...)
20 | binary.BigEndian.PutUint32(buf32, id)
21 | msgByte = append(msgByte, buf32...)
22 | return hex.EncodeToString(msgByte)
23 | }
24 |
25 | // 构建分布式唯一id转换回去
26 | func DecodeBin2hex(clientId string) (uint32, uint16, uint32) {
27 | msgByte, _ := hex.DecodeString(clientId)
28 | ip4 := msgByte[0:4]
29 | port2 := msgByte[4:6]
30 | id4 := msgByte[6:]
31 |
32 | ip := binary.BigEndian.Uint32(ip4)
33 | port := binary.BigEndian.Uint16(port2)
34 | id := binary.BigEndian.Uint32(id4)
35 | return ip, port, id
36 | }
37 |
38 | func Ip2long(ipstr string) (ip uint32) {
39 | r := `^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})`
40 | reg, err := regexp.Compile(r)
41 | if err != nil {
42 | return
43 | }
44 | ips := reg.FindStringSubmatch(ipstr)
45 | if ips == nil {
46 | return
47 | }
48 |
49 | ip1, _ := strconv.Atoi(ips[1])
50 | ip2, _ := strconv.Atoi(ips[2])
51 | ip3, _ := strconv.Atoi(ips[3])
52 | ip4, _ := strconv.Atoi(ips[4])
53 |
54 | if ip1 > 255 || ip2 > 255 || ip3 > 255 || ip4 > 255 {
55 | return
56 | }
57 |
58 | ip += uint32(ip1 * 0x1000000)
59 | ip += uint32(ip2 * 0x10000)
60 | ip += uint32(ip3 * 0x100)
61 | ip += uint32(ip4)
62 |
63 | return ip
64 | }
65 |
66 | func Long2Ip(ip uint32) string {
67 | a := byte((ip >> 24) & 0xFF)
68 | b := byte((ip >> 16) & 0xFF)
69 | c := byte((ip >> 8) & 0xFF)
70 | d := byte(ip & 0xFF)
71 | return net.IPv4(a, b, c, d).String()
72 | }
73 |
--------------------------------------------------------------------------------
/network/Interface.go:
--------------------------------------------------------------------------------
1 | package network
2 |
3 | import (
4 | "net"
5 | )
6 |
7 | // tcp 服务端 or 客户端监听接口
8 | type ListenTcp interface {
9 | SetUrl(address *Url) // 设置监听地址
10 | Url() *Url // 地址
11 | SetEvent(event Event) // 设置信息事件
12 | Event() Event // 信息事件
13 | SetProtocol(protocol Protocol) // 设置解析协议
14 | Protocol() Protocol // 协议对象
15 | Close() // 主动关闭
16 | ListenAndServe() // 启动监听,阻塞
17 | SetNewConnect(func(listen ListenTcp, conn net.Conn) Connect)
18 | }
19 |
20 | // 连接实例
21 | type Connect interface {
22 | SetHeader(header Header)
23 | Header() Header
24 | GetCon() net.Conn
25 | Close()
26 | Id() uint32
27 | SetUserId(uid uint64)
28 | UserId() uint64
29 | GroupsId() map[uint64]struct{}
30 | SetGroupId(id uint64)
31 | DeleteGroupId(id uint64)
32 | Send(msg interface{}) error
33 | SendByte(msg []byte) error
34 | SendString(msg string) error
35 | GetIp() uint32
36 | GetPort() uint16
37 | SetExtData(bytes []byte)
38 | ExtData() []byte
39 | }
40 |
41 | type Event interface {
42 | OnStart(listen ListenTcp)
43 | // 新链接
44 | OnConnect(connect Connect)
45 | // 新信息
46 | OnMessage(connect Connect, message []byte)
47 | // 链接关闭
48 | OnClose(connect Connect)
49 | // 发送错误
50 | OnError(listen ListenTcp, err error)
51 | }
52 |
53 | type Protocol interface {
54 | // 初始化
55 | Init()
56 | // 第一次连接,通常获取头信息
57 | OnConnect(conn net.Conn) (Header, error)
58 | // 读入处理
59 | Read(conn net.Conn) ([]byte, error)
60 | // 发送处理
61 | Write(conn net.Conn, msg []byte) error
62 | }
63 |
64 | type Header interface {
65 | Has(key string) bool
66 | Get(key string) string
67 | Set(data string)
68 | }
69 |
--------------------------------------------------------------------------------
/network/Url.go:
--------------------------------------------------------------------------------
1 | package network
2 |
3 | import (
4 | "net/url"
5 | "strconv"
6 | "strings"
7 | )
8 |
9 | type Url struct {
10 | Origin string // ws://host:port
11 | Scheme string
12 | Host string // host:port
13 | Path string // test.go
14 | Ip string
15 | Port uint16
16 | }
17 |
18 | func NewUrl(addr string) *Url {
19 | parse, err := url.Parse(addr)
20 | if err != nil {
21 | panic("地址格式错误")
22 | }
23 | arr := strings.Split(parse.Host, ":")
24 | port, _ := strconv.Atoi(parse.Port())
25 | return &Url{
26 | Origin: parse.Scheme + "://" + parse.Host,
27 | Scheme: parse.Scheme,
28 | Host: parse.Host,
29 | Path: parse.Path,
30 | Ip: arr[0],
31 | Port: uint16(port),
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/network/error/Errors.go:
--------------------------------------------------------------------------------
1 | package error
2 |
3 | import (
4 | "fmt"
5 | "goworker/network"
6 | )
7 |
8 | // 连接失败
9 | type ListenError struct {
10 | Address *network.Url
11 | }
12 |
13 | func (e *ListenError) Error() string {
14 | return fmt.Sprintf("连接失败 :%s", e.Address.Host)
15 | }
16 |
--------------------------------------------------------------------------------
/network/protocol/PackageLenProtocol.go:
--------------------------------------------------------------------------------
1 | package protocol
2 |
3 | import (
4 | "encoding/binary"
5 | "goworker/network"
6 | "net"
7 | )
8 |
9 | var PackageLen uint8 = 4
10 |
11 | // 定长协议,长度头 + 报文
12 | type PackageLenProtocol struct {
13 | PackageLen uint8
14 | }
15 |
16 | func (self *PackageLenProtocol) Init() {
17 | if self.PackageLen == 0 {
18 | self.PackageLen = PackageLen
19 | }
20 | }
21 |
22 | func (*PackageLenProtocol) OnConnect(conn net.Conn) (network.Header, error) {
23 | return nil, nil
24 | }
25 |
26 | func (self *PackageLenProtocol) Read(conn net.Conn) ([]byte, error) {
27 | var buf = make([]byte, self.PackageLen)
28 | _, err := conn.Read(buf)
29 | if err != nil {
30 | return nil, err
31 | }
32 | PackageLen := uint32(binary.BigEndian.Uint32(buf))
33 | var data = make([]byte, PackageLen-4)
34 | _, err = conn.Read(data)
35 | if err != nil {
36 | return nil, err
37 | }
38 |
39 | return data, nil
40 | }
41 |
42 | func (*PackageLenProtocol) Write(conn net.Conn, msg []byte) error {
43 | var buf32 = make([]byte, 4)
44 | packLen := len(msg) + 4
45 | binary.BigEndian.PutUint32(buf32, uint32(packLen))
46 | msg = append(buf32, msg...)
47 | _, err := conn.Write(msg)
48 | return err
49 | }
50 |
--------------------------------------------------------------------------------
/network/protocol/TextProtocol.go:
--------------------------------------------------------------------------------
1 | package protocol
2 |
3 | import (
4 | "bytes"
5 | "goworker/network"
6 | "net"
7 | )
8 |
9 | type TextProtocol struct {
10 | delim byte
11 | }
12 |
13 | func (t *TextProtocol) Init() {
14 | t.delim = '\n'
15 | }
16 |
17 | func (t *TextProtocol) OnConnect(conn net.Conn) (network.Header, error) {
18 | return nil, nil
19 | }
20 |
21 | func (t *TextProtocol) Read(conn net.Conn) ([]byte, error) {
22 | var message = make([]byte, 1024)
23 | var start = 0
24 | var count = 0
25 | for {
26 | w, err := conn.Read(message[start:])
27 | if err != nil {
28 | return nil, err
29 | }
30 | index := bytes.IndexByte(message[start:start+w], t.delim)
31 | if index >= 0 {
32 | count = start + index
33 | break
34 | }
35 | start = start + w
36 | }
37 |
38 | return message[:count], nil
39 | }
40 |
41 | func (t *TextProtocol) Write(conn net.Conn, msg []byte) error {
42 | msg = append(msg, t.delim)
43 | _, err := conn.Write(msg)
44 | return err
45 | }
46 |
--------------------------------------------------------------------------------
/network/protocol/WsClientProtocol.go:
--------------------------------------------------------------------------------
1 | package protocol
2 |
3 | import (
4 | "bytes"
5 | "encoding/base64"
6 | "encoding/binary"
7 | "errors"
8 | "goworker/network"
9 | "goworker/network/protocol/lib"
10 | "math/rand"
11 | "net"
12 | )
13 |
14 | // 客户端端websocket协议
15 | type WsProtocol struct {
16 | // 本地缓冲区
17 | cacheByte []byte
18 | // 缓冲长度
19 | cacheCount int
20 | }
21 |
22 | func (w *WsProtocol) Init() {
23 |
24 | }
25 |
26 | func (w *WsProtocol) OnConnect(conn net.Conn) (network.Header, error) {
27 | w.cacheByte = make([]byte, 0)
28 |
29 | // 发送请求头
30 | strHeader := "GET / HTTP/1.1\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nHost: "
31 | strHeader += conn.RemoteAddr().String() + "\r\n"
32 | strHeader += "Origin: http://" + conn.RemoteAddr().String() + "\r\n"
33 | strHeader += "Sec-WebSocket-Key:" + base64.StdEncoding.EncodeToString(randSeq(16)) + "\r\n"
34 | strHeader += "Sec-WebSocket-Version: 13\r\n\r\n"
35 | conn.Write([]byte(strHeader))
36 |
37 | // 获取协议头
38 | byteHeader, err := w.getHeader(conn)
39 | header := lib.MessageHeader{}
40 | header.Set(string(byteHeader))
41 | return &header, err
42 | }
43 |
44 | func (w *WsProtocol) Read(conn net.Conn) ([]byte, error) {
45 | // 第一个字节:FIN + RSV1-3 + OPCODE
46 | opcodeByte, err := w.readConnOrCache(conn, 1)
47 | if err != nil {
48 | return nil, err
49 | }
50 | FIN := opcodeByte[0] >> 7
51 | // RSV1 := opcodeByte[0] >> 6 & 1 // 自定义协议
52 | // RSV2 := opcodeByte[0] >> 5 & 1 // 自定义协议
53 | // RSV3 := opcodeByte[0] >> 4 & 1 // 自定义协议
54 | // OPCODE := opcodeByte[0] & 15
55 | //
56 | // log.Println(RSV1, RSV2, RSV3, OPCODE)
57 |
58 | // 第二个字节,Mask + Payload length
59 | payloadLenByte, err := w.readConnOrCache(conn, 1)
60 | payloadLen := int(payloadLenByte[0] & 0x7F) // 有效负载
61 | // mask := payloadLenByte[0] >> 7
62 |
63 | switch payloadLen {
64 | case 126: // 两个字节表示的是一个16进制无符号数,这个数用来表示传输数据的长度
65 | temLen, _ := w.readConnOrCache(conn, 2)
66 | payloadLen = int(binary.BigEndian.Uint16(temLen))
67 | case 127: // 8个字节表示的一个64位无符合数,这个数用来表示传输数据的长度
68 | temLen, _ := w.readConnOrCache(conn, 8)
69 | payloadLen = int(binary.BigEndian.Uint64(temLen))
70 | }
71 |
72 | msg := make([]byte, payloadLen)
73 | msg, err = w.readConnOrCache(conn, payloadLen)
74 | if err != nil {
75 | return nil, err
76 | }
77 |
78 | if FIN == 1 {
79 | // 最后的消息片断
80 | return msg, err
81 | }
82 |
83 | nextMsg, err := w.Read(conn)
84 | msg = append(msg, nextMsg...)
85 | return msg, err
86 | }
87 |
88 | func (w *WsProtocol) Write(conn net.Conn, msg []byte) error {
89 | length := len(msg)
90 | sendByte := make([]byte, 0)
91 | sendByte = append(sendByte, []byte{WebsocketMessageType}...)
92 |
93 | var payLenByte byte
94 | switch {
95 | case length <= 125:
96 | payLenByte = byte(0x80) | byte(length)
97 | sendByte = append(sendByte, []byte{payLenByte}...)
98 | case length <= 65536:
99 | payLenByte = byte(0x80) | byte(0x7e)
100 | sendByte = append(sendByte, []byte{payLenByte}...)
101 | // 随后的两个字节表示的是一个16进制无符号数,用来表示传输数据的长度
102 | payLenByte2 := make([]byte, 2)
103 | binary.BigEndian.PutUint16(payLenByte2, uint16(length))
104 | sendByte = append(sendByte, payLenByte2...)
105 | default:
106 | payLenByte = byte(0x80) | byte(0x7f)
107 | sendByte = append(sendByte, []byte{payLenByte}...)
108 | // 随后的是8个字节表示的一个64位无符合数,这个数用来表示传输数据的长度
109 | payLenByte8 := make([]byte, 8)
110 | binary.BigEndian.PutUint64(payLenByte8, uint64(length))
111 | sendByte = append(sendByte, payLenByte8...)
112 | }
113 | n := rand.Uint32()
114 | MaskingKey := [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)}
115 | sendByte = append(sendByte, MaskingKey[:]...)
116 |
117 | for i := 0; i < length; i++ {
118 | msg[i] ^= MaskingKey[i%4]
119 | }
120 | sendByte = append(sendByte, msg...)
121 | _, err := conn.Write(sendByte)
122 | return err
123 | }
124 |
125 | // 读取指定长度数据
126 | func (w *WsProtocol) readConnOrCache(conn net.Conn, count int) ([]byte, error) {
127 | if w.cacheCount > 0 {
128 | // 拥有缓冲数据
129 | if count <= w.cacheCount {
130 | // 缓冲数据比需要的还要大,直接拿取
131 | msg := w.cacheByte[:count]
132 | w.cacheCount = w.cacheCount - count
133 | w.cacheByte = w.cacheByte[count:]
134 | return msg, nil
135 | } else {
136 | // 缓冲数据不足,剩余需要的位数,多读取一点,可以优化速度
137 | data := make([]byte, count+512)
138 | cacheCount, err := conn.Read(data)
139 | if err != nil {
140 | return nil, errors.New("读取数据失败")
141 | }
142 | w.cacheCount = w.cacheCount + cacheCount
143 | w.cacheByte = append(w.cacheByte, data[:cacheCount]...)
144 | return w.readConnOrCache(conn, count)
145 | }
146 | } else {
147 | // 缓冲是空的
148 | data := make([]byte, 1024)
149 | cacheCount, err := conn.Read(data)
150 | if err != nil {
151 | return nil, errors.New("读取数据失败")
152 | }
153 | w.cacheCount = cacheCount
154 | w.cacheByte = append(w.cacheByte, data[:cacheCount]...)
155 | return w.readConnOrCache(conn, count)
156 | }
157 | }
158 |
159 | func (w *WsProtocol) getHeader(conn net.Conn) ([]byte, error) {
160 | data := make([]byte, 1024)
161 | count, err := conn.Read(data)
162 | if err != nil {
163 | return nil, errors.New("获取协议头信息错误")
164 | }
165 |
166 | sep := []byte("\r\n\r\n")
167 | index := bytes.Index(data, sep)
168 | if index > 0 {
169 | // 一般都是比较小数据的头部
170 | if count != index+4 {
171 | w.cacheByte = append(w.cacheByte, data[index+4:count]...)
172 | w.cacheCount = count - index - 4
173 | }
174 | return data[:index], nil
175 | } else {
176 | return nil, errors.New("协议头异常,不存在分隔符也不应超过1024位")
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/network/protocol/WstServerProtocol.go:
--------------------------------------------------------------------------------
1 | package protocol
2 |
3 | import (
4 | "bytes"
5 | "crypto/sha1"
6 | "encoding/base64"
7 | "encoding/binary"
8 | "errors"
9 | "goworker/network"
10 | "goworker/network/protocol/lib"
11 | "io"
12 | "math/rand"
13 | "net"
14 | "time"
15 | )
16 |
17 | // websocket 协议格式
18 | var WebsocketMessageType byte = 0x81
19 |
20 | // 二进制信息
21 | const BinaryMessage byte = 0x82
22 |
23 | // 服务端websocket协议
24 | type WebsocketProtocol struct {
25 | // 本地缓冲区
26 | cacheByte []byte
27 | // 缓冲长度
28 | cacheCount int
29 | }
30 |
31 | func randSeq(l int) []byte {
32 | bytes2 := []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
33 | var result []byte
34 | r := rand.New(rand.NewSource(time.Now().UnixNano()))
35 | for i := 0; i < l; i++ {
36 | result = append(result, bytes2[r.Intn(len(bytes2))])
37 | }
38 | return result
39 | }
40 |
41 | func (w *WebsocketProtocol) Init() {
42 |
43 | }
44 |
45 | func (w *WebsocketProtocol) OnConnect(conn net.Conn) (network.Header, error) {
46 | w.cacheByte = make([]byte, 0)
47 | // 获取协议头
48 | byteHeader, err := w.getHeader(conn)
49 | header := lib.MessageHeader{}
50 | header.Set(string(byteHeader))
51 | Upgrade := header.Get("Upgrade")
52 | if Upgrade != "websocket" {
53 | return nil, errors.New("升级的协议不是websocket")
54 | }
55 | guid := "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
56 | h := sha1.New()
57 | _, _ = io.WriteString(h, header.Get("Sec-WebSocket-Key")+guid)
58 | accept := make([]byte, 28)
59 | base64.StdEncoding.Encode(accept, h.Sum(nil))
60 | // 返回成功请求头
61 | strHeader := "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\n"
62 | strHeader += "Sec-WebSocket-Accept:" + string(accept) + "\r\n\r\n"
63 | _, _ = conn.Write([]byte(strHeader))
64 | return &header, err
65 | }
66 |
67 | func (w *WebsocketProtocol) Read(conn net.Conn) ([]byte, error) {
68 | // 第一个字节:FIN + RSV1-3 + OPCODE
69 | opcodeByte, err := w.readConnOrCache(conn, 1)
70 | if err != nil {
71 | return nil, err
72 | }
73 | FIN := opcodeByte[0] >> 7
74 | // RSV1 := opcodeByte[0] >> 6 & 1 // 自定义协议
75 | // RSV2 := opcodeByte[0] >> 5 & 1 // 自定义协议
76 | // RSV3 := opcodeByte[0] >> 4 & 1 // 自定义协议
77 | // OPCODE := opcodeByte[0] & 15
78 | //
79 | // log.Println(RSV1, RSV2, RSV3, OPCODE)
80 |
81 | // 第二个字节,Mask + Payload length
82 | payloadLenByte, err := w.readConnOrCache(conn, 1)
83 | payloadLen := int(payloadLenByte[0] & 0x7F) // 有效负载
84 | // mask := payloadLenByte[0] >> 7
85 |
86 | switch payloadLen {
87 | case 126: // 两个字节表示的是一个16进制无符号数,这个数用来表示传输数据的长度
88 | temLen, _ := w.readConnOrCache(conn, 2)
89 | payloadLen = int(binary.BigEndian.Uint16(temLen))
90 | case 127: // 8个字节表示的一个64位无符合数,这个数用来表示传输数据的长度
91 | temLen, _ := w.readConnOrCache(conn, 8)
92 | payloadLen = int(binary.BigEndian.Uint64(temLen))
93 | }
94 |
95 | msg := make([]byte, payloadLen)
96 | // 掩码读取
97 | maskingKey, err := w.readConnOrCache(conn, 4)
98 | if err != nil {
99 | return nil, err
100 | }
101 | payloadDataByte, err := w.readConnOrCache(conn, payloadLen)
102 | if err != nil {
103 | return nil, err
104 | }
105 | for i := 0; i < payloadLen; i++ {
106 | msg[i] = payloadDataByte[i] ^ maskingKey[i%4]
107 | }
108 | if FIN == 1 {
109 | // 最后的消息片断
110 | return msg, err
111 | }
112 | nextMsg, err := w.Read(conn)
113 | msg = append(msg, nextMsg...)
114 | return msg, err
115 | }
116 |
117 | func (w *WebsocketProtocol) Write(conn net.Conn, msg []byte) error {
118 | length := len(msg)
119 | sendByte := make([]byte, 0)
120 | sendByte = append(sendByte, []byte{WebsocketMessageType}...)
121 |
122 | var payLenByte byte
123 | switch {
124 | case length <= 125:
125 | payLenByte = byte(0x00) | byte(length)
126 | sendByte = append(sendByte, []byte{payLenByte}...)
127 | case length <= 65536:
128 | payLenByte = byte(0x00) | byte(126)
129 | sendByte = append(sendByte, []byte{payLenByte}...)
130 | payLenByte2 := make([]byte, 2)
131 | binary.BigEndian.PutUint16(payLenByte2, uint16(length))
132 | sendByte = append(sendByte, payLenByte2...)
133 | default:
134 | payLenByte = byte(0x00) | byte(127)
135 | sendByte = append(sendByte, []byte{payLenByte}...)
136 | payLenByte8 := make([]byte, 8)
137 | binary.BigEndian.PutUint64(payLenByte8, uint64(length))
138 | sendByte = append(sendByte, payLenByte8...)
139 | }
140 | sendByte = append(sendByte, msg...)
141 | _, err := conn.Write(sendByte)
142 | return err
143 | }
144 |
145 | // 读取指定长度数据
146 | func (w *WebsocketProtocol) readConnOrCache(conn net.Conn, count int) ([]byte, error) {
147 | if w.cacheCount > 0 {
148 | // 拥有缓冲数据
149 | if count <= w.cacheCount {
150 | // 缓冲数据比需要的还要大,直接拿取
151 | msg := w.cacheByte[:count]
152 | w.cacheCount = w.cacheCount - count
153 | w.cacheByte = w.cacheByte[count:]
154 | return msg, nil
155 | } else {
156 | // 缓冲数据不足,剩余需要的位数,多读取一点,可以优化速度
157 | data := make([]byte, count+512)
158 | cacheCount, err := conn.Read(data)
159 | if err != nil {
160 | return nil, errors.New("读取数据失败")
161 | }
162 | w.cacheCount = w.cacheCount + cacheCount
163 | w.cacheByte = append(w.cacheByte, data[:cacheCount]...)
164 | return w.readConnOrCache(conn, count)
165 | }
166 | } else {
167 | // 缓冲是空的
168 | data := make([]byte, 1024)
169 | cacheCount, err := conn.Read(data)
170 | if err != nil {
171 | return nil, errors.New("读取数据失败")
172 | }
173 | w.cacheCount = cacheCount
174 | w.cacheByte = append(w.cacheByte, data[:cacheCount]...)
175 | return w.readConnOrCache(conn, count)
176 | }
177 | }
178 |
179 | func (w *WebsocketProtocol) getHeader(conn net.Conn) ([]byte, error) {
180 | data := make([]byte, 1024)
181 | count, err := conn.Read(data)
182 | if err != nil {
183 | return nil, errors.New("获取协议头信息错误")
184 | }
185 |
186 | sep := []byte("\r\n\r\n")
187 | index := bytes.Index(data, sep)
188 | if index > 0 {
189 | // 一般都是比较小数据的头部
190 | if count != index+4 {
191 | w.cacheByte = append(w.cacheByte, data[index+4:count]...)
192 | w.cacheCount = count - index - 4
193 | }
194 | return data[:index], nil
195 | } else {
196 | return nil, errors.New("协议头异常,不存在分隔符也不应超过1024位")
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/network/protocol/lib/Header.go:
--------------------------------------------------------------------------------
1 | package lib
2 |
3 | import (
4 | "strings"
5 | )
6 |
7 | type MessageHeader struct {
8 | header map[string]string
9 | }
10 |
11 | func (h *MessageHeader) Has(key string) bool {
12 | _, ok := h.header[key]
13 | return ok
14 | }
15 |
16 | func (h *MessageHeader) Get(key string) string {
17 | return h.header[key]
18 | }
19 |
20 | func (h *MessageHeader) Set(data string) {
21 | h.header = map[string]string{}
22 | arr := strings.Split(data, "\r\n")
23 | for _, value := range arr[1:] {
24 | index := strings.Index(value, ":")
25 | if index >= 0 {
26 | h.header[value[:index]] = strings.TrimSpace(value[index+1:])
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/network/tcp/Build.go:
--------------------------------------------------------------------------------
1 | package tcp
2 |
3 | import (
4 | "goworker/network"
5 | "goworker/network/protocol"
6 | )
7 |
8 | func NewClient(address string) network.ListenTcp {
9 | url := network.NewUrl(address)
10 | client := Client{}
11 | switch url.Scheme {
12 | case "ws":
13 | client.SetProtocol(&protocol.WsProtocol{})
14 | case "text":
15 | client.SetProtocol(&protocol.TextProtocol{})
16 | case "pack":
17 | client.SetProtocol(&protocol.PackageLenProtocol{})
18 | default:
19 | panic("ws or text")
20 | }
21 | client.SetUrl(url)
22 | return &client
23 | }
24 |
25 | func NewServer(address string) network.ListenTcp {
26 | url := network.NewUrl(address)
27 | server := Server{}
28 | switch url.Scheme {
29 | case "ws":
30 | server.SetProtocol(&protocol.WebsocketProtocol{})
31 | case "text":
32 | server.SetProtocol(&protocol.TextProtocol{})
33 | case "pack":
34 | server.SetProtocol(&protocol.PackageLenProtocol{})
35 | default:
36 | panic("ws、text、pack")
37 | }
38 | server.SetUrl(url)
39 | return &server
40 | }
41 |
--------------------------------------------------------------------------------
/network/tcp/Client.go:
--------------------------------------------------------------------------------
1 | package tcp
2 |
3 | import (
4 | "fmt"
5 | error2 "goworker/network/error"
6 | "log"
7 | "net"
8 | )
9 |
10 | type Client struct {
11 | Listen
12 | }
13 |
14 | func (c *Client) ListenAndServe() {
15 | tcpAddr, err := net.ResolveTCPAddr("tcp4", c.url.Host)
16 | fmt.Println(c.url.Host)
17 | c.conn, err = net.DialTCP("tcp", nil, tcpAddr)
18 | fmt.Println(tcpAddr)
19 | if err != nil {
20 | go c.event.OnError(c, &error2.ListenError{c.url})
21 | log.Printf("tcp client 启动失败, err : %v\n", err.Error())
22 | return
23 | }
24 | c.id += 1
25 | go c.event.OnStart(c)
26 |
27 | if c.newConnect == nil {
28 | c.newConnect = NewConnect
29 | }
30 | Connect := c.newConnect(c, c.conn)
31 | c.protocol.Init()
32 | header, err := c.protocol.OnConnect(c.conn)
33 | if err != nil {
34 | _ = c.conn.Close()
35 | go c.event.OnError(c, &error2.ListenError{c.url})
36 | log.Printf("%v\n", err.Error())
37 | return
38 | }
39 | Connect.SetHeader(header)
40 | go c.event.OnConnect(Connect)
41 |
42 | for {
43 | msg, err := c.protocol.Read(c.conn)
44 | if err != nil {
45 | c.event.OnClose(Connect)
46 | return
47 | }
48 | c.event.OnMessage(Connect, msg)
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/network/tcp/Connect.go:
--------------------------------------------------------------------------------
1 | package tcp
2 |
3 | import (
4 | "errors"
5 | "goworker/network"
6 | "net"
7 | )
8 |
9 | var id uint32
10 |
11 | type Connection struct {
12 | ConnectTcp
13 | }
14 |
15 | func (c *Connection) Send(msg interface{}) error {
16 | switch msg.(type) {
17 | case []byte:
18 | return c.SendByte(msg.([]byte))
19 | case string:
20 | return c.SendString(msg.(string))
21 | }
22 | return errors.New("不支持的类型")
23 | }
24 |
25 | func (c *Connection) SetUserId(uid uint64) {
26 | c.userId = uid
27 | }
28 |
29 | func (c *Connection) UserId() uint64 {
30 | return c.userId
31 | }
32 |
33 | func (c *Connection) SetGroupId(groupsId uint64) {
34 | c.groupsId[groupsId] = struct{}{}
35 | }
36 |
37 | func (c *Connection) DeleteGroupId(groupsId uint64) {
38 | delete(c.groupsId, groupsId)
39 | }
40 |
41 | func (c *Connection) GroupsId() map[uint64]struct{} {
42 | return c.groupsId
43 | }
44 |
45 | func NewConnect(listen network.ListenTcp, conn net.Conn) network.Connect {
46 | id = id + 1
47 | url := network.NewUrl(listen.Url().Scheme + "://" + listen.Url().Host)
48 | return &Connection{
49 | ConnectTcp: ConnectTcp{
50 | id: id,
51 | userId: 0,
52 | url: url,
53 | conn: conn,
54 | Listen: listen,
55 | },
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/network/tcp/ConnectTcp.go:
--------------------------------------------------------------------------------
1 | package tcp
2 |
3 | import (
4 | "encoding/binary"
5 | "goworker/network"
6 | "net"
7 | "regexp"
8 | )
9 |
10 | type ConnectTcp struct {
11 | ip uint32
12 | id uint32
13 | //clientId string
14 | userId uint64
15 | groupsId map[uint64]struct{}
16 | url *network.Url
17 | conn net.Conn
18 | Listen network.ListenTcp
19 | header network.Header
20 | extData []byte
21 | }
22 |
23 | func (c *ConnectTcp) GetIp() uint32 {
24 | if c.ip != 0 {
25 | return c.ip
26 | }
27 | ipStr := c.conn.RemoteAddr().String()
28 | r := `^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})`
29 | reg, err := regexp.Compile(r)
30 | if err != nil {
31 | return 0
32 | }
33 | ips := reg.FindStringSubmatch(ipStr)
34 | if ips == nil {
35 | return 0
36 | }
37 |
38 | c.ip = network.Ip2long(ips[0])
39 | return c.ip
40 | }
41 |
42 | func (c *ConnectTcp) GetPort() uint16 {
43 | return c.url.Port
44 | }
45 |
46 | func (c *ConnectTcp) GetCon() net.Conn {
47 | return c.conn
48 | }
49 |
50 | func (c *ConnectTcp) Close() {
51 | _ = c.conn.Close()
52 | }
53 |
54 | func (c *ConnectTcp) Id() uint32 {
55 | return c.id
56 | }
57 |
58 | //func (c *ConnectTcp) SetClientId(uid string) {
59 | // c.clientId = uid
60 | //}
61 | //
62 | //func (c *ConnectTcp) ClientId() string {
63 | // return c.clientId
64 | //}
65 |
66 | func (c *ConnectTcp) Url() *network.Url {
67 | return c.url
68 | }
69 |
70 | func (c *ConnectTcp) SendByte(msg []byte) error {
71 | var buf32 = make([]byte, 4)
72 | binary.BigEndian.PutUint32(buf32, uint32(len(msg)))
73 | err := c.Listen.Protocol().Write(c.conn, append(buf32, msg...))
74 | if err != nil {
75 | return err
76 | }
77 | return nil
78 | }
79 |
80 | func (c *ConnectTcp) SendString(msg string) error {
81 | var buf32 = make([]byte, 4)
82 | binary.BigEndian.PutUint32(buf32, uint32(len(msg)))
83 | err := c.Listen.Protocol().Write(c.conn, append(buf32, []byte(msg)...))
84 | if err != nil {
85 | return err
86 | }
87 | return nil
88 | }
89 |
90 | func (c *ConnectTcp) SetHeader(header network.Header) {
91 | c.header = header
92 | }
93 | func (c *ConnectTcp) Header() network.Header {
94 | return c.header
95 | }
96 |
97 | func (c *ConnectTcp) SetExtData(bytes []byte) {
98 | c.extData = bytes
99 | }
100 |
101 | func (c *ConnectTcp) ExtData() []byte {
102 | return c.extData
103 | }
104 |
--------------------------------------------------------------------------------
/network/tcp/Listen.go:
--------------------------------------------------------------------------------
1 | package tcp
2 |
3 | import (
4 | "goworker/network"
5 | "net"
6 | )
7 |
8 | type Listen struct {
9 | id uint32
10 | url *network.Url
11 | event network.Event
12 | protocol network.Protocol
13 | conn net.Conn
14 | newConnect func(listen network.ListenTcp, conn net.Conn) network.Connect
15 | }
16 |
17 | func (c *Listen) SetUrl(address *network.Url) {
18 | c.url = address
19 | }
20 |
21 | func (c *Listen) Url() *network.Url {
22 | return c.url
23 | }
24 |
25 | func (c *Listen) SetEvent(event network.Event) {
26 | c.event = event
27 | }
28 |
29 | func (c *Listen) Event() network.Event {
30 | return c.event
31 | }
32 |
33 | func (c *Listen) SetProtocol(protocol network.Protocol) {
34 | c.protocol = protocol
35 | }
36 |
37 | func (c *Listen) Protocol() network.Protocol {
38 | return c.protocol
39 | }
40 |
41 | func (c *Listen) Close() {
42 | _ = c.conn.Close()
43 | }
44 |
45 | func (c *Listen) SetNewConnect(new func(listen network.ListenTcp, conn net.Conn) network.Connect) {
46 | c.newConnect = new
47 | }
48 |
--------------------------------------------------------------------------------
/network/tcp/Server.go:
--------------------------------------------------------------------------------
1 | package tcp
2 |
3 | import (
4 | "fmt"
5 | error2 "goworker/network/error"
6 | "log"
7 | "net"
8 | )
9 |
10 | type Server struct {
11 | Listen
12 | }
13 |
14 | /*
15 | 启动监听
16 | */
17 | func (this *Server) ListenAndServe() {
18 | listener, err := net.Listen("tcp", this.Url().Host)
19 | if err != nil {
20 | go this.event.OnError(this, &error2.ListenError{this.Url()})
21 | log.Fatal("Error starting TCP server.", this.Url().Host, err)
22 | return
23 | }
24 | if this.newConnect == nil {
25 | this.newConnect = NewConnect
26 | }
27 | defer this.Close()
28 | this.protocol.Init()
29 | this.event.OnStart(this)
30 | for {
31 | con, _ := listener.Accept()
32 | this.id += 1
33 | go this.newConnection(con)
34 | }
35 | }
36 |
37 | /*
38 | 新的连接
39 | */
40 | func (this *Server) newConnection(conn net.Conn) {
41 | Connect := this.newConnect(this, conn)
42 | header, err := this.protocol.OnConnect(conn)
43 | fmt.Println(header)
44 | if err != nil {
45 | _ = this.conn.Close()
46 | go this.event.OnError(this, &error2.ListenError{this.url})
47 | log.Printf("%v\n", err.Error())
48 | return
49 | }
50 | Connect.SetHeader(header)
51 | defer this.event.OnClose(Connect)
52 | go this.event.OnConnect(Connect)
53 |
54 | for {
55 | message, err := this.protocol.Read(conn)
56 | if err != nil {
57 | Connect.Close()
58 | break
59 | }
60 | go this.event.OnMessage(Connect, message)
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/network/tcpclient/Tcpclient.go:
--------------------------------------------------------------------------------
1 | package tcpclient
2 |
3 | import (
4 | "encoding/binary"
5 | "errors"
6 | "net"
7 | "sync"
8 | "time"
9 | )
10 |
11 | const limitMessageSize = 16384
12 |
13 | type Client interface {
14 | // GetHostAddr is used to get address of TCP host.
15 | GetHostAddr() (hostAddr string)
16 | // Send is used to send and get TCP data via TCP connection.
17 | Send(input []byte) (output []byte, err error)
18 | // Close is used to close all connections in connection pool.
19 | Close() (err error)
20 | }
21 |
22 | type defaultClient struct {
23 | status bool
24 | hostAddr string
25 | minConns int
26 | maxConns int
27 | idleConnTimeout time.Duration
28 | waitConnTimeout time.Duration
29 | clearPeriod time.Duration
30 | poolSize int
31 | poolCounter uint64
32 | poolLock sync.Mutex
33 | connPool chan *connection
34 | initDelay time.Duration
35 | maxRetry int
36 | }
37 |
38 | type connection struct {
39 | id uint64
40 | tcpConn net.Conn
41 | lastActive time.Time
42 | }
43 |
44 | func NewClient(hostAddr string, minConns, maxConns int, idleConnTimeout, waitConnTimeout, clearPeriod time.Duration) (client Client, err error) {
45 | c := &defaultClient{
46 | status: true,
47 | hostAddr: hostAddr,
48 | minConns: minConns,
49 | maxConns: maxConns,
50 | idleConnTimeout: idleConnTimeout,
51 | waitConnTimeout: waitConnTimeout,
52 | clearPeriod: clearPeriod,
53 | poolSize: 0,
54 | poolLock: sync.Mutex{},
55 | connPool: make(chan *connection, maxConns),
56 | initDelay: time.Millisecond * 10,
57 | maxRetry: 4,
58 | }
59 | for i := 0; i < c.minConns; i++ {
60 | if _, err = c.fillConnPool(false); err != nil {
61 | c.Close()
62 | return client, err
63 | }
64 | }
65 | go c.startPoolManager()
66 | return c, nil
67 | }
68 |
69 | // GetHostAddr is used to get address of TCP host.
70 | func (c *defaultClient) GetHostAddr() (hostAddr string) {
71 | return c.hostAddr
72 | }
73 |
74 | // Send is used to send and get TCP data via TCP connection.
75 | func (c *defaultClient) Send(input []byte) (output []byte, err error) {
76 | if !c.status {
77 | return nil, errors.New("all connections in connection pool are already closed")
78 | }
79 | conn := &connection{}
80 | select {
81 | case conn = <-c.connPool:
82 | case <-time.After(c.waitConnTimeout):
83 | conn, err = c.fillConnPool(true)
84 | if err != nil {
85 | return nil, err
86 | }
87 | }
88 | originConn := conn
89 | conn.lastActive = time.Now()
90 | defer func() {
91 | if conn == nil {
92 | c.drainConnPool(originConn, true)
93 | } else {
94 | c.connPool <- conn
95 | }
96 | }()
97 | retry(
98 | c.initDelay,
99 | c.maxRetry,
100 | func() {
101 | output, err = c.sendAndReceive(conn, input)
102 | },
103 | func() bool {
104 | if err != nil {
105 | _, err = c.drainConnPool(conn, true)
106 | if err != nil {
107 | return true
108 | }
109 | originConn = nil
110 | conn, err = c.fillConnPool(true)
111 | return true
112 | }
113 | return false
114 | },
115 | )
116 | return output, err
117 | }
118 |
119 | // Close is used to close all connections in connection pool.
120 | func (c *defaultClient) Close() (err error) {
121 | for empty := false; !empty && c.poolSize > 0; {
122 | conn := <-c.connPool
123 | empty, err = c.drainConnPool(conn, true)
124 | if err != nil {
125 | return err
126 | }
127 | }
128 | c.status = false
129 | return nil
130 | }
131 |
132 | func (c *defaultClient) sendAndReceive(conn *connection, input []byte) (output []byte, err error) {
133 | if conn == nil {
134 | return nil, errors.New("connection is empty")
135 | }
136 | // send data length
137 | dataSize := make([]byte, 4)
138 | binary.LittleEndian.PutUint32(dataSize, uint32(len(input)))
139 | _, err = conn.tcpConn.Write(dataSize)
140 | if err != nil {
141 | return nil, err
142 | }
143 | // send data
144 | for i := 0; i <= len(input)/limitMessageSize; i++ {
145 | start := i * limitMessageSize
146 | end := (i + 1) * limitMessageSize
147 | if end > len(input) {
148 | end = len(input)
149 | }
150 | _, err = conn.tcpConn.Write(input[start:end])
151 | if err != nil {
152 | return nil, err
153 | }
154 | }
155 | // set read timeout
156 | if err != nil {
157 | return nil, err
158 | }
159 |
160 | // receive data length
161 | _, err = conn.tcpConn.Read(dataSize)
162 | if err != nil {
163 | return nil, err
164 | }
165 | // receive data
166 | output = make([]byte, binary.LittleEndian.Uint32(dataSize))
167 | for i := 0; i <= len(output)/limitMessageSize; i++ {
168 | start := i * limitMessageSize
169 | end := (i + 1) * limitMessageSize
170 | if end > len(output) {
171 | end = len(output)
172 | }
173 | _, err = conn.tcpConn.Read(output[start:end])
174 | if err != nil {
175 | return nil, err
176 | }
177 | }
178 | return output, err
179 | }
180 |
181 | func (c *defaultClient) fillConnPool(getConn bool) (conn *connection, err error) {
182 | c.poolLock.Lock()
183 | defer c.poolLock.Unlock()
184 | if c.poolSize == c.maxConns {
185 | return nil, errors.New("connection pool is full")
186 | }
187 | tcpConn, err := net.Dial("tcp", c.hostAddr)
188 | if err != nil {
189 | return nil, err
190 | }
191 | c.poolCounter++
192 | conn = &connection{
193 | id: c.poolCounter,
194 | tcpConn: tcpConn,
195 | lastActive: time.Now(),
196 | }
197 | c.poolSize++
198 | if getConn {
199 | return conn, nil
200 | }
201 | c.connPool <- conn
202 | return nil, nil
203 | }
204 |
205 | func (c *defaultClient) startPoolManager() {
206 | for {
207 | if !c.status {
208 | return
209 | }
210 | poolLength := len(c.connPool)
211 | for i := 0; i < poolLength; i++ {
212 | conn := <-c.connPool
213 | if time.Since(conn.lastActive) > c.idleConnTimeout {
214 | _, _ = c.drainConnPool(conn, false)
215 | } else {
216 | c.connPool <- conn
217 | }
218 | }
219 | time.Sleep(c.clearPeriod)
220 | }
221 | }
222 |
223 | func (c *defaultClient) drainConnPool(conn *connection, forceMode bool) (empty bool, err error) {
224 | c.poolLock.Lock()
225 | defer c.poolLock.Unlock()
226 | if c.poolSize == 0 {
227 | return true, errors.New("connection pool is empty")
228 | }
229 | defer func() {
230 | if err != nil {
231 | c.connPool <- conn
232 | }
233 | }()
234 | if c.poolSize == c.minConns && !forceMode {
235 | err = errors.New("pool size cannot be lower than minimum number of connections")
236 | return false, err
237 | }
238 | c.poolSize--
239 | if conn != nil {
240 | err = conn.tcpConn.Close()
241 | }
242 | if err != nil {
243 | return false, err
244 | }
245 | empty = c.poolSize == 0
246 | return empty, nil
247 | }
248 |
249 | func retry(initDelay time.Duration, maxRetry int, processFn func(), retryCondFn func() bool) {
250 | processFn()
251 | delay := initDelay
252 | for i := 0; i < maxRetry && retryCondFn(); i++ {
253 | time.Sleep(delay)
254 | delay *= 2
255 | processFn()
256 | }
257 | }
258 |
--------------------------------------------------------------------------------
/register.log:
--------------------------------------------------------------------------------
1 | 2023/06/02 16:40:54 register server listening at: text://127.0.0.1:1238
2 |
--------------------------------------------------------------------------------
/utils/Config.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "fmt"
5 | "github.com/fsnotify/fsnotify"
6 | "github.com/spf13/viper"
7 | )
8 |
9 | type Config struct {
10 | Debug bool `mapstructure:"debug" json:"debug" yaml:"debug"`
11 | Gateway string `mapstructure:"gateway" json:"gateway" yaml:"gateway"`
12 | GatewayInternal string `mapstructure:"gatewayInternal" json:"gatewayInternal" yaml:"gatewayInternal"`
13 | Register string `mapstructure:"register" json:"register" yaml:"register"`
14 | Secret string `mapstructure:"secret" json:"secret" yaml:"secret"`
15 | }
16 |
17 | var GlobalConfig Config
18 |
19 | func init() {
20 | v := viper.New()
21 | v.SetConfigFile("config.yaml")
22 | err := v.ReadInConfig()
23 | if err != nil {
24 | panic(any(fmt.Errorf("Fatal error config file: %s \n", err)))
25 | }
26 | v.WatchConfig()
27 | v.OnConfigChange(func(e fsnotify.Event) {
28 | fmt.Println("config file changed:", e.Name)
29 | if err := v.Unmarshal(&GlobalConfig); err != nil {
30 | fmt.Println(err)
31 | }
32 | })
33 | if err := v.Unmarshal(&GlobalConfig); err != nil {
34 | fmt.Println(err)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/utils/Process.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "io/ioutil"
7 | "os"
8 | "os/signal"
9 | "path/filepath"
10 | "runtime"
11 | "strconv"
12 | "strings"
13 | "syscall"
14 | )
15 |
16 | func GetRootPath() string {
17 | dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
18 | if err != nil {
19 | dir, _ = os.Getwd()
20 | return dir
21 | }
22 | return dir
23 | }
24 |
25 | func GetRootFile() string {
26 | paths, fileName := filepath.Split(os.Args[0])
27 | ext := filepath.Ext(fileName)
28 | abs := strings.TrimSuffix(fileName, ext)
29 | return paths + abs
30 | }
31 |
32 | /*
33 | 保存pid
34 | 命令key 唯一标识
35 | */
36 | func SavePidToFile(key string) {
37 | pid := os.Getpid()
38 | path := GetRootFile() + "_" + key + ".lock"
39 | _ = ioutil.WriteFile(path, []byte(fmt.Sprintf("%d", pid)), 0666)
40 | }
41 |
42 | /*
43 | 删除pid文件
44 | 命令key 唯一标识
45 | */
46 | func DeleteSavePidToFile(key string) {
47 | path := GetRootFile() + "_" + key + ".lock"
48 | _ = os.Remove(path)
49 | }
50 |
51 | /*
52 | 获取pid
53 | 命令key 唯一标识
54 | */
55 | func GetPidForFile(key string) int {
56 | path := GetRootFile() + "_" + key + ".lock"
57 | str, err := ioutil.ReadFile(path)
58 | if err != nil {
59 | return 0
60 | }
61 | pid, err := strconv.Atoi(string(str))
62 | if err != nil {
63 | return 0
64 | }
65 | return pid
66 | }
67 |
68 | func ListenStopSignal(handle func(sig os.Signal)) {
69 | sigs := make(chan os.Signal, 1)
70 | signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
71 | go func() {
72 | sig := <-sigs
73 | handle(sig)
74 | }()
75 | }
76 |
77 | /*
78 | 停止进程
79 | 命令key 唯一标识
80 | windows 不发送信号,直接停止
81 | */
82 | func StopSignal(key string) error {
83 | pid := GetPidForFile(key)
84 | if pid == 0 {
85 | return errors.New("找不到pid记录文件")
86 | }
87 | // 通过pid获取子进程
88 | pro, err := os.FindProcess(pid)
89 | if err != nil {
90 | return errors.New("找不到进程信息,文件过期")
91 | }
92 | err = pro.Signal(syscall.SIGINT)
93 | if err != nil {
94 | if runtime.GOOS == "windows" {
95 | err = pro.Kill()
96 | if err != nil {
97 | return nil
98 | }
99 | DeleteSavePidToFile(key)
100 | }
101 | return nil
102 | }
103 | return nil
104 | }
105 |
--------------------------------------------------------------------------------