@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,731 @@
1
+ import {EventEmitter} from 'events';
2
+ import * as util from 'util';
3
+ import {getLogger} from '@bigtyphoon/melo-logger';
4
+ import * as utils from '../../util/utils';
5
+ import {SID, FRONTENDID, UID} from '../../util/constants';
6
+ import {ISocket} from '../../interfaces/ISocket';
7
+ import * as path from 'path';
8
+
9
+ let logger = getLogger('melo', path.basename(__filename));
10
+
11
+ let FRONTEND_SESSION_FIELDS = ['id', 'frontendId', 'uid', '__sessionService__'];
12
+ let EXPORTED_SESSION_FIELDS = ['id', 'frontendId', 'uid', 'settings'];
13
+
14
+ let ST_INITED = 0;
15
+ let ST_CLOSED = 1;
16
+
17
+ export interface SessionServiceOptions {
18
+ singleSession?: boolean;
19
+ }
20
+
21
+ /**
22
+ * Session service maintains the internal session for each client connection.
23
+ *
24
+ * Session service is created by session component and is only
25
+ * <b>available</b> in frontend servers. You can access the service by
26
+ * `app.get('sessionService')` or `app.sessionService` in frontend servers.
27
+ *
28
+ * @param {Object} opts constructor parameters
29
+ * @class
30
+ * @constructor
31
+ */
32
+ export class SessionService {
33
+ singleSession: boolean;
34
+ sessions: { [sid: number]: Session };
35
+ uidMap: { [uid: string]: Session[] };
36
+
37
+ constructor(opts ?: SessionServiceOptions) {
38
+ opts = opts || {};
39
+ this.singleSession = opts.singleSession;
40
+ this.sessions = {}; // sid -> session
41
+ this.uidMap = {}; // uid -> sessions
42
+ }
43
+
44
+ /**
45
+ * Create and return internal session.
46
+ *
47
+ * @param {Integer} sid uniqe id for the internal session
48
+ * @param {String} frontendId frontend server in which the internal session is created
49
+ * @param {Object} socket the underlying socket would be held by the internal session
50
+ *
51
+ * @return {Session}
52
+ *
53
+ * @memberOf SessionService
54
+ * @api private
55
+ */
56
+ create(sid: SID, frontendId: FRONTENDID, socket: ISocket) {
57
+ let session = new Session(sid, frontendId, socket, this);
58
+ this.sessions[session.id] = session;
59
+
60
+ return session;
61
+ }
62
+
63
+ /**
64
+ * Bind the session with a user id.
65
+ *
66
+ * @memberOf SessionService
67
+ * @api private
68
+ */
69
+ bind(sid: SID, uid: UID, cb: (err: Error | null, result ?: void) => void) {
70
+ let session = this.sessions[sid];
71
+
72
+ if (!session) {
73
+ process.nextTick(function () {
74
+ cb(new Error('session does not exist, sid: ' + sid));
75
+ });
76
+ return;
77
+ }
78
+
79
+ if (session.uid) {
80
+ if (session.uid === uid) {
81
+ // already bound with the same uid
82
+ cb(null);
83
+ return;
84
+ }
85
+
86
+ // already bound with other uid
87
+ process.nextTick(function () {
88
+ cb(new Error('session has already bound with ' + session.uid));
89
+ });
90
+ return;
91
+ }
92
+
93
+ let sessions = this.uidMap[uid];
94
+
95
+ if (!!this.singleSession && !!sessions) {
96
+ process.nextTick(function () {
97
+ cb(new Error('singleSession is enabled, and session has already bound with uid: ' + uid));
98
+ });
99
+ return;
100
+ }
101
+
102
+ if (!sessions) {
103
+ sessions = this.uidMap[uid] = [];
104
+ }
105
+
106
+ for (let i = 0, l = sessions.length; i < l; i++) {
107
+ // session has binded with the uid
108
+ if (sessions[i].id === session.id) {
109
+ process.nextTick(cb);
110
+ return;
111
+ }
112
+ }
113
+ sessions.push(session);
114
+
115
+ session.bind(uid);
116
+
117
+ if (cb) {
118
+ process.nextTick(cb);
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Unbind a session with the user id.
124
+ *
125
+ * @memberOf SessionService
126
+ * @api private
127
+ */
128
+ unbind(sid: SID, uid: UID, cb: (err ?: Error, result ?: void) => void) {
129
+ let session = this.sessions[sid];
130
+
131
+ if (!session) {
132
+ process.nextTick(function () {
133
+ cb(new Error('session does not exist, sid: ' + sid));
134
+ });
135
+ return;
136
+ }
137
+
138
+ if (!session.uid || session.uid !== uid) {
139
+ process.nextTick(function () {
140
+ cb(new Error('session has not bind with ' + session.uid));
141
+ });
142
+ return;
143
+ }
144
+
145
+ let sessions = this.uidMap[uid], sess;
146
+ if (sessions) {
147
+ for (let i = 0, l = sessions.length; i < l; i++) {
148
+ sess = sessions[i];
149
+ if (sess.id === sid) {
150
+ sessions.splice(i, 1);
151
+ break;
152
+ }
153
+ }
154
+
155
+ if (sessions.length === 0) {
156
+ delete this.uidMap[uid];
157
+ }
158
+ }
159
+ session.unbind(uid);
160
+
161
+ if (cb) {
162
+ process.nextTick(cb);
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Get session by id.
168
+ *
169
+ * @param {Number} id The session id
170
+ * @return {Session}
171
+ *
172
+ * @memberOf SessionService
173
+ * @api private
174
+ */
175
+ get(sid: SID) {
176
+ return this.sessions[sid];
177
+ }
178
+
179
+ /**
180
+ * Get sessions by userId.
181
+ *
182
+ * @param {Number} uid User id associated with the session
183
+ * @return {Array} list of session binded with the uid
184
+ *
185
+ * @memberOf SessionService
186
+ * @api private
187
+ */
188
+ getByUid(uid: UID) {
189
+ return this.uidMap[uid];
190
+ }
191
+
192
+ /**
193
+ * Remove session by key.
194
+ *
195
+ * @param {Number} sid The session id
196
+ *
197
+ * @memberOf SessionService
198
+ * @api private
199
+ */
200
+ remove(sid: SID) {
201
+ let session = this.sessions[sid];
202
+ if (session) {
203
+ let uid = session.uid;
204
+ delete this.sessions[session.id];
205
+
206
+ let sessions = this.uidMap[uid];
207
+ if (!sessions) {
208
+ return;
209
+ }
210
+
211
+ for (let i = 0, l = sessions.length; i < l; i++) {
212
+ if (sessions[i].id === sid) {
213
+ sessions.splice(i, 1);
214
+ if (sessions.length === 0) {
215
+ delete this.uidMap[uid];
216
+ }
217
+ break;
218
+ }
219
+ }
220
+ }
221
+ }
222
+
223
+ /**
224
+ * Import the key/value into session.
225
+ *
226
+ * @api private
227
+ */
228
+ import(sid: SID, key: string, value: string, cb: (err ?: Error, result ?: void) => void) {
229
+ let session = this.sessions[sid];
230
+ if (!session) {
231
+ utils.invokeCallback(cb, new Error('session does not exist, sid: ' + sid));
232
+ return;
233
+ }
234
+ session.set(key, value);
235
+ utils.invokeCallback(cb);
236
+ }
237
+
238
+ /**
239
+ * Import new value for the existed session.
240
+ *
241
+ * @memberOf SessionService
242
+ * @api private
243
+ */
244
+ importAll(sid: SID, settings: { [key: string]: any }, cb: (err ?: Error, result ?: void) => void) {
245
+ let session = this.sessions[sid];
246
+ if (!session) {
247
+ utils.invokeCallback(cb, new Error('session does not exist, sid: ' + sid));
248
+ return;
249
+ }
250
+
251
+ for (let f in settings) {
252
+ session.set(f, settings[f]);
253
+ }
254
+ utils.invokeCallback(cb);
255
+ }
256
+
257
+ /**
258
+ * Kick all the session offline under the user id.
259
+ *
260
+ * @param {Number} uid user id asscociated with the session
261
+ * @param {Function} cb callback function
262
+ *
263
+ * @memberOf SessionService
264
+ */
265
+ kick(uid: UID, reason ?: string, cb ?: (err ?: Error, result ?: void) => void) {
266
+ // compatible for old kick(uid, cb);
267
+ if (typeof reason === 'function') {
268
+ cb = reason;
269
+ reason = 'kick';
270
+ }
271
+ let sessions = this.getByUid(uid);
272
+
273
+ if (sessions) {
274
+ // notify client
275
+ let sids: SID[] = [];
276
+ let self = this;
277
+ sessions.forEach(function (session) {
278
+ sids.push(session.id);
279
+ });
280
+
281
+ sids.forEach(function (sid) {
282
+ self.sessions[sid].closed(reason);
283
+ });
284
+
285
+ process.nextTick(function () {
286
+ utils.invokeCallback(cb);
287
+ });
288
+ } else {
289
+ process.nextTick(function () {
290
+ utils.invokeCallback(cb);
291
+ });
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Kick a user offline by session id.
297
+ *
298
+ * @param {Number} sid session id
299
+ * @param {Function} cb callback function
300
+ *
301
+ * @memberOf SessionService
302
+ */
303
+ kickBySessionId(sid: SID, reason ?: string, cb ?: (err ?: Error, result ?: void) => void) {
304
+ if (typeof reason === 'function') {
305
+ cb = reason;
306
+ reason = 'kick';
307
+ }
308
+
309
+ let session = this.get(sid);
310
+
311
+ if (session) {
312
+ // notify client
313
+ session.closed(reason);
314
+ process.nextTick(function () {
315
+ utils.invokeCallback(cb);
316
+ });
317
+ } else {
318
+ process.nextTick(function () {
319
+ utils.invokeCallback(cb);
320
+ });
321
+ }
322
+ }
323
+
324
+ /**
325
+ * Get client remote address by session id.
326
+ *
327
+ * @param {Number} sid session id
328
+ * @return {Object} remote address of client
329
+ *
330
+ * @memberOf SessionService
331
+ */
332
+ getClientAddressBySessionId(sid: SID) {
333
+ let session = this.get(sid);
334
+ if (session) {
335
+ let socket = session.__socket__;
336
+ return socket.remoteAddress;
337
+ } else {
338
+ return null;
339
+ }
340
+ }
341
+
342
+ /**
343
+ * Send message to the client by session id.
344
+ *
345
+ * @param {String} sid session id
346
+ * @param {Object} msg message to send
347
+ *
348
+ * @memberOf SessionService
349
+ * @api private
350
+ */
351
+ sendMessage(sid: SID, msg: any) {
352
+ let session = this.sessions[sid];
353
+
354
+ if (!session) {
355
+ logger.debug('Fail to send message for non-existing session, sid: ' + sid + ' msg: ' + msg);
356
+ return false;
357
+ }
358
+
359
+ return send(this, session, msg);
360
+ }
361
+
362
+ /**
363
+ * Send message to the client by user id.
364
+ *
365
+ * @param {String} uid userId
366
+ * @param {Object} msg message to send
367
+ *
368
+ * @memberOf SessionService
369
+ * @api private
370
+ */
371
+ sendMessageByUid(uid: UID, msg: any) {
372
+ let sessions = this.uidMap[uid];
373
+
374
+ if (!sessions) {
375
+ logger.debug('fail to send message by uid for non-existing session. uid: %j',
376
+ uid);
377
+ return false;
378
+ }
379
+
380
+ for (let i = 0, l = sessions.length; i < l; i++) {
381
+ send(this, sessions[i], msg);
382
+ }
383
+ }
384
+
385
+ /**
386
+ * Iterate all the session in the session service.
387
+ *
388
+ * @param {Function} cb callback function to fetch session
389
+ * @api private
390
+ */
391
+ forEachSession(cb: (session: Session) => void) {
392
+ for (let sid in this.sessions) {
393
+ cb(this.sessions[sid]);
394
+ }
395
+ }
396
+
397
+ /**
398
+ * Iterate all the binded session in the session service.
399
+ *
400
+ * @param {Function} cb callback function to fetch session
401
+ * @api private
402
+ */
403
+ forEachBindedSession(cb: (session: Session) => void) {
404
+ let i, l, sessions;
405
+ for (let uid in this.uidMap) {
406
+ sessions = this.uidMap[uid];
407
+ for (i = 0, l = sessions.length; i < l; i++) {
408
+ cb(sessions[i]);
409
+ }
410
+ }
411
+ }
412
+
413
+ /**
414
+ * Get sessions' quantity in specified server.
415
+ *
416
+ */
417
+ getSessionsCount() {
418
+ return Object.keys(this.sessions).length;
419
+ }
420
+
421
+
422
+ akick: (uid: UID, reason ?: string) => Promise<void> = utils.promisify(this.kick.bind(this));
423
+ akickBySessionId: (sid: SID, reason ?: string) => Promise<void> = utils.promisify(this.kickBySessionId.bind(this));
424
+ abind: (sid: SID, uid: UID) => Promise<void> = utils.promisify(this.bind.bind(this));
425
+ aunbind: (sid: SID, uid: UID) => Promise<void> = utils.promisify(this.unbind.bind(this));
426
+ aimport: (sid: SID, key: string, value: any) => Promise<void> = utils.promisify(this.import.bind(this));
427
+ aimportAll: (sid: SID, settings: any) => Promise<void> = utils.promisify(this.importAll.bind(this));
428
+ }
429
+
430
+ /**
431
+ * Send message to the client that associated with the session.
432
+ *
433
+ * @api private
434
+ */
435
+ let send = function (service: SessionService, session: Session, msg: any) {
436
+ session.send(msg);
437
+
438
+ return true;
439
+ };
440
+
441
+ export interface ISession {
442
+ id: number;
443
+ uid: string;
444
+ frontendId: string;
445
+ settings: { [key: string]: any };
446
+ }
447
+
448
+ /**
449
+ * Session maintains the relationship between client connection and user information.
450
+ * There is a session associated with each client connection. And it should bind to a
451
+ * user id after the client passes the identification.
452
+ *
453
+ * Session is created in frontend server and should not be accessed in handler.
454
+ * There is a proxy class called BackendSession in backend servers and FrontendSession
455
+ * in frontend servers.
456
+ */
457
+ export class Session extends EventEmitter implements ISession {
458
+ id: SID;
459
+ frontendId: FRONTENDID;
460
+ uid: UID;
461
+ settings: { [key: string]: any };
462
+
463
+ __socket__: ISocket;
464
+ private __sessionService__: SessionService;
465
+ private __state__: number;
466
+
467
+
468
+ constructor(sid: SID, frontendId: FRONTENDID, socket: ISocket, service: SessionService) {
469
+
470
+ super();
471
+ this.id = sid; // r
472
+ this.frontendId = frontendId; // r
473
+ this.uid = null; // r
474
+ this.settings = {};
475
+
476
+ // private
477
+ this.__socket__ = socket;
478
+ this.__sessionService__ = service;
479
+ this.__state__ = ST_INITED;
480
+ }
481
+
482
+ /*
483
+ * Export current session as frontend session.
484
+ */
485
+ toFrontendSession() {
486
+ return new FrontendSession(this);
487
+ }
488
+
489
+ /**
490
+ * Bind the session with the the uid.
491
+ *
492
+ * @param {Number} uid User id
493
+ * @api public
494
+ */
495
+ bind(uid: UID) {
496
+ this.uid = uid;
497
+ this.emit('bind', uid);
498
+ }
499
+
500
+ /**
501
+ * Unbind the session with the the uid.
502
+ *
503
+ * @param {Number} uid User id
504
+ * @api private
505
+ */
506
+ unbind(uid: UID) {
507
+ this.uid = null;
508
+ this.emit('unbind', uid);
509
+ }
510
+
511
+ /**
512
+ * Set values (one or many) for the session.
513
+ *
514
+ * @param {String|Object} key session key
515
+ * @param {Object} value session value
516
+ * @api public
517
+ */
518
+ set(values: { [key: string]: any }): void;
519
+ set(key: string, value: any): void;
520
+ set(keyOrValues: string | { [key: string]: any }, value ?: any) {
521
+ if (utils.isObject(keyOrValues)) {
522
+ let values = keyOrValues as { [key: string]: any };
523
+ for (let i in values) {
524
+ this.settings[i] = values[i];
525
+ }
526
+ } else {
527
+ this.settings[keyOrValues as string] = value;
528
+ }
529
+ }
530
+
531
+ /**
532
+ * Remove value from the session.
533
+ *
534
+ * @param {String} key session key
535
+ * @api public
536
+ */
537
+ remove(key: string) {
538
+ delete this.settings[key];
539
+ }
540
+
541
+ /**
542
+ * Get value from the session.
543
+ *
544
+ * @param {String} key session key
545
+ * @return {Object} value associated with session key
546
+ * @api public
547
+ */
548
+ get(key: string) {
549
+ return this.settings[key];
550
+ }
551
+
552
+ /**
553
+ * Send message to the session.
554
+ *
555
+ * @param {Object} msg final message sent to client
556
+ */
557
+ send(msg: any) {
558
+ this.__socket__.send(msg);
559
+ }
560
+
561
+ /**
562
+ * Send message to the session in batch.
563
+ *
564
+ * @param {Array} msgs list of message
565
+ */
566
+ sendBatch(msgs: any[]) {
567
+ this.__socket__.sendBatch(msgs);
568
+ }
569
+
570
+ /**
571
+ * Closed callback for the session which would disconnect client in next tick.
572
+ *
573
+ * @api public
574
+ */
575
+ closed(reason: string) {
576
+ if (this.__state__ === ST_CLOSED) {
577
+ return;
578
+ }
579
+ logger.debug('session on [%s] is closed with session id: %s,uid:%s,reason:%j', this.frontendId, this.id, this.uid, reason);
580
+ this.__state__ = ST_CLOSED;
581
+ this.__sessionService__.remove(this.id);
582
+ this.emit('closed', this.toFrontendSession(), reason);
583
+ this.__socket__.emit('closing', reason);
584
+
585
+ let self = this;
586
+ // give a chance to send disconnect message to client
587
+
588
+ process.nextTick(function () {
589
+ self.__socket__.disconnect();
590
+ });
591
+ }
592
+
593
+ /**
594
+ * 是否在线
595
+ */
596
+ get isOnline(): boolean {
597
+ return this.__state__ !== ST_CLOSED;
598
+ }
599
+
600
+ /**
601
+ * 获取客户端的地址
602
+ */
603
+ get remoteAddress() {
604
+ return this.__socket__.remoteAddress;
605
+ }
606
+ }
607
+
608
+ /**
609
+ * Frontend session for frontend server.
610
+ */
611
+ export class FrontendSession extends EventEmitter implements ISession {
612
+ id: number;
613
+ uid: string;
614
+ frontendId: string;
615
+ settings: { [key: string]: any; };
616
+ private __session__: Session;
617
+ private __sessionService__: SessionService;
618
+
619
+ constructor(session: Session) {
620
+ super();
621
+ clone(session, this, FRONTEND_SESSION_FIELDS);
622
+ // deep copy for settings
623
+ this.settings = dclone(session.settings);
624
+ this.__session__ = session;
625
+ }
626
+
627
+
628
+ bind(uid: UID, cb: (err ?: Error, result ?: void) => void) {
629
+ let self = this;
630
+ this.__sessionService__.bind(this.id, uid, function (err) {
631
+ if (!err) {
632
+ self.uid = uid;
633
+ }
634
+ utils.invokeCallback(cb, err);
635
+ });
636
+ }
637
+
638
+ unbind(uid: UID, cb: (err ?: Error, result ?: void) => void) {
639
+ let self = this;
640
+ this.__sessionService__.unbind(this.id, uid, function (err) {
641
+ if (!err) {
642
+ self.uid = null;
643
+ }
644
+ utils.invokeCallback(cb, err);
645
+ });
646
+ }
647
+
648
+ set(key: string, value: any) {
649
+ this.settings[key] = value;
650
+ }
651
+
652
+ get(key: string) {
653
+ return this.settings[key];
654
+ }
655
+
656
+ push(key: string, cb: (err ?: Error, result ?: void) => void) {
657
+ this.__sessionService__.import(this.id, key, this.get(key), cb);
658
+ }
659
+
660
+ pushAll(cb: (err ?: Error, result ?: void) => void) {
661
+ this.__sessionService__.importAll(this.id, this.settings, cb);
662
+ }
663
+
664
+ on(event: string | symbol, listener: (...args: any[]) => void): this {
665
+ this.__session__.on(event, listener);
666
+ return super.on(event, listener);
667
+ }
668
+
669
+ abind(uid: string, ) {
670
+ return new Promise((resolve, reject) => this.bind(uid, (err, ret) => err ? reject(err) : resolve(ret as any)));
671
+ }
672
+
673
+ aunbind(uid: string, ) {
674
+ return new Promise((resolve, reject) => this.unbind(uid, (err, ret) => err ? reject(err) : resolve(ret as any)));
675
+ }
676
+
677
+ apush(key: string) {
678
+ return new Promise((resolve, reject) => this.push(key, (err, ret) => err ? reject(err) : resolve(ret as any)));
679
+ }
680
+
681
+ apushAll() {
682
+ return new Promise((resolve, reject) => this.pushAll((err, ret) => err ? reject(err) : resolve(ret as any)));
683
+ }
684
+
685
+
686
+ // abind = utils.promisify(this.bind.bind(this));
687
+ // aunbind = utils.promisify(this.unbind.bind(this));
688
+ // apush = utils.promisify(this.push.bind(this));
689
+ // apushAll = utils.promisify(this.pushAll.bind(this));
690
+
691
+ /**
692
+ * Export the key/values for serialization.
693
+ *
694
+ * @api private
695
+ */
696
+ export() {
697
+ let res = {};
698
+ clone(this, res, EXPORTED_SESSION_FIELDS);
699
+ return res;
700
+ }
701
+
702
+ /**
703
+ * 是否在线
704
+ */
705
+ get isOnline(): boolean {
706
+ return this.__session__.isOnline;
707
+ }
708
+
709
+ /**
710
+ * 获取客户端的地址
711
+ */
712
+ get remoteAddress() {
713
+ return this.__session__.remoteAddress;
714
+ }
715
+ }
716
+
717
+ let clone = function (src: any, dest: any, includes: any) {
718
+ let f;
719
+ for (let i = 0, l = includes.length; i < l; i++) {
720
+ f = includes[i];
721
+ dest[f] = src[f];
722
+ }
723
+ };
724
+
725
+ let dclone = function (src: any) {
726
+ let res: any = {};
727
+ for (let f in src) {
728
+ res[f] = src[f];
729
+ }
730
+ return res;
731
+ };