index.ts 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. import { checkTokenAction, stopCheckToken } from '@/services/bus/token';
  2. import { NeedClearSourceDataType, NoClearSourceDataType } from '@/services/dataCenter/interface';
  3. import { funCode } from '@/services/funcode/index';
  4. import { serviceURL } from '@/services/request/index';
  5. import timerUtil from '@/utils/timer/timerUtil';
  6. import { Callback, MTP2WebSocket, ReconnectChangeState } from '@/utils/websocket/index';
  7. import { Package40, Package50 } from '@/utils/websocket/package';
  8. import eventBus from '../utils/eventBus';
  9. import DataCenter from './dataCenter/index';
  10. import { noticeParseRsp } from './socket/protobuf/buildReq';
  11. /** 行情和交易长链 */
  12. interface LongLink {
  13. /** 行情长链 */
  14. quote: MTP2WebSocket<Package40>;
  15. /** 交易长链 */
  16. trade: MTP2WebSocket<Package50>;
  17. }
  18. type LontLinkName = 'quote' | 'trade';
  19. /** 全局数据连接生命周期控制类 */
  20. export default new (class LifeCycleCtr {
  21. /** 数据中心 */
  22. private dataCenter = new DataCenter();
  23. /** 长链接管理 */
  24. public Socket: LongLink = {
  25. quote: new MTP2WebSocket<Package40>(0),
  26. trade: new MTP2WebSocket<Package50>(1),
  27. };
  28. constructor() { }
  29. /** 数据中心初始化 */
  30. initDataCenter(): void { }
  31. /**
  32. * 从数据中心获取普通数据
  33. * @param key needClearSourceDataType | noClearSourceDataType
  34. */
  35. get(key: keyof (NeedClearSourceDataType & NoClearSourceDataType)) {
  36. return this.dataCenter.getOneOf(key).value;
  37. }
  38. /**
  39. * 从数据中心获取数据响应式数据
  40. * @param key needClearSourceDataType | noClearSourceDataType
  41. */
  42. getRef(key: keyof (NeedClearSourceDataType & NoClearSourceDataType)) {
  43. return this.dataCenter.getOneOf(key);
  44. }
  45. /**
  46. * 从数据中心获取所有数据
  47. * @param key needClearSourceDataType | noClearSourceDataType
  48. */
  49. reset() {
  50. this.dataCenter.reset();
  51. }
  52. /**
  53. * 数据中心存入数据
  54. * @param key needClearSourceDataType | noClearSourceDataType
  55. * @param value any
  56. */
  57. set(key: keyof (NeedClearSourceDataType & NoClearSourceDataType), value: any) {
  58. return this.dataCenter.setOneOf(key, value);
  59. }
  60. /** 主动连接行情 */
  61. connectQuote(): Promise<string> {
  62. if (this.Socket['quote'].connState === 0) {
  63. return this.connectServer('quote', serviceURL.quoteUrl).then(() => {
  64. // 开始发送心跳
  65. this.startBeatTime('quote');
  66. return 'ok';
  67. });
  68. } else {
  69. return Promise.resolve('已连接quote');
  70. }
  71. }
  72. /** 主动连接交易 */
  73. connectTrading(): Promise<string> {
  74. return this.connectServer('trade', serviceURL.tradeUrl).then(() => {
  75. // 开始发送心跳
  76. this.startBeatTime('trade');
  77. return 'ok';
  78. });
  79. // if (this.Socket['trade'].connState === 0) {
  80. // return this.connectServer('trade', serviceURL.tradeUrl);
  81. // } else {
  82. // return Promise.resolve('已连接trading');
  83. // }
  84. }
  85. /** 连接服务器 */
  86. connectServer(socket: LontLinkName, ws: string): Promise<string> {
  87. return new Promise((resolve, reject) => {
  88. this.Socket[socket].conn(ws);
  89. this.Socket[socket].onConnected = () => {
  90. console.info(`${socket},${ws},建立链接成功!`);
  91. resolve('ok');
  92. };
  93. this.Socket[socket].onClosed = () => {
  94. // 清空心跳定时器
  95. this.Socket[socket].stopBeatTimer(socket);
  96. console.error(`${socket},${ws},断开链接了!`);
  97. };
  98. this.Socket[socket].onError = (obj: MTP2WebSocket<Package40> | MTP2WebSocket<Package50>, err: Error) => {
  99. console.error(`${socket},${ws},发送错误:${err.message}`);
  100. reject(err);
  101. };
  102. if (socket === 'quote') this.quoteRelevant(this.Socket[socket]);
  103. if (socket === 'trade') this.tradingRelevant(this.Socket[socket]);
  104. });
  105. }
  106. /** 发送心跳 */
  107. startBeatTime(socket: LontLinkName): void {
  108. this.Socket[socket].startBeatTime(socket);
  109. this.Socket[socket].canReconnect = true;
  110. }
  111. /** 向交易服务器发送请求 */
  112. sendTradingServer(p: Package50, rsp?: number, callback?: Callback): void {
  113. this.Socket['trade'].send(p, rsp, callback);
  114. }
  115. /** 向行情服务器发送请求 */
  116. sendQuoteServer(p: Package40, rsp?: number, callback?: Callback): void {
  117. this.Socket['quote'].send(p, rsp, callback);
  118. }
  119. /** 主动关闭行情服务 */
  120. closeQuote() {
  121. this.Socket['quote'].close();
  122. }
  123. /** 主动关闭长链接 */
  124. closeServer(): void {
  125. this.Socket['trade'].close();
  126. this.dataCenter.reset();
  127. // sessionStorage.clear();
  128. // localStorageUtil.removeItem('loginData');
  129. timerUtil.clearAll();
  130. }
  131. /** 处理行情相关信息 */
  132. quoteRelevant(socket: MTP2WebSocket<Package40>) {
  133. // 推送信息
  134. socket.onReceivePush = (obj, msg: Package40) => {
  135. eventBus.$emit('quoteReceiveNtf', msg.content);
  136. };
  137. // 重连成功回调
  138. socket.onReconnectChangeState = (obj: MTP2WebSocket<Package40>, state) => {
  139. switch (state) {
  140. /** 开始重连 */
  141. case ReconnectChangeState.BeginReconnect:
  142. // 停止 token 校验
  143. // stopCheckToken()
  144. console.log(obj.host, '开始尝试重连服务端');
  145. break;
  146. /** 尝试重连失败,将在下一个周期后再次尝试重连 */
  147. case ReconnectChangeState.FailAndWaitPeriod:
  148. console.log(obj.host, '尝试重连失败,将在下一个周期后再次尝试重连');
  149. break;
  150. /** 重连成功,将进行业务操作 */
  151. case ReconnectChangeState.ReconnectSuccessed:
  152. console.log(obj.host, '重连成功,可开始进行业务操作');
  153. // 通知上层 重新订阅商品
  154. eventBus.$emit('quoteReconnectSucess', true);
  155. break;
  156. /** 重连成功后业务操作失败并将再次重试,由业务模块发起 */
  157. case ReconnectChangeState.LoginFail:
  158. break;
  159. /** 重连成功后业务操作成功(包括交易服务的账户登录状态更新或行情服务的行情订阅等 */
  160. case ReconnectChangeState.Logined:
  161. // 重连成功继续校验token
  162. // checkTokenAction();
  163. console.log(obj.host, '重连成功后业务操作成功(包括交易服务的账户登录状态更新或行情服务的行情订阅等');
  164. // 行情链路重连成功后,需要通知上层 重新订阅商品
  165. break;
  166. }
  167. };
  168. }
  169. /** 处理交易相关信息 */
  170. tradingRelevant(socket: MTP2WebSocket<Package50>) {
  171. // eslint-disable-next-line @typescript-eslint/no-this-alias
  172. const _this = this
  173. // 推送信息
  174. socket.onReceivePush = (_self, msg) => {
  175. switch (msg.funCode) {
  176. case funCode.CustOfflineNtf:
  177. //接收到账户离线通知
  178. eventBus.$emit('custOfflineNtf', noticeParseRsp(msg, 'CustOfflineNtf'));
  179. break;
  180. case funCode.LogoutRsp:
  181. // 接收到用户登出应答
  182. eventBus.$emit('userLogout', noticeParseRsp(msg, 'LogoutRsp'));
  183. break;
  184. case funCode.PosChangedNtf:
  185. //接收到头寸变化通知!
  186. eventBus.$emit('posChangedNtf', noticeParseRsp(msg, 'PosChangedNtf'));
  187. break;
  188. case funCode.MoneyChangedNtf:
  189. // 接收到资金变化通知
  190. eventBus.$emit('moneyChangedNtf', noticeParseRsp(msg, 'MoneyChangedNtf'));
  191. break;
  192. case funCode.OrderCanceledNtf:
  193. // 接收到委托单撤单通知
  194. eventBus.$emit('orderCanceledNtf', noticeParseRsp(msg, 'OrderCanceledNtf'));
  195. break;
  196. default:
  197. msg.funCode !== 0 && console.warn({ msg: '接收到通知:' + msg.funCode });
  198. break;
  199. }
  200. };
  201. // 重连成功回调
  202. socket.onReconnectChangeState = (obj: MTP2WebSocket<Package50>, state) => {
  203. switch (state) {
  204. /** 开始重连 */
  205. case ReconnectChangeState.BeginReconnect:
  206. // 停止 token 校验
  207. stopCheckToken()
  208. console.log(obj.host, '开始尝试重连服务端');
  209. break;
  210. /** 尝试重连失败,将在下一个周期后再次尝试重连 */
  211. case ReconnectChangeState.FailAndWaitPeriod:
  212. console.log(obj.host, '尝试重连失败,将在下一个周期后再次尝试重连');
  213. break;
  214. /** 重连成功,将进行业务操作 */
  215. case ReconnectChangeState.ReconnectSuccessed:
  216. //重新发起心跳
  217. _this.startBeatTime('trade');
  218. // 重新启动定时 token 校验
  219. checkTokenAction()
  220. console.log(obj.host, '重连成功,将进行业务操作');
  221. break;
  222. /** 重连成功后业务操作失败并将再次重试,由业务模块发起 */
  223. case ReconnectChangeState.LoginFail:
  224. break;
  225. /** 重连成功后业务操作成功(包括交易服务的账户登录状态更新或行情服务的行情订阅等 */
  226. case ReconnectChangeState.Logined:
  227. break;
  228. }
  229. };
  230. }
  231. })();