@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.
- package/LICENSE +22 -0
- package/README.md +55 -0
- package/bin/commadtest.ts +10 -0
- package/bin/commands/add.ts +43 -0
- package/bin/commands/init.ts +292 -0
- package/bin/commands/kill.ts +21 -0
- package/bin/commands/list.ts +60 -0
- package/bin/commands/masterha.ts +40 -0
- package/bin/commands/restart.ts +48 -0
- package/bin/commands/start.ts +65 -0
- package/bin/commands/stop.ts +26 -0
- package/bin/melo.ts +30 -0
- package/bin/utils/constants.ts +27 -0
- package/bin/utils/utils.ts +130 -0
- package/dist/bin/commadtest.js +9 -0
- package/dist/bin/commands/add.js +40 -0
- package/dist/bin/commands/init.js +279 -0
- package/dist/bin/commands/kill.js +21 -0
- package/dist/bin/commands/list.js +65 -0
- package/dist/bin/commands/masterha.js +36 -0
- package/dist/bin/commands/restart.js +45 -0
- package/dist/bin/commands/start.js +58 -0
- package/dist/bin/commands/stop.js +20 -0
- package/dist/bin/melo.js +26 -0
- package/dist/bin/utils/constants.js +28 -0
- package/dist/bin/utils/utils.js +134 -0
- package/dist/lib/application.js +888 -0
- package/dist/lib/common/manager/appManager.js +112 -0
- package/dist/lib/common/manager/taskManager.js +39 -0
- package/dist/lib/common/remote/backend/msgRemote.js +63 -0
- package/dist/lib/common/remote/frontend/channelRemote.js +78 -0
- package/dist/lib/common/remote/frontend/sessionRemote.js +76 -0
- package/dist/lib/common/service/backendSessionService.js +337 -0
- package/dist/lib/common/service/channelService.js +514 -0
- package/dist/lib/common/service/connectionService.js +95 -0
- package/dist/lib/common/service/filterService.js +112 -0
- package/dist/lib/common/service/handlerService.js +187 -0
- package/dist/lib/common/service/sessionService.js +610 -0
- package/dist/lib/components/backendSession.js +14 -0
- package/dist/lib/components/channel.js +13 -0
- package/dist/lib/components/connection.js +12 -0
- package/dist/lib/components/connector.js +437 -0
- package/dist/lib/components/dictionary.js +93 -0
- package/dist/lib/components/master.js +39 -0
- package/dist/lib/components/monitor.js +25 -0
- package/dist/lib/components/protobuf.js +156 -0
- package/dist/lib/components/proxy.js +236 -0
- package/dist/lib/components/pushScheduler.js +62 -0
- package/dist/lib/components/remote.js +127 -0
- package/dist/lib/components/server.js +63 -0
- package/dist/lib/components/session.js +20 -0
- package/dist/lib/connectors/commands/handshake.js +119 -0
- package/dist/lib/connectors/commands/heartbeat.js +67 -0
- package/dist/lib/connectors/commands/kick.js +15 -0
- package/dist/lib/connectors/common/coder.js +90 -0
- package/dist/lib/connectors/common/handler.js +57 -0
- package/dist/lib/connectors/hybrid/IHybridSocket.js +3 -0
- package/dist/lib/connectors/hybrid/switcher.js +100 -0
- package/dist/lib/connectors/hybrid/tcpprocessor.js +40 -0
- package/dist/lib/connectors/hybrid/tcpsocket.js +171 -0
- package/dist/lib/connectors/hybrid/wsprocessor.js +49 -0
- package/dist/lib/connectors/hybridconnector.js +89 -0
- package/dist/lib/connectors/hybridsocket.js +139 -0
- package/dist/lib/connectors/mqtt/generate.js +113 -0
- package/dist/lib/connectors/mqtt/mqttadaptor.js +81 -0
- package/dist/lib/connectors/mqtt/protocol.js +48 -0
- package/dist/lib/connectors/mqttconnector.js +107 -0
- package/dist/lib/connectors/mqttsocket.js +59 -0
- package/dist/lib/connectors/sioconnector.js +135 -0
- package/dist/lib/connectors/siosocket.js +69 -0
- package/dist/lib/connectors/udpconnector.js +76 -0
- package/dist/lib/connectors/udpsocket.js +93 -0
- package/dist/lib/filters/handler/serial.js +44 -0
- package/dist/lib/filters/handler/time.js +32 -0
- package/dist/lib/filters/handler/timeout.js +45 -0
- package/dist/lib/filters/handler/toobusy.js +36 -0
- package/dist/lib/filters/rpc/rpcLog.js +43 -0
- package/dist/lib/filters/rpc/toobusy.js +41 -0
- package/dist/lib/index.js +81 -0
- package/dist/lib/interfaces/IComponent.js +3 -0
- package/dist/lib/interfaces/IConnector.js +3 -0
- package/dist/lib/interfaces/IHandlerFilter.js +3 -0
- package/dist/lib/interfaces/ILifeCycle.js +3 -0
- package/dist/lib/interfaces/IPlugin.js +3 -0
- package/dist/lib/interfaces/IPushScheduler.js +3 -0
- package/dist/lib/interfaces/ISocket.js +3 -0
- package/dist/lib/interfaces/IStore.js +3 -0
- package/dist/lib/interfaces/define.js +3 -0
- package/dist/lib/master/master.js +129 -0
- package/dist/lib/master/starter.js +236 -0
- package/dist/lib/master/watchdog.js +120 -0
- package/dist/lib/melo.js +125 -0
- package/dist/lib/modules/console.js +436 -0
- package/dist/lib/modules/masterwatcher.js +98 -0
- package/dist/lib/modules/monitorwatcher.js +124 -0
- package/dist/lib/modules/onlineUser.js +69 -0
- package/dist/lib/modules/restartNotifyModule.js +107 -0
- package/dist/lib/modules/watchServer.js +737 -0
- package/dist/lib/monitor/monitor.js +80 -0
- package/dist/lib/pushSchedulers/buffer.js +96 -0
- package/dist/lib/pushSchedulers/direct.js +58 -0
- package/dist/lib/pushSchedulers/multi.js +80 -0
- package/dist/lib/server/server.js +500 -0
- package/dist/lib/util/appUtil.js +306 -0
- package/dist/lib/util/constants.js +117 -0
- package/dist/lib/util/countDownLatch.js +51 -0
- package/dist/lib/util/events.js +20 -0
- package/dist/lib/util/handlerHelper.js +8 -0
- package/dist/lib/util/log.js +14 -0
- package/dist/lib/util/moduleUtil.js +101 -0
- package/dist/lib/util/pathUtil.js +134 -0
- package/dist/lib/util/remoterHelper.js +8 -0
- package/dist/lib/util/utils.js +358 -0
- package/dist/test/application.js +522 -0
- package/dist/test/config/log4js.json +28 -0
- package/dist/test/config/master.json +9 -0
- package/dist/test/config/servers.json +6 -0
- package/dist/test/filters/handler/serial.js +41 -0
- package/dist/test/filters/handler/time.js +41 -0
- package/dist/test/filters/handler/timeout.js +41 -0
- package/dist/test/filters/handler/toobusy.js +57 -0
- package/dist/test/filters/rpc/rpcLog.js +22 -0
- package/dist/test/filters/rpc/toobusy.js +39 -0
- package/dist/test/manager/mockChannelManager.js +77 -0
- package/dist/test/manager/taskManager.js +68 -0
- package/dist/test/mock-base/app/servers/other-file +0 -0
- package/dist/test/mock-plugin/components/mockPlugin.js +10 -0
- package/dist/test/mock-plugin/events/mockEvent.js +12 -0
- package/dist/test/modules/console.js +242 -0
- package/dist/test/pomelo.js +19 -0
- package/dist/test/remote/channelRemote.js +159 -0
- package/dist/test/service/channel.js +134 -0
- package/dist/test/service/channelService.js +216 -0
- package/dist/test/service/connectionService.js +114 -0
- package/dist/test/service/filterService.js +144 -0
- package/dist/test/service/handlerService.js +65 -0
- package/dist/test/service/sessionService.js +387 -0
- package/dist/test/util/countDownLatch.js +70 -0
- package/dist/test/util/pathUtil.js +108 -0
- package/dist/test/util/utils.js +140 -0
- package/lib/application.ts +1240 -0
- package/lib/common/manager/appManager.ts +118 -0
- package/lib/common/manager/taskManager.ts +50 -0
- package/lib/common/remote/backend/msgRemote.ts +134 -0
- package/lib/common/remote/frontend/channelRemote.ts +91 -0
- package/lib/common/remote/frontend/sessionRemote.ts +91 -0
- package/lib/common/service/backendSessionService.ts +388 -0
- package/lib/common/service/channelService.ts +609 -0
- package/lib/common/service/connectionService.ts +112 -0
- package/lib/common/service/filterService.ts +118 -0
- package/lib/common/service/handlerService.ts +224 -0
- package/lib/common/service/sessionService.ts +731 -0
- package/lib/components/backendSession.ts +14 -0
- package/lib/components/channel.ts +11 -0
- package/lib/components/connection.ts +13 -0
- package/lib/components/connector.ts +533 -0
- package/lib/components/dictionary.ts +121 -0
- package/lib/components/master.ts +41 -0
- package/lib/components/monitor.ts +30 -0
- package/lib/components/protobuf.ts +208 -0
- package/lib/components/proxy.ts +282 -0
- package/lib/components/pushScheduler.ts +70 -0
- package/lib/components/remote.ts +166 -0
- package/lib/components/server.ts +71 -0
- package/lib/components/session.ts +22 -0
- package/lib/connectors/commands/handshake.ts +155 -0
- package/lib/connectors/commands/heartbeat.ts +83 -0
- package/lib/connectors/commands/kick.ts +11 -0
- package/lib/connectors/common/coder.ts +93 -0
- package/lib/connectors/common/handler.ts +62 -0
- package/lib/connectors/hybrid/IHybridSocket.ts +9 -0
- package/lib/connectors/hybrid/switcher.ts +142 -0
- package/lib/connectors/hybrid/tcpprocessor.ts +43 -0
- package/lib/connectors/hybrid/tcpsocket.ts +223 -0
- package/lib/connectors/hybrid/wsprocessor.ts +57 -0
- package/lib/connectors/hybridconnector.ts +134 -0
- package/lib/connectors/hybridsocket.ts +168 -0
- package/lib/connectors/mqtt/generate.ts +103 -0
- package/lib/connectors/mqtt/mqttadaptor.ts +114 -0
- package/lib/connectors/mqtt/protocol.ts +49 -0
- package/lib/connectors/mqttconnector.ts +134 -0
- package/lib/connectors/mqttsocket.ts +79 -0
- package/lib/connectors/sioconnector.ts +161 -0
- package/lib/connectors/siosocket.ts +85 -0
- package/lib/connectors/udpconnector.ts +113 -0
- package/lib/connectors/udpsocket.ts +110 -0
- package/lib/filters/handler/serial.ts +46 -0
- package/lib/filters/handler/time.ts +35 -0
- package/lib/filters/handler/timeout.ts +50 -0
- package/lib/filters/handler/toobusy.ts +37 -0
- package/lib/filters/rpc/rpcLog.ts +42 -0
- package/lib/filters/rpc/toobusy.ts +41 -0
- package/lib/index.ts +74 -0
- package/lib/interfaces/IComponent.ts +47 -0
- package/lib/interfaces/IConnector.ts +20 -0
- package/lib/interfaces/IHandlerFilter.ts +15 -0
- package/lib/interfaces/ILifeCycle.ts +16 -0
- package/lib/interfaces/IPlugin.ts +65 -0
- package/lib/interfaces/IPushScheduler.ts +52 -0
- package/lib/interfaces/ISocket.ts +26 -0
- package/lib/interfaces/IStore.ts +10 -0
- package/lib/interfaces/define.ts +15 -0
- package/lib/master/master.ts +148 -0
- package/lib/master/starter.ts +234 -0
- package/lib/master/watchdog.ts +135 -0
- package/lib/melo.ts +152 -0
- package/lib/modules/console.ts +465 -0
- package/lib/modules/masterwatcher.ts +120 -0
- package/lib/modules/monitorwatcher.ts +151 -0
- package/lib/modules/onlineUser.ts +78 -0
- package/lib/modules/restartNotifyModule.ts +128 -0
- package/lib/modules/watchServer.ts +766 -0
- package/lib/monitor/monitor.ts +99 -0
- package/lib/pushSchedulers/buffer.ts +117 -0
- package/lib/pushSchedulers/direct.ts +65 -0
- package/lib/pushSchedulers/multi.ts +94 -0
- package/lib/server/server.ts +554 -0
- package/lib/util/appUtil.ts +313 -0
- package/lib/util/constants.ts +154 -0
- package/lib/util/countDownLatch.ts +72 -0
- package/lib/util/events.ts +15 -0
- package/lib/util/handlerHelper.ts +5 -0
- package/lib/util/log.ts +11 -0
- package/lib/util/moduleUtil.ts +110 -0
- package/lib/util/pathUtil.ts +132 -0
- package/lib/util/remoterHelper.ts +68 -0
- package/lib/util/utils.ts +365 -0
- package/package.json +93 -0
- package/template/game-server/.vscode/launch.json +27 -0
- package/template/game-server/app/servers/connector/handler/entryHandler.ts +50 -0
- package/template/game-server/app/servers/connector/remote/authRemoter.ts +36 -0
- package/template/game-server/app.ts +30 -0
- package/template/game-server/app.ts.mqtt +32 -0
- package/template/game-server/app.ts.sio +36 -0
- package/template/game-server/app.ts.sio.wss +34 -0
- package/template/game-server/app.ts.udp +31 -0
- package/template/game-server/app.ts.wss +40 -0
- package/template/game-server/config/adminServer.json +5 -0
- package/template/game-server/config/adminUser.json +22 -0
- package/template/game-server/config/clientProtos.json +1 -0
- package/template/game-server/config/dictionary.json +1 -0
- package/template/game-server/config/log4js.json +150 -0
- package/template/game-server/config/master.json +8 -0
- package/template/game-server/config/serverProtos.json +1 -0
- package/template/game-server/config/servers.json +12 -0
- package/template/game-server/copy.js +5 -0
- package/template/game-server/package.json +28 -0
- package/template/game-server/preload.ts +40 -0
- package/template/game-server/tsconfig.json +36 -0
- package/template/npm-install.bat +4 -0
- package/template/npm-install.sh +5 -0
- package/template/readme.md +31 -0
- package/template/shared/server.crt +15 -0
- package/template/shared/server.key +15 -0
- package/template/web-server/app.js +25 -0
- package/template/web-server/app.js.https +36 -0
- package/template/web-server/bin/component.bat +1 -0
- package/template/web-server/bin/component.sh +1 -0
- package/template/web-server/package.json +10 -0
- package/template/web-server/public/css/base.css +76 -0
- package/template/web-server/public/image/logo.png +0 -0
- package/template/web-server/public/image/sp.png +0 -0
- package/template/web-server/public/index.html +57 -0
- package/template/web-server/public/index.html.sio +58 -0
- package/template/web-server/public/js/lib/build/build.js +1730 -0
- package/template/web-server/public/js/lib/build/build.js.wss +1721 -0
- package/template/web-server/public/js/lib/component.json +6 -0
- package/template/web-server/public/js/lib/local/boot/component.json +11 -0
- package/template/web-server/public/js/lib/local/boot/index.js +11 -0
- package/template/web-server/public/js/lib/meloclient.js +456 -0
- package/template/web-server/public/js/lib/meloclient.js.wss +456 -0
- package/template/web-server/public/js/lib/socket.io.js +3 -0
- package/test/application.ts +607 -0
- package/test/filters/handler/serial.ts +47 -0
- package/test/filters/handler/time.ts +47 -0
- package/test/filters/handler/timeout.ts +46 -0
- package/test/filters/handler/toobusy.ts +59 -0
- package/test/filters/rpc/rpcLog.ts +20 -0
- package/test/filters/rpc/toobusy.ts +40 -0
- package/test/manager/mockChannelManager.ts +92 -0
- package/test/manager/taskManager.ts +78 -0
- package/test/mock-base/app/servers/other-file +0 -0
- package/test/mock-plugin/components/mockPlugin.ts +8 -0
- package/test/mock-plugin/events/mockEvent.ts +12 -0
- package/test/modules/console.ts +264 -0
- package/test/pomelo.ts +18 -0
- package/test/remote/channelRemote.ts +176 -0
- package/test/service/channel.ts +161 -0
- package/test/service/channelService.ts +243 -0
- package/test/service/connectionService.ts +142 -0
- package/test/service/filterService.ts +165 -0
- package/test/service/handlerService.ts +77 -0
- package/test/service/sessionService.ts +464 -0
- package/test/util/countDownLatch.ts +81 -0
- package/test/util/pathUtil.ts +122 -0
- 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
|
+
};
|