TsrpcNet.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /**
  2. * tsrpc连接管理
  3. */
  4. import { HttpClient as HttpClient_Browser, WsClient as WsClient_Browser } from 'tsrpc-browser';
  5. import { HttpClient as HttpClient_Miniapp, WsClient as WsClient_Miniapp } from 'tsrpc-miniapp';
  6. import { serviceProto as ServiceProtoRoom, ServiceType, ServiceType as ServiceTypeRoom } from "../shared/protocols/ServiceProtoRoom";
  7. import { GameServerConfig } from './GameServerConfig';
  8. import { ShareConfig } from './ShareConfig';
  9. import { Security } from './Security';
  10. import { BaseResponse } from './base';
  11. /** TSRPC网络模块 */
  12. export class TsrpcNet {
  13. /** 连接房间服务器 Websocket 客户端 */
  14. wscRoom: WsClient_Browser<ServiceTypeRoom> = null!;
  15. private static instance: TsrpcNet;
  16. static getInstance(): TsrpcNet {
  17. if (this.instance == null) {
  18. this.instance = new TsrpcNet();
  19. //@ts-ignore
  20. window.TsrpcNet = this;
  21. }
  22. return this.instance;
  23. }
  24. constructor() {
  25. }
  26. /**
  27. * 创建连接房间服务器 Websocket 客户端
  28. * @param serverUrl 服务器地址
  29. * @returns WsClient
  30. */
  31. createWscRoom(serverUrl: string) {
  32. // 创建客户端与房间服务器的 WebSocket 连接
  33. serverUrl = serverUrl.replace(/[\u0000\x00]/g, "");
  34. this.wscRoom = new (cc.sys.platform == cc.sys.WECHAT_GAME ? WsClient_Miniapp : WsClient_Browser)(ServiceProtoRoom, {
  35. // server: serverUrl + "?" + Date.now(),
  36. server: serverUrl,
  37. heartbeat: {
  38. interval: GameServerConfig.heartbeat_interval,
  39. timeout: GameServerConfig.heartbeat_timeout
  40. },
  41. json: ShareConfig.json,
  42. // logger: console,
  43. logMsg: true,
  44. });
  45. this.flowClientApi(this.wscRoom);
  46. this.flowAuth(this.wscRoom);
  47. return this.wscRoom;
  48. }
  49. /** HTTP 客户端协议数据加密、解密 */
  50. private flowClientApi(hc: any) {
  51. if (!ShareConfig.security) return;
  52. hc.flows.preSendDataFlow.push(v => {
  53. if (v.data instanceof Uint8Array) {
  54. v.data = Security.encrypt(v.data);
  55. }
  56. return v;
  57. });
  58. // 在处理接收到的数据之前,通常要进行加密/解密
  59. hc.flows.preRecvDataFlow.push(v => {
  60. if (v.data instanceof Uint8Array) {
  61. v.data = Security.decrypt(v.data);
  62. }
  63. return v;
  64. });
  65. }
  66. /** 帐号登录令牌验证是否逻辑(帐号中加入登录令牌,服务器通过令牌解析玩家数据,如果存在就是已登录) */
  67. private flowAuth(client: any) { // HttpClient WsClient
  68. // 执行 callApi 之前协议中插入登录令牌
  69. client.flows.preCallApiFlow.push(v => {
  70. // 请求前插入登录令牌
  71. let ssoToken = cc.sys.localStorage.getItem('SSO_TOKEN');
  72. if (ssoToken) {
  73. v.req.__ssoToken = ssoToken;
  74. }
  75. return v;
  76. })
  77. // 将 callApi 的结果返回给调用方之后将登录令牌存到本地(收到协议时将登录令牌存到本地)
  78. client.flows.postApiReturnFlow.push(v => {
  79. if (v.return.isSucc) {
  80. let res = v.return.res as BaseResponse;
  81. // 请求成功后刷新登录令牌
  82. if (res.__ssoToken !== undefined) {
  83. cc.sys.localStorage.setItem('SSO_TOKEN', res.__ssoToken);
  84. }
  85. }
  86. // 登录令牌过期时删除客户端登录令牌(可跳转到登录界面)
  87. else if (v.return.err.code === 'NEED_LOGIN') {
  88. cc.sys.localStorage.setItem('SSO_TOKEN', '');
  89. }
  90. return v;
  91. });
  92. }
  93. /** http请求api */
  94. public async callApi<T extends string & keyof ServiceType['api']>(apiName: T, req: ServiceType['api'][T]['req']) {
  95. let ret = await this.wscRoom.callApi('RoomJoin', req);
  96. return ret;
  97. }
  98. /** ws发送消息 */
  99. public sendMsg<T extends string & keyof ServiceType['msg']>(msgName: T, msg: ServiceType['msg'][T]) {
  100. this.wscRoom.sendMsg(msgName, msg);
  101. }
  102. /** 监听消息 */
  103. public listenMsg<T extends keyof ServiceType['msg']>(msgName: T | RegExp, callback: Function) {
  104. this.wscRoom.listenMsg(msgName, v => {
  105. callback(v);
  106. });
  107. }
  108. }