@bigtyphoon/melo 1.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +55 -0
  3. package/bin/commadtest.ts +10 -0
  4. package/bin/commands/add.ts +43 -0
  5. package/bin/commands/init.ts +292 -0
  6. package/bin/commands/kill.ts +21 -0
  7. package/bin/commands/list.ts +60 -0
  8. package/bin/commands/masterha.ts +40 -0
  9. package/bin/commands/restart.ts +48 -0
  10. package/bin/commands/start.ts +65 -0
  11. package/bin/commands/stop.ts +26 -0
  12. package/bin/melo.ts +30 -0
  13. package/bin/utils/constants.ts +27 -0
  14. package/bin/utils/utils.ts +130 -0
  15. package/dist/bin/commadtest.js +9 -0
  16. package/dist/bin/commands/add.js +40 -0
  17. package/dist/bin/commands/init.js +279 -0
  18. package/dist/bin/commands/kill.js +21 -0
  19. package/dist/bin/commands/list.js +65 -0
  20. package/dist/bin/commands/masterha.js +36 -0
  21. package/dist/bin/commands/restart.js +45 -0
  22. package/dist/bin/commands/start.js +58 -0
  23. package/dist/bin/commands/stop.js +20 -0
  24. package/dist/bin/melo.js +26 -0
  25. package/dist/bin/utils/constants.js +28 -0
  26. package/dist/bin/utils/utils.js +134 -0
  27. package/dist/lib/application.js +888 -0
  28. package/dist/lib/common/manager/appManager.js +112 -0
  29. package/dist/lib/common/manager/taskManager.js +39 -0
  30. package/dist/lib/common/remote/backend/msgRemote.js +63 -0
  31. package/dist/lib/common/remote/frontend/channelRemote.js +78 -0
  32. package/dist/lib/common/remote/frontend/sessionRemote.js +76 -0
  33. package/dist/lib/common/service/backendSessionService.js +337 -0
  34. package/dist/lib/common/service/channelService.js +514 -0
  35. package/dist/lib/common/service/connectionService.js +95 -0
  36. package/dist/lib/common/service/filterService.js +112 -0
  37. package/dist/lib/common/service/handlerService.js +187 -0
  38. package/dist/lib/common/service/sessionService.js +610 -0
  39. package/dist/lib/components/backendSession.js +14 -0
  40. package/dist/lib/components/channel.js +13 -0
  41. package/dist/lib/components/connection.js +12 -0
  42. package/dist/lib/components/connector.js +437 -0
  43. package/dist/lib/components/dictionary.js +93 -0
  44. package/dist/lib/components/master.js +39 -0
  45. package/dist/lib/components/monitor.js +25 -0
  46. package/dist/lib/components/protobuf.js +156 -0
  47. package/dist/lib/components/proxy.js +236 -0
  48. package/dist/lib/components/pushScheduler.js +62 -0
  49. package/dist/lib/components/remote.js +127 -0
  50. package/dist/lib/components/server.js +63 -0
  51. package/dist/lib/components/session.js +20 -0
  52. package/dist/lib/connectors/commands/handshake.js +119 -0
  53. package/dist/lib/connectors/commands/heartbeat.js +67 -0
  54. package/dist/lib/connectors/commands/kick.js +15 -0
  55. package/dist/lib/connectors/common/coder.js +90 -0
  56. package/dist/lib/connectors/common/handler.js +57 -0
  57. package/dist/lib/connectors/hybrid/IHybridSocket.js +3 -0
  58. package/dist/lib/connectors/hybrid/switcher.js +100 -0
  59. package/dist/lib/connectors/hybrid/tcpprocessor.js +40 -0
  60. package/dist/lib/connectors/hybrid/tcpsocket.js +171 -0
  61. package/dist/lib/connectors/hybrid/wsprocessor.js +49 -0
  62. package/dist/lib/connectors/hybridconnector.js +89 -0
  63. package/dist/lib/connectors/hybridsocket.js +139 -0
  64. package/dist/lib/connectors/mqtt/generate.js +113 -0
  65. package/dist/lib/connectors/mqtt/mqttadaptor.js +81 -0
  66. package/dist/lib/connectors/mqtt/protocol.js +48 -0
  67. package/dist/lib/connectors/mqttconnector.js +107 -0
  68. package/dist/lib/connectors/mqttsocket.js +59 -0
  69. package/dist/lib/connectors/sioconnector.js +135 -0
  70. package/dist/lib/connectors/siosocket.js +69 -0
  71. package/dist/lib/connectors/udpconnector.js +76 -0
  72. package/dist/lib/connectors/udpsocket.js +93 -0
  73. package/dist/lib/filters/handler/serial.js +44 -0
  74. package/dist/lib/filters/handler/time.js +32 -0
  75. package/dist/lib/filters/handler/timeout.js +45 -0
  76. package/dist/lib/filters/handler/toobusy.js +36 -0
  77. package/dist/lib/filters/rpc/rpcLog.js +43 -0
  78. package/dist/lib/filters/rpc/toobusy.js +41 -0
  79. package/dist/lib/index.js +81 -0
  80. package/dist/lib/interfaces/IComponent.js +3 -0
  81. package/dist/lib/interfaces/IConnector.js +3 -0
  82. package/dist/lib/interfaces/IHandlerFilter.js +3 -0
  83. package/dist/lib/interfaces/ILifeCycle.js +3 -0
  84. package/dist/lib/interfaces/IPlugin.js +3 -0
  85. package/dist/lib/interfaces/IPushScheduler.js +3 -0
  86. package/dist/lib/interfaces/ISocket.js +3 -0
  87. package/dist/lib/interfaces/IStore.js +3 -0
  88. package/dist/lib/interfaces/define.js +3 -0
  89. package/dist/lib/master/master.js +129 -0
  90. package/dist/lib/master/starter.js +236 -0
  91. package/dist/lib/master/watchdog.js +120 -0
  92. package/dist/lib/melo.js +125 -0
  93. package/dist/lib/modules/console.js +436 -0
  94. package/dist/lib/modules/masterwatcher.js +98 -0
  95. package/dist/lib/modules/monitorwatcher.js +124 -0
  96. package/dist/lib/modules/onlineUser.js +69 -0
  97. package/dist/lib/modules/restartNotifyModule.js +107 -0
  98. package/dist/lib/modules/watchServer.js +737 -0
  99. package/dist/lib/monitor/monitor.js +80 -0
  100. package/dist/lib/pushSchedulers/buffer.js +96 -0
  101. package/dist/lib/pushSchedulers/direct.js +58 -0
  102. package/dist/lib/pushSchedulers/multi.js +80 -0
  103. package/dist/lib/server/server.js +500 -0
  104. package/dist/lib/util/appUtil.js +306 -0
  105. package/dist/lib/util/constants.js +117 -0
  106. package/dist/lib/util/countDownLatch.js +51 -0
  107. package/dist/lib/util/events.js +20 -0
  108. package/dist/lib/util/handlerHelper.js +8 -0
  109. package/dist/lib/util/log.js +14 -0
  110. package/dist/lib/util/moduleUtil.js +101 -0
  111. package/dist/lib/util/pathUtil.js +134 -0
  112. package/dist/lib/util/remoterHelper.js +8 -0
  113. package/dist/lib/util/utils.js +358 -0
  114. package/dist/test/application.js +522 -0
  115. package/dist/test/config/log4js.json +28 -0
  116. package/dist/test/config/master.json +9 -0
  117. package/dist/test/config/servers.json +6 -0
  118. package/dist/test/filters/handler/serial.js +41 -0
  119. package/dist/test/filters/handler/time.js +41 -0
  120. package/dist/test/filters/handler/timeout.js +41 -0
  121. package/dist/test/filters/handler/toobusy.js +57 -0
  122. package/dist/test/filters/rpc/rpcLog.js +22 -0
  123. package/dist/test/filters/rpc/toobusy.js +39 -0
  124. package/dist/test/manager/mockChannelManager.js +77 -0
  125. package/dist/test/manager/taskManager.js +68 -0
  126. package/dist/test/mock-base/app/servers/other-file +0 -0
  127. package/dist/test/mock-plugin/components/mockPlugin.js +10 -0
  128. package/dist/test/mock-plugin/events/mockEvent.js +12 -0
  129. package/dist/test/modules/console.js +242 -0
  130. package/dist/test/pomelo.js +19 -0
  131. package/dist/test/remote/channelRemote.js +159 -0
  132. package/dist/test/service/channel.js +134 -0
  133. package/dist/test/service/channelService.js +216 -0
  134. package/dist/test/service/connectionService.js +114 -0
  135. package/dist/test/service/filterService.js +144 -0
  136. package/dist/test/service/handlerService.js +65 -0
  137. package/dist/test/service/sessionService.js +387 -0
  138. package/dist/test/util/countDownLatch.js +70 -0
  139. package/dist/test/util/pathUtil.js +108 -0
  140. package/dist/test/util/utils.js +140 -0
  141. package/lib/application.ts +1240 -0
  142. package/lib/common/manager/appManager.ts +118 -0
  143. package/lib/common/manager/taskManager.ts +50 -0
  144. package/lib/common/remote/backend/msgRemote.ts +134 -0
  145. package/lib/common/remote/frontend/channelRemote.ts +91 -0
  146. package/lib/common/remote/frontend/sessionRemote.ts +91 -0
  147. package/lib/common/service/backendSessionService.ts +388 -0
  148. package/lib/common/service/channelService.ts +609 -0
  149. package/lib/common/service/connectionService.ts +112 -0
  150. package/lib/common/service/filterService.ts +118 -0
  151. package/lib/common/service/handlerService.ts +224 -0
  152. package/lib/common/service/sessionService.ts +731 -0
  153. package/lib/components/backendSession.ts +14 -0
  154. package/lib/components/channel.ts +11 -0
  155. package/lib/components/connection.ts +13 -0
  156. package/lib/components/connector.ts +533 -0
  157. package/lib/components/dictionary.ts +121 -0
  158. package/lib/components/master.ts +41 -0
  159. package/lib/components/monitor.ts +30 -0
  160. package/lib/components/protobuf.ts +208 -0
  161. package/lib/components/proxy.ts +282 -0
  162. package/lib/components/pushScheduler.ts +70 -0
  163. package/lib/components/remote.ts +166 -0
  164. package/lib/components/server.ts +71 -0
  165. package/lib/components/session.ts +22 -0
  166. package/lib/connectors/commands/handshake.ts +155 -0
  167. package/lib/connectors/commands/heartbeat.ts +83 -0
  168. package/lib/connectors/commands/kick.ts +11 -0
  169. package/lib/connectors/common/coder.ts +93 -0
  170. package/lib/connectors/common/handler.ts +62 -0
  171. package/lib/connectors/hybrid/IHybridSocket.ts +9 -0
  172. package/lib/connectors/hybrid/switcher.ts +142 -0
  173. package/lib/connectors/hybrid/tcpprocessor.ts +43 -0
  174. package/lib/connectors/hybrid/tcpsocket.ts +223 -0
  175. package/lib/connectors/hybrid/wsprocessor.ts +57 -0
  176. package/lib/connectors/hybridconnector.ts +134 -0
  177. package/lib/connectors/hybridsocket.ts +168 -0
  178. package/lib/connectors/mqtt/generate.ts +103 -0
  179. package/lib/connectors/mqtt/mqttadaptor.ts +114 -0
  180. package/lib/connectors/mqtt/protocol.ts +49 -0
  181. package/lib/connectors/mqttconnector.ts +134 -0
  182. package/lib/connectors/mqttsocket.ts +79 -0
  183. package/lib/connectors/sioconnector.ts +161 -0
  184. package/lib/connectors/siosocket.ts +85 -0
  185. package/lib/connectors/udpconnector.ts +113 -0
  186. package/lib/connectors/udpsocket.ts +110 -0
  187. package/lib/filters/handler/serial.ts +46 -0
  188. package/lib/filters/handler/time.ts +35 -0
  189. package/lib/filters/handler/timeout.ts +50 -0
  190. package/lib/filters/handler/toobusy.ts +37 -0
  191. package/lib/filters/rpc/rpcLog.ts +42 -0
  192. package/lib/filters/rpc/toobusy.ts +41 -0
  193. package/lib/index.ts +74 -0
  194. package/lib/interfaces/IComponent.ts +47 -0
  195. package/lib/interfaces/IConnector.ts +20 -0
  196. package/lib/interfaces/IHandlerFilter.ts +15 -0
  197. package/lib/interfaces/ILifeCycle.ts +16 -0
  198. package/lib/interfaces/IPlugin.ts +65 -0
  199. package/lib/interfaces/IPushScheduler.ts +52 -0
  200. package/lib/interfaces/ISocket.ts +26 -0
  201. package/lib/interfaces/IStore.ts +10 -0
  202. package/lib/interfaces/define.ts +15 -0
  203. package/lib/master/master.ts +148 -0
  204. package/lib/master/starter.ts +234 -0
  205. package/lib/master/watchdog.ts +135 -0
  206. package/lib/melo.ts +152 -0
  207. package/lib/modules/console.ts +465 -0
  208. package/lib/modules/masterwatcher.ts +120 -0
  209. package/lib/modules/monitorwatcher.ts +151 -0
  210. package/lib/modules/onlineUser.ts +78 -0
  211. package/lib/modules/restartNotifyModule.ts +128 -0
  212. package/lib/modules/watchServer.ts +766 -0
  213. package/lib/monitor/monitor.ts +99 -0
  214. package/lib/pushSchedulers/buffer.ts +117 -0
  215. package/lib/pushSchedulers/direct.ts +65 -0
  216. package/lib/pushSchedulers/multi.ts +94 -0
  217. package/lib/server/server.ts +554 -0
  218. package/lib/util/appUtil.ts +313 -0
  219. package/lib/util/constants.ts +154 -0
  220. package/lib/util/countDownLatch.ts +72 -0
  221. package/lib/util/events.ts +15 -0
  222. package/lib/util/handlerHelper.ts +5 -0
  223. package/lib/util/log.ts +11 -0
  224. package/lib/util/moduleUtil.ts +110 -0
  225. package/lib/util/pathUtil.ts +132 -0
  226. package/lib/util/remoterHelper.ts +68 -0
  227. package/lib/util/utils.ts +365 -0
  228. package/package.json +93 -0
  229. package/template/game-server/.vscode/launch.json +27 -0
  230. package/template/game-server/app/servers/connector/handler/entryHandler.ts +50 -0
  231. package/template/game-server/app/servers/connector/remote/authRemoter.ts +36 -0
  232. package/template/game-server/app.ts +30 -0
  233. package/template/game-server/app.ts.mqtt +32 -0
  234. package/template/game-server/app.ts.sio +36 -0
  235. package/template/game-server/app.ts.sio.wss +34 -0
  236. package/template/game-server/app.ts.udp +31 -0
  237. package/template/game-server/app.ts.wss +40 -0
  238. package/template/game-server/config/adminServer.json +5 -0
  239. package/template/game-server/config/adminUser.json +22 -0
  240. package/template/game-server/config/clientProtos.json +1 -0
  241. package/template/game-server/config/dictionary.json +1 -0
  242. package/template/game-server/config/log4js.json +150 -0
  243. package/template/game-server/config/master.json +8 -0
  244. package/template/game-server/config/serverProtos.json +1 -0
  245. package/template/game-server/config/servers.json +12 -0
  246. package/template/game-server/copy.js +5 -0
  247. package/template/game-server/package.json +28 -0
  248. package/template/game-server/preload.ts +40 -0
  249. package/template/game-server/tsconfig.json +36 -0
  250. package/template/npm-install.bat +4 -0
  251. package/template/npm-install.sh +5 -0
  252. package/template/readme.md +31 -0
  253. package/template/shared/server.crt +15 -0
  254. package/template/shared/server.key +15 -0
  255. package/template/web-server/app.js +25 -0
  256. package/template/web-server/app.js.https +36 -0
  257. package/template/web-server/bin/component.bat +1 -0
  258. package/template/web-server/bin/component.sh +1 -0
  259. package/template/web-server/package.json +10 -0
  260. package/template/web-server/public/css/base.css +76 -0
  261. package/template/web-server/public/image/logo.png +0 -0
  262. package/template/web-server/public/image/sp.png +0 -0
  263. package/template/web-server/public/index.html +57 -0
  264. package/template/web-server/public/index.html.sio +58 -0
  265. package/template/web-server/public/js/lib/build/build.js +1730 -0
  266. package/template/web-server/public/js/lib/build/build.js.wss +1721 -0
  267. package/template/web-server/public/js/lib/component.json +6 -0
  268. package/template/web-server/public/js/lib/local/boot/component.json +11 -0
  269. package/template/web-server/public/js/lib/local/boot/index.js +11 -0
  270. package/template/web-server/public/js/lib/meloclient.js +456 -0
  271. package/template/web-server/public/js/lib/meloclient.js.wss +456 -0
  272. package/template/web-server/public/js/lib/socket.io.js +3 -0
  273. package/test/application.ts +607 -0
  274. package/test/filters/handler/serial.ts +47 -0
  275. package/test/filters/handler/time.ts +47 -0
  276. package/test/filters/handler/timeout.ts +46 -0
  277. package/test/filters/handler/toobusy.ts +59 -0
  278. package/test/filters/rpc/rpcLog.ts +20 -0
  279. package/test/filters/rpc/toobusy.ts +40 -0
  280. package/test/manager/mockChannelManager.ts +92 -0
  281. package/test/manager/taskManager.ts +78 -0
  282. package/test/mock-base/app/servers/other-file +0 -0
  283. package/test/mock-plugin/components/mockPlugin.ts +8 -0
  284. package/test/mock-plugin/events/mockEvent.ts +12 -0
  285. package/test/modules/console.ts +264 -0
  286. package/test/pomelo.ts +18 -0
  287. package/test/remote/channelRemote.ts +176 -0
  288. package/test/service/channel.ts +161 -0
  289. package/test/service/channelService.ts +243 -0
  290. package/test/service/connectionService.ts +142 -0
  291. package/test/service/filterService.ts +165 -0
  292. package/test/service/handlerService.ts +77 -0
  293. package/test/service/sessionService.ts +464 -0
  294. package/test/util/countDownLatch.ts +81 -0
  295. package/test/util/pathUtil.ts +122 -0
  296. package/test/util/utils.ts +165 -0
