├── .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 | ![](https://www.workerman.net/doc/gateway-worker/images/GatewayWorker.png) 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 | --------------------------------------------------------------------------------