gamerpc 8.0.6 → 8.0.7

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/src/gameConn.js DELETED
@@ -1,705 +0,0 @@
1
- //const {encrypt, decrypt, createHmac} = require('./utils/util');
2
- const {stringify, NotifyType, extendObj, CommStatus, clone, ReturnCodeName, ReturnCode, CommMode, io} = require('./utils/util');
3
- const EventEmitter = require('events').EventEmitter;
4
- const Indicator = require('./utils/Indicator');
5
- // const assert = require('./utils/assert')
6
- // let {sha1, hash160, hash256, verifyData, generateKey, signObj, verifyObj, verifyAddress} = require('./utils/verifyData');
7
- // const Secret = require('./utils/secret')
8
-
9
- /**
10
- * RPC控件
11
- * @note
12
- * 1、根据创建参数,可分别支持WS、Socket、Http三种常用通讯模式,支持Notify、JSONP、Watching等报文通讯模式
13
- * 2、支持LBS重定向功能
14
- * 3、内部封装了一定的断言功能
15
- */
16
- class Remote {
17
- constructor(options) {
18
- this.rpcMode = CommMode.post;
19
- this.loginMode = Indicator.inst();
20
- this.configOri = options; //读取并保存初始配置,不会修改
21
- this.config = clone(this.configOri); //复制一份配置信息,有可能修改
22
- this.notifyHandles = {};
23
- this.userInfo = {};
24
- //事件管理器
25
- this.events = new EventEmitter();
26
- //状态管理器
27
- this.status = Indicator.inst(options.status);
28
-
29
- //两阶段登录时,用户输入验证码时提交此事件
30
- this.events.on('authcode', async code => {
31
- console.log('gameconn: commit authcode', code);
32
- await this.setSign(code).login();
33
- })
34
- }
35
-
36
- /**
37
- * 修改通讯模式
38
- * @param {*} $mode 通讯模式
39
- * @param {*} cb 建立连接时的回调
40
- */
41
- setmode($mode) {
42
- this.rpcMode = $mode;
43
- return this;
44
- }
45
-
46
- /**
47
- * 创建通讯连接组件
48
- * @param {*} ip
49
- * @param {*} port
50
- */
51
- async createSocket(ip, port) {
52
- if(!ip) {
53
- ip = this.config.webserver.host;
54
- }
55
- if(!port) {
56
- port = this.config.webserver.port;
57
- }
58
-
59
- this.close();
60
-
61
- this.socket = io(`${this.config.UrlHead}://${ip}:${port}`, {'force new connection': true});
62
- this.socket.on('notify', ret => {//监听推送消息
63
- if(this.notifyHandles[ret.type]) {
64
- this.notifyHandles[ret.type](ret.info);
65
- }
66
- else if(!!this.notifyHandles['0']){
67
- this.notifyHandles['0'](ret.info);
68
- }
69
- })
70
- .on('disconnect', ()=>{//断线重连
71
- console.log('gameconn: socket disconnected');
72
- this.events.emit('comm', {status: 'disconnect'});
73
- this.socket.needConnect = true;
74
- setTimeout(()=>{
75
- if(!!this.socket.needConnect) {
76
- this.socket.needConnect = false;
77
- this.socket.connect();
78
- }
79
- }, 1500);
80
- }).on('connect', () => { //连接消息
81
- console.log('gameconn: socket connected');
82
- this.events.emit('comm', {status: 'connect'});
83
- }).on('error', () => {
84
- this.events.emit('comm', {status: 'error'});
85
- });
86
-
87
- let self = this;
88
- let prom = new Promise(resolve => {
89
- self.events.on('comm', async msg => {
90
- if(msg.status == 'connect') {
91
- resolve();
92
- }
93
- })
94
- });
95
- return prom;
96
- }
97
-
98
- /**
99
- * 获取OpenId
100
- */
101
- async getOpenId() {
102
- //此处根据实际需要,发起了基于HTTP请求的认证访问,和本身创建时指定的通讯模式无关。
103
- console.log('gameconn: getOpenId');
104
- let msg = await this.getRequest({
105
- port: this.configOri.webserver.authPort,
106
- openkey: this.userInfo.openkey,
107
- }, this.userInfo.domain);
108
-
109
- //客户端从模拟网关取得了签名集
110
- if(!msg) {
111
- return false;
112
- }
113
-
114
- if(!msg.unionid) {
115
- msg.unionid = msg.openid;
116
- }
117
-
118
- this.userInfo.openid = msg.unionid;
119
- this.userInfo.openkey = msg.access_token;
120
-
121
- console.log('gameconn: getOpenId', msg.unionid);
122
- return true;
123
- }
124
-
125
- /**
126
- * 获取签名数据集
127
- */
128
- async getSign() {
129
- console.log('gameconn: getSign');
130
- //此处根据实际需要,发起了基于HTTP请求的认证访问,和本身创建时指定的通讯模式无关。
131
- let router = this.userInfo.openid.split('.')[0]; //openid一般由代表验证模式的前缀,加上代表节点类型的后缀组成, 获取签名接口的路由路径默认等于其前缀
132
- let msg = await this.getRequest({}, router);
133
-
134
- //客户端从模拟网关取得了签名集
135
- if(!msg) {
136
- return false;
137
- }
138
-
139
- this.userInfo.auth = msg;
140
-
141
- console.log('gameconn: getSign', msg);
142
-
143
- return true;
144
- }
145
-
146
- /**
147
- * 设置验证码
148
- * @param {*} code
149
- */
150
- setSign(code) {
151
- if(!!this.userInfo) {
152
- if(this.loginMode.check(CommStatus.reqSign)) {
153
- this.status.set(CommStatus.signCode);
154
- this.userInfo.auth = this.userInfo.auth || {};
155
- this.userInfo.auth.captcha = code;
156
- }
157
- }
158
- return this;
159
- }
160
-
161
- /**
162
- * 登录并获得令牌
163
- */
164
- async getToken() {
165
- if(!this.userInfo
166
- || (this.loginMode.check(CommStatus.reqLb) && !this.status.check(CommStatus.lb))
167
- || (this.loginMode.check(CommStatus.reqSign) && !this.status.check(CommStatus.signCode)
168
- || this.status.check(CommStatus.logined))
169
- ) {
170
- //不满足登录的前置条件或已经登录
171
- return false;
172
- }
173
-
174
- //将签证发送到服务端进行验证
175
- console.log('gameconn: getToken');
176
- let msg = await this.fetching({
177
- 'func': 'login.UserLogin',
178
- "oemInfo": this.userInfo,
179
- });
180
-
181
- if(!!msg) {
182
- console.log('gameconn: getToken', msg.code);
183
- if(msg.code == ReturnCode.Success && !!msg.data) {
184
- if(typeof msg.data == 'object') {
185
- extendObj(this.userInfo, msg.data);
186
- }
187
- this.status.set(CommStatus.logined);
188
- this.events.emit('logined', {code:0, data:{currentAuthority: this.userInfo.currentAuthority}});
189
-
190
- return true;
191
- } else {
192
- this.events.emit('logined', {code: msg.code});
193
- }
194
- } else {
195
- console.log('gameconn: getToken failed');
196
- this.events.emit('logined', {code:-1});
197
- }
198
- return false;
199
- }
200
-
201
- /**
202
- * 清空先前的缓存状态
203
- */
204
- clearCache() {
205
- if(this.userInfo) {
206
- this.userInfo.token = null;
207
- }
208
- }
209
-
210
- /**
211
- * 执行负载均衡流程
212
- * @param {*} ui
213
- */
214
- async setLB(force) {
215
- if(!this.userInfo) {
216
- //尚未设置有效的用户数据,无法执行
217
- return false;
218
- }
219
-
220
- if(!force && this.status.check(CommStatus.lb)) {
221
- //已经执行过LB操作,且非强制执行模式
222
- return true;
223
- }
224
-
225
- this.clearCache();
226
- this.status.init();
227
-
228
- console.log('gameconn: lb');
229
- let msg = await this.locate(this.configOri.webserver.host, this.configOri.webserver.port)
230
- .getRequest({"func": "lb.getServerInfo", "oemInfo":{"domain": this.userInfo.domain, "openid": this.userInfo.openid}});
231
-
232
- if(!!msg && msg.code == ReturnCode.Success) {
233
- console.log('gameconn: lb', msg.data);
234
- this.status.set(CommStatus.lb);
235
- this.locate(msg.data.ip, msg.data.port);
236
- return true;
237
- }
238
-
239
- console.log('gameconn: lb failed');
240
- return false;
241
- }
242
-
243
- /**
244
- * 登录流程
245
- * @param {Object} options
246
- * @param {Boolean} options.force 强制登录
247
- */
248
- async login(options) {
249
- options = options || {};
250
- if(options.force) {
251
- this.clearCache();
252
- this.status.init();
253
- }
254
-
255
- if(options.domain) {
256
- let authmode = options.openid.split('.')[0];
257
- switch(authmode) {
258
- case 'bxs': { //新增一种验证模式
259
- this.setUserInfo({
260
- domain: options.domain, //认证模式
261
- openid: options.openid, //用户证书
262
- openkey: options.openkey, //中间证书,经由Auth服务器转换成 openid 下发给客户端
263
- auth: options.auth, //验证信息
264
- }, CommStatus.reqLb);
265
-
266
- break;
267
- }
268
-
269
- case 'authwx': {
270
- this.setUserInfo({
271
- domain: options.domain, //认证模式
272
- openkey: options.openkey, //中间证书,经由Auth服务器转换成 openid 下发给客户端
273
- }, CommStatus.reqLb | CommStatus.reqOpenId);
274
-
275
- break;
276
- }
277
-
278
- case 'auth2step': {
279
- this.setUserInfo({
280
- domain: options.domain, //验证模式
281
- openid: options.openid, //用户证书
282
- openkey: options.openkey, //用户证书
283
- addrType: options.addrType, //验证方式
284
- address: options.address, //验证地址
285
- }, CommStatus.reqLb | CommStatus.reqSign);
286
-
287
- break;
288
- }
289
-
290
- case 'authpwd': {
291
- this.setUserInfo({
292
- domain: options.domain, //验证模式
293
- openid: options.openid, //用户证书
294
- openkey: options.openkey, //用户密码
295
- }, CommStatus.reqLb);
296
-
297
- break;
298
- }
299
-
300
- default: {
301
- this.setUserInfo({
302
- domain: options.domain || 'official', //验证模式
303
- openid: options.openid, //登录名称
304
- openkey: options.openkey, //登录密码
305
- });
306
- break;
307
- }
308
- }
309
- }
310
-
311
- if(this.status.check(CommStatus.logined)) {
312
- return false;
313
- }
314
-
315
- if(!this.userInfo) {
316
- return false;
317
- }
318
-
319
- //检测执行微信所需要的KeyId转换
320
- if(this.loginMode.check(CommStatus.reqOpenId)) {
321
- if(!this.status.check(CommStatus.OpenId)) {
322
- if(!(await this.getOpenId())) {
323
- throw(new Error('keyId error'));
324
- } else {
325
- this.status.set(CommStatus.OpenId);
326
- }
327
- }
328
- }
329
-
330
- //检测执行负载均衡
331
- if(this.loginMode.check(CommStatus.reqLb)) {
332
- if(!this.status.check(CommStatus.lb)) {
333
- //如果需要负载均衡且尚未执行,执行如下语句
334
- if(!(await this.setLB())) {
335
- //如果负载均衡失败,抛出异常,外围程序负责重新调用
336
- throw(new Error('lb error'));
337
- } else {
338
- this.status.set(CommStatus.lb);
339
- }
340
- }
341
- }
342
-
343
- //检测执行两阶段验证
344
- //两阶段验证模式(例如浏览器直接登录):执行此操作,访问控制器方法 authmode.auth 获取签名对象,并赋值到 userInfo.auth 字段,服务端同时会将关联验证码通过邮件或短信下发
345
- //第三方授权登录模式(例如微信或QQ登录)跳过此步
346
- if(this.loginMode.check(CommStatus.reqSign)) {
347
- if(!this.status.check(CommStatus.sign)) {
348
- //如果需要两阶段验证且尚未执行,执行如下语句
349
- if(!(await this.getSign())) {
350
- //如果负载均衡失败,抛出异常,外围程序负责重新调用
351
- throw(new Error('get sign error'));
352
- } else {
353
- this.status.set(CommStatus.sign);
354
- return true;
355
- }
356
- } else {
357
- return await this.getToken();
358
- }
359
- } else {
360
- return await this.getToken();
361
- }
362
- }
363
-
364
- /**
365
- * 设置用户信息
366
- * 1. 支持局部设定模式
367
- * 2. 每次设置,状态类缓存会被清除,通讯状态被复原
368
- * @param {Object} ui {openid}
369
- * @param {Number} st 登录流程描述符
370
- */
371
- setUserInfo(ui, st) {
372
- this.userInfo = this.userInfo || {};
373
-
374
- this.clearCache();
375
-
376
- //设置登录模式
377
- if(!!st) {
378
- this.loginMode.init(st);
379
- }
380
-
381
- //合并对象数据
382
- extendObj(this.userInfo, ui);
383
-
384
- return this;
385
- }
386
-
387
- /**
388
- * 设置服务端推送报文的监控句柄,支持链式调用
389
- * @param cb 回调
390
- * @param etype
391
- * @returns {Remote}
392
- */
393
- watch(cb, etype = '0') {
394
- this.notifyHandles[etype] = cb;
395
- return this;
396
- }
397
- /**
398
- * 移除监控句柄
399
- * @param {*} etype
400
- */
401
- unWatch(etype) {
402
- if(!!this.notifyHandles[etype]) {
403
- delete this.notifyHandles[etype];
404
- }
405
- return this;
406
- }
407
-
408
- /**
409
- * 判断返回值是否成功
410
- * @param msg 网络报文
411
- * @param out 强制打印日志
412
- * @returns {*}
413
- */
414
- isSuccess(msg, out=false) {
415
- if(!msg) {
416
- return false;
417
- }
418
-
419
- msg.msg = ReturnCodeName[msg.code];
420
-
421
- if((msg.code != ReturnCode.Success) || out){
422
- this.log(msg);
423
- }
424
-
425
- return msg.code == ReturnCode.Success;
426
- }
427
-
428
- /**
429
- * 直接打印各种对象
430
- * @param val
431
- */
432
- log(val){
433
- if(!val){
434
- console.log('undefined');
435
- return;
436
- }
437
-
438
- if(!!val.code){
439
- val.msg = ReturnCodeName[val.code];
440
- }
441
-
442
- switch(typeof val){
443
- case 'number':
444
- case 'string':
445
- case 'boolean':
446
- console.log(val);
447
- break;
448
- case 'function':
449
- console.log(val());
450
- break;
451
- case 'undefined':
452
- console.log('err: undefined');
453
- break;
454
- default:
455
- console.log(JSON.stringify(val));
456
- break;
457
- }
458
- }
459
-
460
- get newone(){
461
- return new Remote(this.configOri).setmode(this.rpcMode);
462
- }
463
-
464
- /**
465
- * 获取新的远程对象
466
- * @returns {Remote}
467
- */
468
- get new(){
469
- return new Remote(this.configOri).setmode(this.rpcMode);
470
- }
471
-
472
- /**
473
- * 等待指定时长
474
- * @param {Number} time 等待时长(毫秒)
475
- */
476
- async wait (time) {
477
- await (async (time) => {return new Promise(resolve => {setTimeout(resolve, time);});})(time);
478
- }
479
-
480
- /**
481
- * 为了提供node下的兼容性而添加的属性设定函数
482
- * @param {*} fn
483
- */
484
- setFetch(fn) {
485
- this.fetch = fn;
486
- return this;
487
- }
488
-
489
- /**
490
- * 向服务端提交请求,默认JSONP模式
491
- * @param params 命令参数,JSON对象
492
- * .command 命令名称,格式: obj.func, 可以缩写为 func,此时obj为默认值'index',例如 index.setNewbie 等价于 setNewbie
493
- * .url 附加url地址
494
- * @param callback 回调函数
495
- * @returns {*}
496
- */
497
- async fetching(params) {
498
- this.parseParams(params);
499
-
500
- if(this.loginMode.check(CommStatus.reqLb) && !this.status.check(CommStatus.lb)) {
501
- await this.setLB();
502
- }
503
-
504
- switch(this.rpcMode) {
505
- case CommMode.ws:
506
- if(!this.socket) {
507
- await this.createSocket(this.config.webserver.host, this.config.webserver.port);
508
- }
509
- return new Promise((resolve, reject) => {
510
- this.socket.emit('req', params, msg => {
511
- resolve(msg);
512
- });
513
- });
514
-
515
- case CommMode.get:
516
- return this.getRequest(params);
517
-
518
- case CommMode.post:
519
- return this.postRequest(params);
520
- }
521
-
522
- return Promise.reject();
523
- }
524
-
525
- /**
526
- * 设定远程服务器地址
527
- * @param ip
528
- * @param port
529
- * @returns {Remote}
530
- */
531
- locate(ip, port){
532
- this.config.webserver.host = ip;
533
- this.config.webserver.port = port;
534
-
535
- return this;
536
- }
537
-
538
- /**
539
- * 关闭长连接
540
- */
541
- close() {
542
- if(this.socket){
543
- this.socket.removeAllListeners();
544
- this.socket.disconnect();
545
- this.socket = null;
546
- }
547
-
548
- return this;
549
- }
550
-
551
- /**
552
- * 彻底清除连接器历史数据,包括通讯状态、运行数据缓存,只保留最原始的配置信息
553
- */
554
- init() {
555
- this.close();
556
-
557
- this.config = clone(this.configOri); //复制一份配置信息,有可能修改
558
- this.userInfo = {};
559
- this.status.init();
560
- this.loginMode.init();
561
-
562
- return this;
563
- }
564
-
565
- /**
566
- * 参数调整
567
- * @param params
568
- */
569
- parseParams(params) {
570
- params.func = !!params.func ? params.func : 'index.login';
571
- //填充自动登录参数
572
- let arr = params.func.split('.');
573
- if(arr.length > 1) {
574
- params.control = arr[0];
575
- params.func = arr[1];
576
- } else {
577
- params.func = arr[0];
578
- }
579
-
580
- params.oemInfo = {
581
- domain: this.userInfo.domain,
582
- openid: this.userInfo.openid,
583
- };
584
-
585
- if(this.userInfo.openkey) {
586
- params.oemInfo.openkey = this.userInfo.openkey;
587
- }
588
- if(this.userInfo.token) {
589
- params.oemInfo.token = this.userInfo.token;
590
- }
591
- if(this.userInfo.addrType) {
592
- params.oemInfo.addrType = this.userInfo.addrType;
593
- }
594
- if(this.userInfo.address) {
595
- params.oemInfo.address = this.userInfo.address;
596
- }
597
- if(this.userInfo.auth) {
598
- params.oemInfo.auth = this.userInfo.auth;
599
- }
600
- }
601
-
602
- /**
603
- * 以 GET 方式访问远程API
604
- * @param {*} url 远程地址
605
- */
606
- async get(url) {
607
- const newOptions = { json: true, method: 'GET', mode: 'cors', };
608
-
609
- newOptions.headers = {
610
- Accept: 'application/json',
611
- 'Content-Type': 'application/json; charset=utf-8',
612
- };
613
-
614
- if(this.fetch) {
615
- let ret = await this.fetch(url, newOptions);
616
- return await ret.json();
617
- }
618
- else {
619
- let ret = await fetch(url, newOptions);
620
- return await ret.json();
621
- }
622
- }
623
-
624
- /**
625
- * 以 POST 方式访问远程API
626
- * @param {*} url 远程地址
627
- * @param {*} options body
628
- */
629
- async post(url, options) {
630
- const newOptions = { json: true, method: 'POST', mode: 'cors', body: JSON.stringify(options) };
631
-
632
- newOptions.headers = {
633
- Accept: 'application/json',
634
- 'Content-Type': 'application/json; charset=utf-8',
635
- };
636
-
637
- try {
638
- if(this.fetch) {
639
- let ret = await this.fetch(url, newOptions);
640
- return await ret.json();
641
- }
642
- else {
643
- let ret = await fetch(url, newOptions);
644
- return await ret.json();
645
- }
646
- }
647
- catch(e) {
648
- console.error(e);
649
- }
650
- }
651
-
652
- /**
653
- * (内部函数)发起基于Http协议的RPC请求
654
- * @param params
655
- */
656
- async getRequest(params, authControl) {
657
- this.parseParams(params);
658
-
659
- let port = !!params.port ? params.port : this.config.webserver.port;
660
- let url = !!authControl ? `${this.config.UrlHead}://${this.config.webserver.host}:${port}/${authControl}` : `${this.config.UrlHead}://${this.config.webserver.host}:${port}/index.html`;
661
- url += "?" + Object.keys(params).reduce((ret, next)=>{
662
- if(ret != '') {
663
- ret += '&';
664
- }
665
- //增加了字段编译,避免特殊字符如汉字对URL拼接造成干扰
666
- return ret + next + "=" + ((typeof params[next]) == "object" ? encodeURIComponent(JSON.stringify(params[next])) : encodeURIComponent(params[next]));
667
- }, '');
668
-
669
- return this.get(url);
670
- }
671
-
672
- /**
673
- * (内部函数)发起基于Http协议的RPC请求
674
- * @param params
675
- */
676
- async postRequest(params, authControl) {
677
- this.parseParams(params);
678
-
679
- let port = !!params.port ? params.port : this.config.webserver.port;
680
- let url = !!authControl ? `${this.config.UrlHead}://${this.config.webserver.host}:${port}/${authControl}` : `${this.config.UrlHead}://${this.config.webserver.host}:${port}/index.html`;
681
-
682
- return this.post(url, params);
683
- }
684
- }
685
-
686
- Remote.prototype.CommMode = CommMode;
687
- // Remote.prototype.createHmac = createHmac;
688
- // Remote.prototype.assert = assert;
689
- Remote.prototype.stringify = stringify;
690
- // Remote.prototype.encrypt = encrypt;
691
- // Remote.prototype.decrypt = decrypt;
692
- // Remote.prototype.verifyData = verifyData;
693
- // Remote.prototype.generateKey = generateKey;
694
- // Remote.prototype.signObj = signObj;
695
- // Remote.prototype.verifyObj = verifyObj;
696
- // Remote.prototype.verifyAddress = verifyAddress;
697
- Remote.prototype.CommStatus = CommStatus;
698
- Remote.prototype.ReturnCode = ReturnCode;
699
- Remote.prototype.NotifyType = NotifyType;
700
- // Remote.prototype.Secret = Secret;
701
- // Remote.prototype.hash256 = hash256;
702
- // Remote.prototype.hash160 = hash160;
703
- // Remote.prototype.sha1 = sha1;
704
-
705
- module.exports = Remote;