@@ -0,0 +1,142 @@
1
+ import { EventEmitter } from 'events';
2
+ import * as util from 'util';
3
+ import { WSProcessor } from './wsprocessor';
4
+ import { TCPProcessor } from './tcpprocessor';
5
+ import { getLogger } from '@bigtyphoon/melo-logger';
6
+ import * as net from 'net';
7
+ import * as tls from 'tls';
8
+ import { TlsOptions } from 'tls';
9
+ import * as WebSocket from 'ws';
10
+ import { TcpSocket } from './tcpsocket';
11
+ import { IHybridSocket } from './IHybridSocket';
12
+ import * as path from 'path';
13
+ let logger = getLogger('melo', path.basename(__filename));
14
+
15
+
16
+ let HTTP_METHODS = [
17
+ 'GET', 'POST', 'DELETE', 'PUT', 'HEAD'
18
+ ];
19
+ // max length of 'DELETE'
20
+ let MAX_HTTP_METHODS_LEN = 6;
21
+
22
+ let ST_STARTED = 1;
23
+ let ST_CLOSED = 2;
24
+
25
+ let DEFAULT_TIMEOUT = 90;
26
+
27
+ export type SslWatcher = (cb: (opts: tls.SecureContextOptions) => void) => void;
28
+ export interface HybridSwitcherOptions {
29
+ closeMethod ?: 'end';
30
+ timeout ?: number;
31
+ setNoDelay ?: boolean;
32
+ ssl ?: TlsOptions;
33
+ sslWatcher?: SslWatcher;
34
+ }
35
+ export interface IHybridSwitcher {
36
+ on(evt: 'connection' , listener: (socket: IHybridSocket) => void): void;
37
+ }
38
+
39
+ /**
40
+ * Switcher for tcp and websocket protocol
41
+ *
42
+ * @param {Object} server tcp server instance from node.js net module
43
+ */
44
+ export class HybridSwitcher extends EventEmitter implements IHybridSwitcher {
45
+ server: net.Server;
46
+ wsprocessor: WSProcessor;
47
+ tcpprocessor: TCPProcessor;
48
+ id: number;
49
+ timeout: number;
50
+ setNoDelay: boolean;
51
+ state: number;
52
+
53
+
54
+ constructor(server: net.Server, opts: HybridSwitcherOptions) {
55
+ super();
56
+ this.server = server;
57
+ this.wsprocessor = new WSProcessor();
58
+ this.tcpprocessor = new TCPProcessor(opts.closeMethod);
59
+ this.id = 1;
60
+ this.timeout = (opts.timeout || DEFAULT_TIMEOUT) * 1000;
61
+ this.setNoDelay = opts.setNoDelay;
62
+
63
+ if (!opts.ssl) {
64
+ this.server.on('connection', this.newSocket.bind(this));
65
+ } else {
66
+ this.server.on('secureConnection', this.newSocket.bind(this));
67
+ this.server.on('clientError', function (e, tlsSo) {
68
+ logger.warn('an ssl error occured before handshake established: ', e);
69
+ tlsSo.destroy();
70
+ });
71
+ }
72
+
73
+ this.wsprocessor.on('connection', this.emit.bind(this, 'connection'));
74
+ this.tcpprocessor.on('connection', this.emit.bind(this, 'connection'));
75
+
76
+ this.state = ST_STARTED;
77
+ }
78
+
79
+ newSocket(socket: net.Socket) {
80
+ if (this.state !== ST_STARTED) {
81
+ return;
82
+ }
83
+
84
+ socket.on('error', (err: Error) => {
85
+ logger.debug('connection error:%s, the remote ip is %s && port is %s', err.message, socket.remoteAddress, socket.remotePort);
86
+ socket.destroy();
87
+ });
88
+
89
+ socket.on('close', () => {
90
+ socket.destroy();
91
+ });
92
+ socket.setTimeout(this.timeout, function () {
93
+ logger.warn('connection is timeout without communication, the remote ip is %s && port is %s',
94
+ socket.remoteAddress, socket.remotePort);
95
+ socket.destroy();
96
+ });
97
+
98
+ let self = this;
99
+
100
+ socket.once('data', (data) => {
101
+ // FIXME: handle incomplete HTTP method
102
+ if (isHttp(data)) {
103
+ this.processHttp(self.wsprocessor, socket, data);
104
+ } else {
105
+ if (!!self.setNoDelay) {
106
+ socket.setNoDelay(true);
107
+ }
108
+ this.processTcp(self.tcpprocessor, socket, data);
109
+ }
110
+ });
111
+ }
112
+
113
+ close() {
114
+ if (this.state !== ST_STARTED) {
115
+ return;
116
+ }
117
+
118
+ this.state = ST_CLOSED;
119
+ this.wsprocessor.close();
120
+ this.tcpprocessor.close();
121
+ }
122
+
123
+ private processHttp(processor: WSProcessor, socket: net.Socket, data: Buffer) {
124
+ processor.add(socket, data);
125
+ }
126
+
127
+ private processTcp(processor: TCPProcessor, socket: net.Socket, data: Buffer) {
128
+ processor.add(socket, data);
129
+ }
130
+
131
+ }
132
+ let isHttp = function (data: Buffer) {
133
+ let head = data.toString('utf8', 0, MAX_HTTP_METHODS_LEN - 1);
134
+
135
+ for (let i = 0, l = HTTP_METHODS.length; i < l; i++) {
136
+ if (head.indexOf(HTTP_METHODS[i]) === 0) {
137
+ return true;
138
+ }
139
+ }
140
+
141
+ return false;
142
+ };
@@ -0,0 +1,43 @@
1
+ import { EventEmitter } from 'events';
2
+ import * as util from 'util';
3
+ import * as net from 'net';
4
+ import * as utils from '../../util/utils';
5
+ import { TcpSocket } from './tcpsocket';
6
+
7
+ let ST_STARTED = 1;
8
+ let ST_CLOSED = 2;
9
+
10
+ // private protocol, no need exports
11
+ let HEAD_SIZE = 4;
12
+
13
+ /**
14
+ * websocket protocol processor
15
+ */
16
+ export class TCPProcessor extends EventEmitter {
17
+ closeMethod: 'end';
18
+ state: number;
19
+ constructor(closeMethod?: 'end') {
20
+ super();
21
+ this.closeMethod = closeMethod;
22
+ this.state = ST_STARTED;
23
+ }
24
+ add(socket: net.Socket, data: Buffer) {
25
+ if (this.state !== ST_STARTED) {
26
+ return;
27
+ }
28
+ let tcpsocket = new TcpSocket(socket, {
29
+ headSize: HEAD_SIZE,
30
+ headHandler: utils.headHandler,
31
+ closeMethod: this.closeMethod
32
+ });
33
+ this.emit('connection', tcpsocket);
34
+ socket.emit('data', data);
35
+ }
36
+
37
+ close() {
38
+ if (this.state !== ST_STARTED) {
39
+ return;
40
+ }
41
+ this.state = ST_CLOSED;
42
+ }
43
+ }
@@ -0,0 +1,223 @@
1
+ import {Stream} from 'stream';
2
+ import * as util from 'util';
3
+ import * as net from 'net';
4
+ import {Package} from '@bigtyphoon/melo-protocol';
5
+ import {getLogger} from '@bigtyphoon/melo-logger';
6
+ import {ISocket} from '../../interfaces/ISocket';
7
+ import {IHybridSocket} from './IHybridSocket';
8
+ import * as path from 'path';
9
+
10
+ let logger = getLogger('melo', path.basename(__filename));
11
+
12
+
13
+ export interface TcpSocketOptions {
14
+ headSize: number;
15
+ headHandler: (data: Buffer) => number;
16
+ closeMethod?: 'end';
17
+ }
18
+
19
+ /**
20
+ * Work states
21
+ */
22
+ let ST_HEAD = 1; // wait for head
23
+ let ST_BODY = 2; // wait for body
24
+ let ST_CLOSED = 3; // closed
25
+
26
+ /**
27
+ * Tcp socket wrapper with package compositing.
28
+ * Collect the package from socket and emit a completed package with 'data' event.
29
+ * Uniform with ws.WebSocket interfaces.
30
+ *
31
+ * @param {Object} socket origin socket from node.js net module
32
+ * @param {Object} opts options parameter.
33
+ * opts.headSize size of package head
34
+ * opts.headHandler(headBuffer) handler for package head. caculate and return body size from head data.
35
+ */
36
+ export class TcpSocket extends Stream implements IHybridSocket {
37
+ readable: boolean;
38
+ writeable: boolean;
39
+
40
+ _socket: net.Socket;
41
+ headSize: number;
42
+ closeMethod: string;
43
+ headBuffer: Buffer;
44
+ headHandler: Function;
45
+
46
+ headOffset: number;
47
+ packageOffset: number;
48
+ packageSize: number;
49
+ packageBuffer: Buffer;
50
+ state: number;
51
+
52
+ constructor(socket: net.Socket, opts?: TcpSocketOptions) {
53
+ // stream style interfaces.
54
+ // TODO: need to port to stream2 after node 0.9
55
+ super();
56
+ if (!socket || !opts) {
57
+ throw new Error('invalid socket or opts');
58
+ }
59
+
60
+ if (!opts.headSize || typeof opts.headHandler !== 'function') {
61
+ throw new Error('invalid opts.headSize or opts.headHandler');
62
+ }
63
+
64
+ this.readable = true;
65
+ this.writeable = true;
66
+
67
+ this._socket = socket;
68
+ this.headSize = opts.headSize;
69
+ this.closeMethod = opts.closeMethod;
70
+ this.headBuffer = Buffer.alloc(opts.headSize);
71
+ this.headHandler = opts.headHandler;
72
+
73
+ this.headOffset = 0;
74
+ this.packageOffset = 0;
75
+ this.packageSize = 0;
76
+ this.packageBuffer = null;
77
+
78
+ // bind event form the origin socket
79
+ this._socket.on('data', this.ondata.bind(this));
80
+ this._socket.on('end', this.onend.bind(this));
81
+ this._socket.on('error', this.emit.bind(this, 'error'));
82
+ this._socket.on('close', this.emit.bind(this, 'close'));
83
+
84
+ this.state = ST_HEAD;
85
+ }
86
+
87
+
88
+ send(msg: any, options: { binary?: boolean }, cb?: (err ?: Error) => void) {
89
+ this._socket.write(msg, options.binary ? 'binary' : 'utf8', cb);
90
+ }
91
+
92
+ close() {
93
+ if (!!this.closeMethod && this.closeMethod === 'end') {
94
+ this._socket.end();
95
+ } else {
96
+ try {
97
+ this._socket.destroy();
98
+ } catch (e) {
99
+ logger.error('socket close with destroy error: %j', e.stack);
100
+ }
101
+ }
102
+ }
103
+
104
+ ondata(chunk: Buffer) {
105
+ if (this.state === ST_CLOSED) {
106
+ throw new Error('socket has closed');
107
+ }
108
+
109
+ if (typeof chunk !== 'string' && !Buffer.isBuffer(chunk)) {
110
+ throw new Error('invalid data');
111
+ }
112
+
113
+ if (typeof chunk === 'string') {
114
+ chunk = Buffer.from(chunk, 'utf8');
115
+ }
116
+
117
+ let offset = 0, end = chunk.length;
118
+
119
+ while (offset < end && this.state !== ST_CLOSED) {
120
+ if (this.state === ST_HEAD) {
121
+ offset = this.readHead(chunk, offset);
122
+ }
123
+
124
+ if (this.state === ST_BODY) {
125
+ offset = this.readBody(chunk, offset);
126
+ }
127
+ }
128
+
129
+ return true;
130
+ }
131
+
132
+ onend(chunk: Buffer) {
133
+ if (chunk) {
134
+ this._socket.write(chunk);
135
+ }
136
+
137
+ this.state = ST_CLOSED;
138
+ this.reset();
139
+ this.emit('end');
140
+ }
141
+
142
+ /**
143
+ * Read head segment from data to socket.headBuffer.
144
+ *
145
+ * @param {Object} socket Socket instance
146
+ * @param {Object} data Buffer instance
147
+ * @param {Number} offset offset read star from data
148
+ * @return {Number} new offset of data after read
149
+ */
150
+ readHead(data: Buffer, offset: number) {
151
+ let hlen = this.headSize - this.headOffset;
152
+ let dlen = data.length - offset;
153
+ let len = Math.min(hlen, dlen);
154
+ let dend = offset + len;
155
+
156
+ data.copy(this.headBuffer, this.headOffset, offset, dend);
157
+ this.headOffset += len;
158
+
159
+ if (this.headOffset === this.headSize) {
160
+ // if head segment finished
161
+ let size = this.headHandler(this.headBuffer);
162
+ if (size < 0) {
163
+ throw new Error('invalid body size: ' + size);
164
+ }
165
+ // check if header contains a valid type
166
+ if (checkTypeData(this.headBuffer[0])) {
167
+ this.packageSize = size + this.headSize;
168
+ this.packageBuffer = Buffer.alloc(this.packageSize);
169
+ this.headBuffer.copy(this.packageBuffer, 0, 0, this.headSize);
170
+ this.packageOffset = this.headSize;
171
+ this.state = ST_BODY;
172
+ } else {
173
+ dend = data.length;
174
+ logger.error('close the connection with invalid head message, the remote ip is %s && port is %s && message is %j', this._socket.remoteAddress, this._socket.remotePort, data);
175
+ this.close();
176
+ }
177
+
178
+ }
179
+
180
+ return dend;
181
+ }
182
+
183
+ /**
184
+ * Read body segment from data buffer to socket.packageBuffer;
185
+ *
186
+ * @param {Object} socket Socket instance
187
+ * @param {Object} data Buffer instance
188
+ * @param {Number} offset offset read star from data
189
+ * @return {Number} new offset of data after read
190
+ */
191
+ readBody(data: Buffer, offset: number) {
192
+ let blen = this.packageSize - this.packageOffset;
193
+ let dlen = data.length - offset;
194
+ let len = Math.min(blen, dlen);
195
+ let dend = offset + len;
196
+
197
+ data.copy(this.packageBuffer, this.packageOffset, offset, dend);
198
+
199
+ this.packageOffset += len;
200
+
201
+ if (this.packageOffset === this.packageSize) {
202
+ // if all the package finished
203
+ let buffer = this.packageBuffer;
204
+ this.emit('message', buffer);
205
+ this.reset();
206
+ }
207
+
208
+ return dend;
209
+ }
210
+
211
+ reset() {
212
+ this.headOffset = 0;
213
+ this.packageOffset = 0;
214
+ this.packageSize = 0;
215
+ this.packageBuffer = null;
216
+ this.state = ST_HEAD;
217
+ }
218
+
219
+ }
220
+
221
+ let checkTypeData = function (data: number) {
222
+ return data === Package.TYPE_HANDSHAKE || data === Package.TYPE_HANDSHAKE_ACK || data === Package.TYPE_HEARTBEAT || data === Package.TYPE_DATA || data === Package.TYPE_KICK;
223
+ };
@@ -0,0 +1,57 @@
1
+ import { Server as HttpServer } from 'http';
2
+ import { EventEmitter } from 'events';
3
+ import * as util from 'util';
4
+ import * as net from 'net';
5
+ import * as WebSocket from 'ws';
6
+
7
+ let ST_STARTED = 1;
8
+ let ST_CLOSED = 2;
9
+
10
+ /**
11
+ * websocket protocol processor
12
+ */
13
+ export class WSProcessor extends EventEmitter {
14
+ httpServer: HttpServer;
15
+ wsServer: WebSocket.Server;
16
+ state: number;
17
+
18
+ constructor() {
19
+ super();
20
+ this.httpServer = new HttpServer();
21
+
22
+ let self = this;
23
+ this.wsServer = new WebSocket.Server({ server: this.httpServer });
24
+
25
+ this.wsServer.on('connection', function (socket, request) {
26
+ // emit socket to outside
27
+ self.emit('connection', socket, request);
28
+ });
29
+
30
+ this.state = ST_STARTED;
31
+ }
32
+
33
+
34
+ add(socket: net.Socket, data: Buffer) {
35
+ if (this.state !== ST_STARTED) {
36
+ return;
37
+ }
38
+ this.httpServer.emit('connection', socket);
39
+ if (typeof (socket as any).ondata === 'function') {
40
+ // compatible with stream2
41
+ (socket as any).ondata(data, 0, data.length);
42
+ } else {
43
+ // compatible with old stream
44
+ socket.emit('data', data);
45
+ }
46
+ }
47
+
48
+ close() {
49
+ if (this.state !== ST_STARTED) {
50
+ return;
51
+ }
52
+ this.state = ST_CLOSED;
53
+ this.wsServer.close();
54
+ this.wsServer = null;
55
+ this.httpServer = null;
56
+ }
57
+ }
@@ -0,0 +1,134 @@
1
+ import * as net from 'net';
2
+ import * as tls from 'tls';
3
+ import * as util from 'util';
4
+ import { EventEmitter } from 'events';
5
+
6
+ import { HybridSocket } from './hybridsocket';
7
+ import { HybridSwitcher as Switcher, HybridSwitcherOptions } from './hybrid/switcher';
8
+ import { HandshakeCommand } from './commands/handshake';
9
+ import { HeartbeatCommand } from './commands/heartbeat';
10
+ import * as Kick from './commands/kick';
11
+ import * as coder from './common/coder';
12
+ import { ConnectorComponent } from '../components/connector';
13
+ import { DictionaryComponent } from '../components/dictionary';
14
+ import { ProtobufComponent } from '../components/protobuf';
15
+ import { IComponent } from '../interfaces/IComponent';
16
+ import { melo } from '../melo';
17
+ import { IConnector } from '../interfaces/IConnector';
18
+ import { TlsOptions } from 'tls';
19
+ import * as WebSocket from 'ws';
20
+ import { TcpSocket } from './hybrid/tcpsocket';
21
+ import { IHybridSocket } from './hybrid/IHybridSocket';
22
+
23
+ let curId = 1;
24
+
25
+ export interface HybridConnectorOptions extends HybridSwitcherOptions {
26
+ useDict?: boolean;
27
+ useProtobuf?: boolean;
28
+ distinctHost?: boolean;
29
+ realIPKey?: string; // 代理过后真实客户端ip获取字段
30
+ realPortKey?: string; // 代理过后真实客户端port获取字段
31
+ }
32
+
33
+ /**
34
+ * Connector that manager low level connection and protocol bewteen server and client.
35
+ * Develper can provide their own connector to switch the low level prototol, such as tcp or probuf.
36
+ */
37
+ export class HybridConnector extends EventEmitter implements IConnector {
38
+ opts: HybridConnectorOptions;
39
+ port: number;
40
+ host: string;
41
+ useDict: boolean;
42
+ useProtobuf: boolean;
43
+ handshake: HandshakeCommand;
44
+ heartbeat: HeartbeatCommand;
45
+ distinctHost: boolean;
46
+ ssl: tls.TlsOptions;
47
+ switcher: Switcher;
48
+
49
+ connector: IConnector;
50
+ dictionary: DictionaryComponent;
51
+ protobuf: ProtobufComponent;
52
+ decodeIO_protobuf: IComponent;
53
+
54
+ listeningServer: net.Server | tls.Server;
55
+
56
+ constructor(port: number, host: string, opts?: HybridConnectorOptions) {
57
+ super();
58
+
59
+ this.opts = opts || {};
60
+ if (this.opts.realPortKey) {
61
+ this.opts.realPortKey = opts.realPortKey.toLowerCase();
62
+ }
63
+ if (this.opts.realIPKey) {
64
+ this.opts.realIPKey = opts.realIPKey.toLowerCase();
65
+ }
66
+ this.port = port;
67
+ this.host = host;
68
+ this.useDict = opts.useDict;
69
+ this.useProtobuf = opts.useProtobuf;
70
+ this.handshake = new HandshakeCommand(opts);
71
+ this.heartbeat = new HeartbeatCommand(opts);
72
+ this.distinctHost = opts.distinctHost;
73
+ this.ssl = opts.ssl;
74
+
75
+ this.switcher = null;
76
+ }
77
+
78
+ /**
79
+ * Start connector to listen the specified port
80
+ */
81
+ start(cb: () => void) {
82
+ let app = melo.app;
83
+ let self = this;
84
+
85
+ let gensocket = function (socket: IHybridSocket, request: any) {
86
+ let hybridsocket = new HybridSocket(curId++, socket, request, self.opts);
87
+ hybridsocket.on('handshake', self.handshake.handle.bind(self.handshake, hybridsocket));
88
+ hybridsocket.on('heartbeat', self.heartbeat.handle.bind(self.heartbeat, hybridsocket));
89
+ hybridsocket.on('disconnect', self.heartbeat.clear.bind(self.heartbeat, hybridsocket.id));
90
+ hybridsocket.on('closing', Kick.handle.bind(null, hybridsocket));
91
+ self.emit('connection', hybridsocket);
92
+ };
93
+
94
+ this.connector = app.components.__connector__.connector;
95
+ this.dictionary = app.components.__dictionary__;
96
+ this.protobuf = app.components.__protobuf__;
97
+ this.decodeIO_protobuf = app.components.__decodeIO__protobuf__;
98
+
99
+ if (!this.ssl) {
100
+ this.listeningServer = net.createServer();
101
+ } else {
102
+ this.listeningServer = tls.createServer(this.ssl);
103
+ if (this.opts.sslWatcher) {
104
+ this.opts.sslWatcher((opts) => {
105
+ (this.listeningServer as tls.Server).setSecureContext(opts);
106
+ });
107
+ }
108
+ }
109
+ this.switcher = new Switcher(this.listeningServer, self.opts);
110
+
111
+ this.switcher.on('connection', function (socket, request) {
112
+ gensocket(socket, request);
113
+ });
114
+
115
+ if (!!this.distinctHost) {
116
+ this.listeningServer.listen(this.port, this.host);
117
+ } else {
118
+ this.listeningServer.listen(this.port);
119
+ }
120
+
121
+ process.nextTick(cb);
122
+ }
123
+
124
+ stop(force: boolean, cb: () => void) {
125
+ this.switcher.close();
126
+ this.listeningServer.close();
127
+
128
+ process.nextTick(cb);
129
+ }
130
+ decode = coder.decode;
131
+
132
+ encode = coder.encode;
133
+
134
+ }