melo-example-robot 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 +6 -0
- package/app/script/ByteArray.ts +1188 -0
- package/app/script/Client.ts +93 -0
- package/app/script/MeloForEgret.ts +911 -0
- package/app.ts +34 -0
- package/dist/app/config/dev/config.json +3 -0
- package/dist/app/config/env.json +4 -0
- package/dist/app/config/prod/config.json +3 -0
- package/dist/app/script/ByteArray.js +1103 -0
- package/dist/app/script/Client.js +83 -0
- package/dist/app/script/MeloForEgret.js +741 -0
- package/dist/app.js +33 -0
- package/dist/http.js +66 -0
- package/dist/nodejs-ts-client/cacheClass.js +19 -0
- package/dist/nodejs-ts-client/client.js +396 -0
- package/dist/nodejs-ts-client/logger.service.js +59 -0
- package/dist/nodejs-ts-client/my.logger.js +49 -0
- package/http.ts +64 -0
- package/nodejs-ts-client/README.md +3 -0
- package/nodejs-ts-client/cacheClass.ts +21 -0
- package/nodejs-ts-client/client.ts +475 -0
- package/nodejs-ts-client/logger.service.ts +107 -0
- package/nodejs-ts-client/my.logger.ts +61 -0
- package/package.json +35 -0
- package/tsconfig.json +33 -0
|
@@ -0,0 +1,911 @@
|
|
|
1
|
+
|
|
2
|
+
import * as egret from './ByteArray';
|
|
3
|
+
import * as WebSocket from 'ws';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Created by govo on 15/8/14.
|
|
7
|
+
*
|
|
8
|
+
* Melo Client for Egret, with protobuf support, with js ws client version 0.0.5
|
|
9
|
+
* Github: https://github.com/govo/MeloForEgret.git
|
|
10
|
+
*
|
|
11
|
+
* Thanks to:
|
|
12
|
+
* D-Deo @ https://github.com/D-Deo/melo-flash-tcp.git
|
|
13
|
+
* and yicaoyimu @ http://bbs.egret.com/forum.php?mod=viewthread&tid=2538&highlight=melo
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
export class WSClient {
|
|
20
|
+
|
|
21
|
+
static DEBUG: boolean = false;
|
|
22
|
+
static EVENT_IO_ERROR: string = 'io-error';
|
|
23
|
+
static EVENT_CLOSE: string = 'close';
|
|
24
|
+
static EVENT_KICK: string = 'onKick';
|
|
25
|
+
static EVENT_HEART_BEAT_TIMEOUT: string = 'heartbeat timeout';
|
|
26
|
+
|
|
27
|
+
private JS_WS_CLIENT_TYPE: string = 'js-websocket';
|
|
28
|
+
private JS_WS_CLIENT_VERSION: string = '0.0.5';
|
|
29
|
+
|
|
30
|
+
private RES_OK: number = 200;
|
|
31
|
+
private RES_FAIL: number = 500;
|
|
32
|
+
private RES_OLD_CLIENT: number = 501;
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
private socket: WebSocket = null;
|
|
36
|
+
private callbacks: any = {};
|
|
37
|
+
private handlers: any = {};
|
|
38
|
+
// Map from request id to route
|
|
39
|
+
private routeMap = {};
|
|
40
|
+
|
|
41
|
+
private heartbeatInterval: number = 0;
|
|
42
|
+
private heartbeatTimeout: number = 0;
|
|
43
|
+
private nextHeartbeatTimeout: number = 0;
|
|
44
|
+
private gapThreshold: number = 100;
|
|
45
|
+
private heartbeatId: any = null;
|
|
46
|
+
private heartbeatTimeoutId: any = null;
|
|
47
|
+
|
|
48
|
+
private handshakeCallback: any = null;
|
|
49
|
+
private handshakeBuffer: any;
|
|
50
|
+
private initCallback: Function = null;
|
|
51
|
+
|
|
52
|
+
private _callbacks: any = {};
|
|
53
|
+
|
|
54
|
+
private reqId: number = 0;
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
private _package: IPackage;
|
|
58
|
+
private _message: IMessage;
|
|
59
|
+
|
|
60
|
+
constructor() {
|
|
61
|
+
|
|
62
|
+
this.socket = null;
|
|
63
|
+
this.callbacks = {};
|
|
64
|
+
this.handlers = {};
|
|
65
|
+
// Map from request id to route
|
|
66
|
+
this.routeMap = {};
|
|
67
|
+
this._message = new Message(this.routeMap);
|
|
68
|
+
this._package = new Package();
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
this.heartbeatInterval = 0;
|
|
72
|
+
this.heartbeatTimeout = 0;
|
|
73
|
+
this.nextHeartbeatTimeout = 0;
|
|
74
|
+
this.gapThreshold = 100;
|
|
75
|
+
this.heartbeatId = null;
|
|
76
|
+
this.heartbeatTimeoutId = null;
|
|
77
|
+
|
|
78
|
+
this.handshakeCallback = null;
|
|
79
|
+
|
|
80
|
+
this.handshakeBuffer = {
|
|
81
|
+
'sys': {
|
|
82
|
+
type: this.JS_WS_CLIENT_TYPE,
|
|
83
|
+
version: this.JS_WS_CLIENT_VERSION
|
|
84
|
+
},
|
|
85
|
+
'user': {
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
this.initCallback = null;
|
|
90
|
+
|
|
91
|
+
this.reqId = 0;
|
|
92
|
+
|
|
93
|
+
this.handlers[Package.TYPE_HANDSHAKE] = this.handshake;
|
|
94
|
+
this.handlers[Package.TYPE_HEARTBEAT] = this.heartbeat;
|
|
95
|
+
this.handlers[Package.TYPE_DATA] = this.onData;
|
|
96
|
+
this.handlers[Package.TYPE_KICK] = this.onKick;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
public init(params, cb: Function): void {
|
|
101
|
+
console.log('init', params);
|
|
102
|
+
this.initCallback = cb;
|
|
103
|
+
let host = params.host;
|
|
104
|
+
let port = params.port;
|
|
105
|
+
//
|
|
106
|
+
// var url = 'ws://' + host;
|
|
107
|
+
// if(port) {
|
|
108
|
+
// url += ':' + port;
|
|
109
|
+
// }
|
|
110
|
+
|
|
111
|
+
this.handshakeBuffer.user = params.user;
|
|
112
|
+
this.handshakeCallback = params.handshakeCallback;
|
|
113
|
+
this.initWebSocket(host, port, cb);
|
|
114
|
+
}
|
|
115
|
+
private initWebSocket(host, port, cb: Function): void {
|
|
116
|
+
console.log('[Melo] connect to:', host, port);
|
|
117
|
+
|
|
118
|
+
let onopen = (event) => {
|
|
119
|
+
this.onConnect();
|
|
120
|
+
};
|
|
121
|
+
let onmessage = (event) => {
|
|
122
|
+
this.onMessage(event);
|
|
123
|
+
};
|
|
124
|
+
let onerror = (event) => {
|
|
125
|
+
this.onIOError(event);
|
|
126
|
+
};
|
|
127
|
+
let onclose = (event) => {
|
|
128
|
+
this.onClose(event);
|
|
129
|
+
};
|
|
130
|
+
let url = 'ws://' + host;
|
|
131
|
+
if (port) {
|
|
132
|
+
url += ':' + port;
|
|
133
|
+
}
|
|
134
|
+
let socket = new WebSocket(url);
|
|
135
|
+
socket.binaryType = 'arraybuffer';
|
|
136
|
+
socket.onopen = onopen;
|
|
137
|
+
socket.onmessage = onmessage;
|
|
138
|
+
socket.onerror = onerror;
|
|
139
|
+
socket.onclose = onclose;
|
|
140
|
+
this.socket = socket;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
public on(event, fn) {
|
|
145
|
+
(this._callbacks[event] = this._callbacks[event] || []).push(fn);
|
|
146
|
+
}
|
|
147
|
+
public request(route, msg, cb) {
|
|
148
|
+
if (arguments.length === 2 && typeof msg === 'function') {
|
|
149
|
+
cb = msg;
|
|
150
|
+
msg = {};
|
|
151
|
+
} else {
|
|
152
|
+
msg = msg || {};
|
|
153
|
+
}
|
|
154
|
+
route = route || msg.route;
|
|
155
|
+
if (!route) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
this.reqId++;
|
|
160
|
+
if (this.reqId > 127) {
|
|
161
|
+
this.reqId = 1;
|
|
162
|
+
}
|
|
163
|
+
let reqId = this.reqId;
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
if (WSClient.DEBUG) {
|
|
167
|
+
console.log(`REQUEST:route:${route} , reqId:${reqId}, msg:${msg}`);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
this.sendMessage(reqId, route, msg);
|
|
171
|
+
|
|
172
|
+
this.callbacks[reqId] = cb;
|
|
173
|
+
this.routeMap[reqId] = route;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
public notify(route: string, msg: any): void {
|
|
177
|
+
this.sendMessage(0, route, msg);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private onMessage(event: { data: string | Buffer | ArrayBuffer | Buffer[]; type: string; target: WebSocket }): void {
|
|
181
|
+
this.processPackage(this._package.decode(new egret.ByteArray(<ArrayBuffer>event.data)));
|
|
182
|
+
|
|
183
|
+
}
|
|
184
|
+
private sendMessage(reqId, route, msg) {
|
|
185
|
+
let byte: egret.ByteArray;
|
|
186
|
+
|
|
187
|
+
byte = this._message.encode(reqId, route, msg);
|
|
188
|
+
byte = this._package.encode(Package.TYPE_DATA, byte);
|
|
189
|
+
|
|
190
|
+
this.send(byte);
|
|
191
|
+
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private onConnect(): void {
|
|
195
|
+
console.log('[Melo] connect success');
|
|
196
|
+
this.send(this._package.encode(Package.TYPE_HANDSHAKE, Protocol.strencode(JSON.stringify(this.handshakeBuffer))));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private onClose(e: any): void {
|
|
200
|
+
console.error('[Melo] connect close:', e);
|
|
201
|
+
// this.emit(Melo.EVENT_CLOSE,e);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
private onIOError(e: any): void {
|
|
205
|
+
// this.emit(Melo.EVENT_IO_ERROR, e);
|
|
206
|
+
console.error('socket error: ', e);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private onKick(event) {
|
|
210
|
+
event = JSON.parse(Protocol.strdecode(event));
|
|
211
|
+
this.emit(WSClient.EVENT_KICK, event);
|
|
212
|
+
}
|
|
213
|
+
private onData(data) {
|
|
214
|
+
// probuff decode
|
|
215
|
+
let msg = this._message.decode(data);
|
|
216
|
+
|
|
217
|
+
if (msg.id > 0) {
|
|
218
|
+
msg.route = this.routeMap[msg.id];
|
|
219
|
+
delete this.routeMap[msg.id];
|
|
220
|
+
if (!msg.route) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// msg.body = this.deCompose(msg);
|
|
226
|
+
|
|
227
|
+
this.processMessage(msg);
|
|
228
|
+
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
private processMessage(msg) {
|
|
232
|
+
if (!msg.id) {
|
|
233
|
+
// server push message
|
|
234
|
+
|
|
235
|
+
if (WSClient.DEBUG) {
|
|
236
|
+
console.log(`EVENT: Route:${msg.route} Msg:${msg.body}`);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
this.emit(msg.route, msg.body);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (WSClient.DEBUG) {
|
|
243
|
+
console.log(`RESPONSE: Id:${msg.id} Msg:${msg.body}`);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// if have a id then find the callback function with the request
|
|
247
|
+
let cb = this.callbacks[msg.id];
|
|
248
|
+
|
|
249
|
+
delete this.callbacks[msg.id];
|
|
250
|
+
if (typeof cb !== 'function') {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
if (msg.body && msg.body.code === 500) {
|
|
254
|
+
let obj: any = { 'code': 500, 'desc': '服务器内部错误', 'key': 'INTERNAL_ERROR' };
|
|
255
|
+
msg.body.error = obj;
|
|
256
|
+
}
|
|
257
|
+
cb(msg.body);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
private heartbeat(data) {
|
|
262
|
+
|
|
263
|
+
if (!this.heartbeatInterval) {
|
|
264
|
+
// no heartbeat
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
let obj = this._package.encode(Package.TYPE_HEARTBEAT);
|
|
269
|
+
if (this.heartbeatTimeoutId) {
|
|
270
|
+
clearTimeout(this.heartbeatTimeoutId);
|
|
271
|
+
this.heartbeatTimeoutId = null;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (this.heartbeatId) {
|
|
275
|
+
// already in a heartbeat interval
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
let self = this;
|
|
280
|
+
self.heartbeatId = setTimeout(function () {
|
|
281
|
+
self.heartbeatId = null;
|
|
282
|
+
self.send(obj);
|
|
283
|
+
|
|
284
|
+
self.nextHeartbeatTimeout = Date.now() + self.heartbeatTimeout;
|
|
285
|
+
self.heartbeatTimeoutId = setTimeout(self.heartbeatTimeoutCb.bind(self, data), self.heartbeatTimeout);
|
|
286
|
+
}, self.heartbeatInterval);
|
|
287
|
+
}
|
|
288
|
+
private heartbeatTimeoutCb(data) {
|
|
289
|
+
let gap = this.nextHeartbeatTimeout - Date.now();
|
|
290
|
+
if (gap > this.gapThreshold) {
|
|
291
|
+
this.heartbeatTimeoutId = setTimeout(this.heartbeatTimeoutCb.bind(this, data), gap);
|
|
292
|
+
} else {
|
|
293
|
+
console.error('server heartbeat timeout', data);
|
|
294
|
+
// this.emit(WSClient.EVENT_HEART_BEAT_TIMEOUT,data);
|
|
295
|
+
this._disconnect();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
public off(event?, fn?) {
|
|
299
|
+
this.removeAllListeners(event, fn);
|
|
300
|
+
}
|
|
301
|
+
public removeAllListeners(event?, fn?) {
|
|
302
|
+
// all
|
|
303
|
+
if (0 === arguments.length) {
|
|
304
|
+
this._callbacks = {};
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// specific event
|
|
309
|
+
let callbacks = this._callbacks[event];
|
|
310
|
+
if (!callbacks) {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// remove all handlers
|
|
315
|
+
if (event && !fn) {
|
|
316
|
+
delete this._callbacks[event];
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// remove specific handler
|
|
321
|
+
let i = this.index(callbacks, fn._off || fn);
|
|
322
|
+
if (~i) {
|
|
323
|
+
callbacks.splice(i, 1);
|
|
324
|
+
}
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
private index(arr, obj) {
|
|
328
|
+
if ([].indexOf) {
|
|
329
|
+
return arr.indexOf(obj);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
for (let i = 0; i < arr.length; ++i) {
|
|
333
|
+
if (arr[i] === obj)
|
|
334
|
+
return i;
|
|
335
|
+
}
|
|
336
|
+
return -1;
|
|
337
|
+
}
|
|
338
|
+
public disconnect(): void {
|
|
339
|
+
this._disconnect();
|
|
340
|
+
}
|
|
341
|
+
private _disconnect(): void {
|
|
342
|
+
console.warn('[Melo] client disconnect ...');
|
|
343
|
+
|
|
344
|
+
if (this.socket) this.socket.close();
|
|
345
|
+
this.socket = null;
|
|
346
|
+
if (this.heartbeatId) {
|
|
347
|
+
clearTimeout(this.heartbeatId);
|
|
348
|
+
this.heartbeatId = null;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (this.heartbeatTimeoutId) {
|
|
352
|
+
clearTimeout(this.heartbeatTimeoutId);
|
|
353
|
+
this.heartbeatTimeoutId = null;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
}
|
|
357
|
+
private processPackage(msg): void {
|
|
358
|
+
this.handlers[msg.type].apply(this, [msg.body]);
|
|
359
|
+
}
|
|
360
|
+
private handshake(resData) {
|
|
361
|
+
|
|
362
|
+
let data = JSON.parse(Protocol.strdecode(resData));
|
|
363
|
+
if (data.code === this.RES_OLD_CLIENT) {
|
|
364
|
+
// this.emit(WSClient.EVENT_IO_ERROR, 'client version not fullfill');
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (data.code !== this.RES_OK) {
|
|
369
|
+
// this.emit(WSClient.EVENT_IO_ERROR, 'handshake fail');
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
this.handshakeInit(data);
|
|
374
|
+
|
|
375
|
+
let obj = this._package.encode(Package.TYPE_HANDSHAKE_ACK);
|
|
376
|
+
this.send(obj);
|
|
377
|
+
if (this.initCallback) {
|
|
378
|
+
this.initCallback(data);
|
|
379
|
+
this.initCallback = null;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
private handshakeInit(data): void {
|
|
383
|
+
|
|
384
|
+
if (data.sys) {
|
|
385
|
+
Routedic.init(data.sys.dict);
|
|
386
|
+
Protobuf.init(data.sys.protos);
|
|
387
|
+
}
|
|
388
|
+
if (data.sys && data.sys.heartbeat) {
|
|
389
|
+
this.heartbeatInterval = data.sys.heartbeat * 1000; // heartbeat interval
|
|
390
|
+
this.heartbeatTimeout = this.heartbeatInterval * 2; // max heartbeat timeout
|
|
391
|
+
} else {
|
|
392
|
+
this.heartbeatInterval = 0;
|
|
393
|
+
this.heartbeatTimeout = 0;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (typeof this.handshakeCallback === 'function') {
|
|
397
|
+
this.handshakeCallback(data.user);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
private send(byte: egret.ByteArray): void {
|
|
401
|
+
if (this.socket) {
|
|
402
|
+
this.socket.send(byte.buffer);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
// private deCompose(msg){
|
|
406
|
+
// return JSON.parse(Protocol.strdecode(msg.body));
|
|
407
|
+
// }
|
|
408
|
+
private emit(event, ...args: any[]) {
|
|
409
|
+
let params = [].slice.call(arguments, 1);
|
|
410
|
+
let callbacks = this._callbacks[event];
|
|
411
|
+
|
|
412
|
+
if (callbacks) {
|
|
413
|
+
callbacks = callbacks.slice(0);
|
|
414
|
+
for (let i = 0, len = callbacks.length; i < len; ++i) {
|
|
415
|
+
callbacks[i].apply(this, params);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
return this;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
class Package implements IPackage {
|
|
426
|
+
static TYPE_HANDSHAKE: number = 1;
|
|
427
|
+
static TYPE_HANDSHAKE_ACK: number = 2;
|
|
428
|
+
static TYPE_HEARTBEAT: number = 3;
|
|
429
|
+
static TYPE_DATA: number = 4;
|
|
430
|
+
static TYPE_KICK: number = 5;
|
|
431
|
+
|
|
432
|
+
public encode(type: number, body?: egret.ByteArray) {
|
|
433
|
+
let length: number = body ? body.length : 0;
|
|
434
|
+
|
|
435
|
+
let buffer: egret.ByteArray = new egret.ByteArray();
|
|
436
|
+
buffer.writeByte(type & 0xff);
|
|
437
|
+
buffer.writeByte((length >> 16) & 0xff);
|
|
438
|
+
buffer.writeByte((length >> 8) & 0xff);
|
|
439
|
+
buffer.writeByte(length & 0xff);
|
|
440
|
+
|
|
441
|
+
if (body) buffer.writeBytes(body, 0, body.length);
|
|
442
|
+
|
|
443
|
+
return buffer;
|
|
444
|
+
}
|
|
445
|
+
public decode(buffer: egret.ByteArray) {
|
|
446
|
+
|
|
447
|
+
let type: number = buffer.readUnsignedByte();
|
|
448
|
+
let len: number = (buffer.readUnsignedByte() << 16 | buffer.readUnsignedByte() << 8 | buffer.readUnsignedByte()) >>> 0;
|
|
449
|
+
|
|
450
|
+
let body: egret.ByteArray;
|
|
451
|
+
|
|
452
|
+
if (buffer.bytesAvailable >= len) {
|
|
453
|
+
body = new egret.ByteArray();
|
|
454
|
+
if (len) buffer.readBytes(body, 0, len);
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
console.log('[Package] no enough length for current type:', type);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
return { type: type, body: body, length: len };
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
class Message implements IMessage {
|
|
465
|
+
|
|
466
|
+
public static MSG_FLAG_BYTES: number = 1;
|
|
467
|
+
public static MSG_ROUTE_CODE_BYTES: number = 2;
|
|
468
|
+
public static MSG_ID_MAX_BYTES: number = 5;
|
|
469
|
+
public static MSG_ROUTE_LEN_BYTES: number = 1;
|
|
470
|
+
|
|
471
|
+
public static MSG_ROUTE_CODE_MAX: number = 0xffff;
|
|
472
|
+
|
|
473
|
+
public static MSG_COMPRESS_ROUTE_MASK: number = 0x1;
|
|
474
|
+
public static MSG_TYPE_MASK: number = 0x7;
|
|
475
|
+
|
|
476
|
+
static TYPE_REQUEST: number = 0;
|
|
477
|
+
static TYPE_NOTIFY: number = 1;
|
|
478
|
+
static TYPE_RESPONSE: number = 2;
|
|
479
|
+
static TYPE_PUSH: number = 3;
|
|
480
|
+
|
|
481
|
+
constructor(private routeMap: {}) {
|
|
482
|
+
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
public encode(id: number, route: string, msg: any) {
|
|
486
|
+
let buffer: egret.ByteArray = new egret.ByteArray();
|
|
487
|
+
|
|
488
|
+
let type: number = id ? Message.TYPE_REQUEST : Message.TYPE_NOTIFY;
|
|
489
|
+
|
|
490
|
+
let byte: egret.ByteArray = Protobuf.encode(route, msg) || Protocol.strencode(JSON.stringify(msg));
|
|
491
|
+
|
|
492
|
+
let rot: any = Routedic.getID(route) || route;
|
|
493
|
+
|
|
494
|
+
buffer.writeByte((type << 1) | ((typeof (rot) === 'string') ? 0 : 1));
|
|
495
|
+
|
|
496
|
+
if (id) {
|
|
497
|
+
// 7.x
|
|
498
|
+
do {
|
|
499
|
+
let tmp: number = id % 128;
|
|
500
|
+
let next: number = Math.floor(id / 128);
|
|
501
|
+
|
|
502
|
+
if (next !== 0) {
|
|
503
|
+
tmp = tmp + 128;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
buffer.writeByte(tmp);
|
|
507
|
+
|
|
508
|
+
id = next;
|
|
509
|
+
} while (id !== 0);
|
|
510
|
+
|
|
511
|
+
// 5.x
|
|
512
|
+
// var len:Array = [];
|
|
513
|
+
// len.push(id & 0x7f);
|
|
514
|
+
// id >>= 7;
|
|
515
|
+
// while(id > 0)
|
|
516
|
+
// {
|
|
517
|
+
// len.push(id & 0x7f | 0x80);
|
|
518
|
+
// id >>= 7;
|
|
519
|
+
// }
|
|
520
|
+
//
|
|
521
|
+
// for (var i:int = len.length - 1; i >= 0; i--)
|
|
522
|
+
// {
|
|
523
|
+
// buffer.writeByte(len[i]);
|
|
524
|
+
// }
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (rot) {
|
|
528
|
+
if (typeof rot === 'string') {
|
|
529
|
+
buffer.writeByte(rot.length & 0xff);
|
|
530
|
+
buffer.writeUTFBytes(rot);
|
|
531
|
+
}
|
|
532
|
+
else {
|
|
533
|
+
buffer.writeByte((rot >> 8) & 0xff);
|
|
534
|
+
buffer.writeByte(rot & 0xff);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (byte) {
|
|
539
|
+
buffer.writeBytes(byte);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
return buffer;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
public decode(buffer: egret.ByteArray): any {
|
|
546
|
+
// parse flag
|
|
547
|
+
let flag: number = buffer.readUnsignedByte();
|
|
548
|
+
let compressRoute: number = flag & Message.MSG_COMPRESS_ROUTE_MASK;
|
|
549
|
+
let type: number = (flag >> 1) & Message.MSG_TYPE_MASK;
|
|
550
|
+
let route: any;
|
|
551
|
+
|
|
552
|
+
// parse id
|
|
553
|
+
let id: number = 0;
|
|
554
|
+
if (type === Message.TYPE_REQUEST || type === Message.TYPE_RESPONSE) {
|
|
555
|
+
// 7.x
|
|
556
|
+
let i: number = 0;
|
|
557
|
+
let m: number;
|
|
558
|
+
do {
|
|
559
|
+
m = buffer.readUnsignedByte();
|
|
560
|
+
id = id + ((m & 0x7f) * Math.pow(2, (7 * i)));
|
|
561
|
+
i++;
|
|
562
|
+
} while (m >= 128);
|
|
563
|
+
|
|
564
|
+
// 5.x
|
|
565
|
+
// var byte:int = buffer.readUnsignedByte();
|
|
566
|
+
// id = byte & 0x7f;
|
|
567
|
+
// while(byte & 0x80)
|
|
568
|
+
// {
|
|
569
|
+
// id <<= 7;
|
|
570
|
+
// byte = buffer.readUnsignedByte();
|
|
571
|
+
// id |= byte & 0x7f;
|
|
572
|
+
// }
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// parse route
|
|
576
|
+
if (type === Message.TYPE_REQUEST || type === Message.TYPE_NOTIFY || type === Message.TYPE_PUSH) {
|
|
577
|
+
|
|
578
|
+
if (compressRoute) {
|
|
579
|
+
route = buffer.readUnsignedShort();
|
|
580
|
+
}
|
|
581
|
+
else {
|
|
582
|
+
let routeLen: number = buffer.readUnsignedByte();
|
|
583
|
+
route = routeLen ? buffer.readUTFBytes(routeLen) : '';
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
else if (type === Message.TYPE_RESPONSE) {
|
|
587
|
+
route = this.routeMap[id];
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
if (!id && !(typeof (route) === 'string')) {
|
|
591
|
+
route = Routedic.getName(route);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
let body: any = Protobuf.decode(route, buffer) || JSON.parse(Protocol.strdecode(buffer));
|
|
595
|
+
|
|
596
|
+
return { id: id, type: type, route: route, body: body };
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
}
|
|
600
|
+
class Protocol {
|
|
601
|
+
|
|
602
|
+
public static strencode(str: string): egret.ByteArray {
|
|
603
|
+
let buffer: egret.ByteArray = new egret.ByteArray();
|
|
604
|
+
buffer.length = str.length;
|
|
605
|
+
buffer.writeUTFBytes(str);
|
|
606
|
+
return buffer;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
public static strdecode(byte: egret.ByteArray): string {
|
|
610
|
+
return byte.readUTFBytes(byte.bytesAvailable);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
class Protobuf {
|
|
614
|
+
static TYPES: any = {
|
|
615
|
+
uInt32: 0,
|
|
616
|
+
sInt32: 0,
|
|
617
|
+
int32: 0,
|
|
618
|
+
double: 1,
|
|
619
|
+
string: 2,
|
|
620
|
+
message: 2,
|
|
621
|
+
float: 5
|
|
622
|
+
};
|
|
623
|
+
private static _clients: any = {};
|
|
624
|
+
private static _servers: any = {};
|
|
625
|
+
|
|
626
|
+
static init(protos: any): void {
|
|
627
|
+
this._clients = protos && protos.client || {};
|
|
628
|
+
this._servers = protos && protos.server || {};
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
static encode(route: string, msg: any): egret.ByteArray {
|
|
632
|
+
|
|
633
|
+
let protos: any = this._clients[route];
|
|
634
|
+
|
|
635
|
+
if (!protos) return null;
|
|
636
|
+
|
|
637
|
+
return this.encodeProtos(protos, msg);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
static decode(route: string, buffer: egret.ByteArray): any {
|
|
641
|
+
|
|
642
|
+
let protos: any = this._servers[route];
|
|
643
|
+
|
|
644
|
+
if (!protos) return null;
|
|
645
|
+
|
|
646
|
+
return this.decodeProtos(protos, buffer);
|
|
647
|
+
}
|
|
648
|
+
private static encodeProtos(protos: any, msg: any): egret.ByteArray {
|
|
649
|
+
let buffer: egret.ByteArray = new egret.ByteArray();
|
|
650
|
+
|
|
651
|
+
for (let name in msg) {
|
|
652
|
+
if (protos[name]) {
|
|
653
|
+
let proto: any = protos[name];
|
|
654
|
+
|
|
655
|
+
switch (proto.option) {
|
|
656
|
+
case 'optional':
|
|
657
|
+
case 'required':
|
|
658
|
+
buffer.writeBytes(this.encodeTag(proto.type, proto.tag));
|
|
659
|
+
this.encodeProp(msg[name], proto.type, protos, buffer);
|
|
660
|
+
break;
|
|
661
|
+
case 'repeated':
|
|
662
|
+
if (!!msg[name] && msg[name].length > 0) {
|
|
663
|
+
this.encodeArray(msg[name], proto, protos, buffer);
|
|
664
|
+
}
|
|
665
|
+
break;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
return buffer;
|
|
671
|
+
}
|
|
672
|
+
static decodeProtos(protos: any, buffer: egret.ByteArray): any {
|
|
673
|
+
let msg: any = {};
|
|
674
|
+
|
|
675
|
+
while (buffer.bytesAvailable) {
|
|
676
|
+
let head: any = this.getHead(buffer);
|
|
677
|
+
let name: string = protos.__tags[head.tag];
|
|
678
|
+
|
|
679
|
+
switch (protos[name].option) {
|
|
680
|
+
case 'optional':
|
|
681
|
+
case 'required':
|
|
682
|
+
msg[name] = this.decodeProp(protos[name].type, protos, buffer);
|
|
683
|
+
break;
|
|
684
|
+
case 'repeated':
|
|
685
|
+
if (!msg[name]) {
|
|
686
|
+
msg[name] = [];
|
|
687
|
+
}
|
|
688
|
+
this.decodeArray(msg[name], protos[name].type, protos, buffer);
|
|
689
|
+
break;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
return msg;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
static encodeTag(type: number, tag: number): egret.ByteArray {
|
|
697
|
+
let value: number = this.TYPES[type] !== undefined ? this.TYPES[type] : 2;
|
|
698
|
+
|
|
699
|
+
return this.encodeUInt32((tag << 3) | value);
|
|
700
|
+
}
|
|
701
|
+
static getHead(buffer: egret.ByteArray): any {
|
|
702
|
+
let tag: number = this.decodeUInt32(buffer);
|
|
703
|
+
|
|
704
|
+
return { type: tag & 0x7, tag: tag >> 3 };
|
|
705
|
+
}
|
|
706
|
+
static encodeProp(value: any, type: string, protos: any, buffer: egret.ByteArray): void {
|
|
707
|
+
switch (type) {
|
|
708
|
+
case 'uInt32':
|
|
709
|
+
buffer.writeBytes(this.encodeUInt32(value));
|
|
710
|
+
break;
|
|
711
|
+
case 'int32':
|
|
712
|
+
case 'sInt32':
|
|
713
|
+
buffer.writeBytes(this.encodeSInt32(value));
|
|
714
|
+
break;
|
|
715
|
+
case 'float':
|
|
716
|
+
// Float32Array
|
|
717
|
+
let floats: egret.ByteArray = new egret.ByteArray();
|
|
718
|
+
floats.endian = egret.Endian.LITTLE_ENDIAN;
|
|
719
|
+
floats.writeFloat(value);
|
|
720
|
+
buffer.writeBytes(floats);
|
|
721
|
+
break;
|
|
722
|
+
case 'double':
|
|
723
|
+
let doubles: egret.ByteArray = new egret.ByteArray();
|
|
724
|
+
doubles.endian = egret.Endian.LITTLE_ENDIAN;
|
|
725
|
+
doubles.writeDouble(value);
|
|
726
|
+
buffer.writeBytes(doubles);
|
|
727
|
+
break;
|
|
728
|
+
case 'string':
|
|
729
|
+
buffer.writeBytes(this.encodeUInt32(value.length));
|
|
730
|
+
buffer.writeUTFBytes(value);
|
|
731
|
+
break;
|
|
732
|
+
default:
|
|
733
|
+
let proto: any = protos.__messages[type] || this._clients['message ' + type];
|
|
734
|
+
if (!!proto) {
|
|
735
|
+
let buf: egret.ByteArray = this.encodeProtos(proto, value);
|
|
736
|
+
buffer.writeBytes(this.encodeUInt32(buf.length));
|
|
737
|
+
buffer.writeBytes(buf);
|
|
738
|
+
}
|
|
739
|
+
break;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
static decodeProp(type: string, protos: any, buffer: egret.ByteArray): any {
|
|
744
|
+
switch (type) {
|
|
745
|
+
case 'uInt32':
|
|
746
|
+
return this.decodeUInt32(buffer);
|
|
747
|
+
case 'int32':
|
|
748
|
+
case 'sInt32':
|
|
749
|
+
return this.decodeSInt32(buffer);
|
|
750
|
+
case 'float':
|
|
751
|
+
let floats: egret.ByteArray = new egret.ByteArray();
|
|
752
|
+
buffer.readBytes(floats, 0, 4);
|
|
753
|
+
floats.endian = egret.Endian.LITTLE_ENDIAN;
|
|
754
|
+
let float: number = buffer.readFloat();
|
|
755
|
+
return floats.readFloat();
|
|
756
|
+
case 'double':
|
|
757
|
+
let doubles: egret.ByteArray = new egret.ByteArray();
|
|
758
|
+
buffer.readBytes(doubles, 0, 8);
|
|
759
|
+
doubles.endian = egret.Endian.LITTLE_ENDIAN;
|
|
760
|
+
return doubles.readDouble();
|
|
761
|
+
case 'string':
|
|
762
|
+
let length: number = this.decodeUInt32(buffer);
|
|
763
|
+
return buffer.readUTFBytes(length);
|
|
764
|
+
default:
|
|
765
|
+
let proto: any = protos && (protos.__messages[type] || this._servers['message ' + type]);
|
|
766
|
+
if (proto) {
|
|
767
|
+
let len: number = this.decodeUInt32(buffer);
|
|
768
|
+
let buf: egret.ByteArray;
|
|
769
|
+
if (len) {
|
|
770
|
+
buf = new egret.ByteArray();
|
|
771
|
+
buffer.readBytes(buf, 0, len);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
return len ? Protobuf.decodeProtos(proto, buf) : false;
|
|
775
|
+
}
|
|
776
|
+
break;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
static isSimpleType(type: string): boolean {
|
|
781
|
+
return (
|
|
782
|
+
type === 'uInt32' ||
|
|
783
|
+
type === 'sInt32' ||
|
|
784
|
+
type === 'int32' ||
|
|
785
|
+
type === 'uInt64' ||
|
|
786
|
+
type === 'sInt64' ||
|
|
787
|
+
type === 'float' ||
|
|
788
|
+
type === 'double'
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
static encodeArray(array: Array<any>, proto: any, protos: any, buffer: egret.ByteArray): void {
|
|
792
|
+
let isSimpleType = this.isSimpleType;
|
|
793
|
+
if (isSimpleType(proto.type)) {
|
|
794
|
+
buffer.writeBytes(this.encodeTag(proto.type, proto.tag));
|
|
795
|
+
buffer.writeBytes(this.encodeUInt32(array.length));
|
|
796
|
+
let encodeProp = this.encodeProp;
|
|
797
|
+
for (let i: number = 0; i < array.length; i++) {
|
|
798
|
+
encodeProp(array[i], proto.type, protos, buffer);
|
|
799
|
+
}
|
|
800
|
+
} else {
|
|
801
|
+
let encodeTag = this.encodeTag;
|
|
802
|
+
for (let j: number = 0; j < array.length; j++) {
|
|
803
|
+
buffer.writeBytes(encodeTag(proto.type, proto.tag));
|
|
804
|
+
this.encodeProp(array[j], proto.type, protos, buffer);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
static decodeArray(array: Array<any>, type: string, protos: any, buffer: egret.ByteArray): void {
|
|
809
|
+
let isSimpleType = this.isSimpleType;
|
|
810
|
+
|
|
811
|
+
if (isSimpleType(type)) {
|
|
812
|
+
let length: number = this.decodeUInt32(buffer);
|
|
813
|
+
for (let i: number = 0; i < length; i++) {
|
|
814
|
+
array.push(this.decodeProp(type, protos, buffer));
|
|
815
|
+
}
|
|
816
|
+
} else {
|
|
817
|
+
array.push(this.decodeProp(type, protos, buffer));
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
static encodeUInt32(n: number): egret.ByteArray {
|
|
822
|
+
let result: egret.ByteArray = new egret.ByteArray();
|
|
823
|
+
|
|
824
|
+
do {
|
|
825
|
+
let tmp: number = n % 128;
|
|
826
|
+
let next: number = Math.floor(n / 128);
|
|
827
|
+
|
|
828
|
+
if (next !== 0) {
|
|
829
|
+
tmp = tmp + 128;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
result.writeByte(tmp);
|
|
833
|
+
n = next;
|
|
834
|
+
}
|
|
835
|
+
while (n !== 0);
|
|
836
|
+
|
|
837
|
+
return result;
|
|
838
|
+
}
|
|
839
|
+
static decodeUInt32(buffer: egret.ByteArray): number {
|
|
840
|
+
let n: number = 0;
|
|
841
|
+
|
|
842
|
+
for (let i: number = 0; i < buffer.length; i++) {
|
|
843
|
+
let m: number = buffer.readUnsignedByte();
|
|
844
|
+
n = n + ((m & 0x7f) * Math.pow(2, (7 * i)));
|
|
845
|
+
if (m < 128) {
|
|
846
|
+
return n;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
return n;
|
|
850
|
+
}
|
|
851
|
+
static encodeSInt32(n: number): egret.ByteArray {
|
|
852
|
+
n = n < 0 ? (Math.abs(n) * 2 - 1) : n * 2;
|
|
853
|
+
|
|
854
|
+
return this.encodeUInt32(n);
|
|
855
|
+
}
|
|
856
|
+
static decodeSInt32(buffer: egret.ByteArray): number {
|
|
857
|
+
let n: number = this.decodeUInt32(buffer);
|
|
858
|
+
|
|
859
|
+
let flag: number = ((n % 2) === 1) ? -1 : 1;
|
|
860
|
+
|
|
861
|
+
n = ((n % 2 + n) / 2) * flag;
|
|
862
|
+
|
|
863
|
+
return n;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
}
|
|
867
|
+
class Routedic {
|
|
868
|
+
private static _ids: Object = {};
|
|
869
|
+
private static _names: Object = {};
|
|
870
|
+
|
|
871
|
+
static init(dict: any): void {
|
|
872
|
+
this._names = dict || {};
|
|
873
|
+
let _names = this._names;
|
|
874
|
+
let _ids = this._ids;
|
|
875
|
+
for (let name in _names) {
|
|
876
|
+
_ids[_names[name]] = name;
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
static getID(name: string) {
|
|
881
|
+
return this._names[name];
|
|
882
|
+
}
|
|
883
|
+
static getName(id: number) {
|
|
884
|
+
return this._ids[id];
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
interface IMessage {
|
|
889
|
+
/**
|
|
890
|
+
* encode
|
|
891
|
+
* @param id
|
|
892
|
+
* @param route
|
|
893
|
+
* @param msg
|
|
894
|
+
* @return ByteArray
|
|
895
|
+
*/
|
|
896
|
+
encode(id: number, route: string, msg: any): egret.ByteArray;
|
|
897
|
+
|
|
898
|
+
/**
|
|
899
|
+
* decode
|
|
900
|
+
* @param buffer
|
|
901
|
+
* @return Object
|
|
902
|
+
*/
|
|
903
|
+
decode(buffer: egret.ByteArray): any;
|
|
904
|
+
}
|
|
905
|
+
interface IPackage {
|
|
906
|
+
|
|
907
|
+
encode(type: number, body?: egret.ByteArray): egret.ByteArray;
|
|
908
|
+
|
|
909
|
+
decode(buffer: egret.ByteArray): any;
|
|
910
|
+
}
|
|
911
|
+
|