index.js 67 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524
  1. /*!
  2. * TSRPC Base Client v2.1.15
  3. * -----------------------------------------
  4. * Copyright (c) Kingworks Corporation.
  5. * MIT License
  6. * https://github.com/k8w/tsrpc-base-client
  7. */
  8. 'use strict';
  9. Object.defineProperty(exports, '__esModule', { value: true });
  10. require('k8w-extend-native');
  11. var tslib = require('tslib');
  12. var tsbuffer = require('tsbuffer');
  13. var tsrpcProto = require('tsrpc-proto');
  14. var tsbufferSchema = require('tsbuffer-schema');
  15. /**
  16. * An auto-increment counter
  17. */
  18. var Counter = /** @class */ (function () {
  19. function Counter(min, max) {
  20. if (min === void 0) { min = 1; }
  21. if (max === void 0) { max = Number.MAX_SAFE_INTEGER; }
  22. this._min = min;
  23. this._max = max;
  24. this._last = max;
  25. }
  26. /**
  27. * Reset the counter, makes `getNext()` restart from `0`
  28. */
  29. Counter.prototype.reset = function () {
  30. this._last = this._max;
  31. };
  32. /**
  33. * Get next counter value, and auto increment `1`
  34. * @param notInc - Just get the next possible value, not actually increasing the sequence
  35. */
  36. Counter.prototype.getNext = function (notInc) {
  37. return this._last >= this._max ? (this._last = this._min) : (notInc ? this._last : ++this._last);
  38. };
  39. Object.defineProperty(Counter.prototype, "last", {
  40. /**
  41. * Last return of `getNext()`
  42. */
  43. get: function () {
  44. return this._last;
  45. },
  46. enumerable: false,
  47. configurable: true
  48. });
  49. return Counter;
  50. }());
  51. /**
  52. * A `Flow` is consists of many `FlowNode`, which is function with the same input and output (like pipeline).
  53. *
  54. * @remarks
  55. * `Flow` is like a hook or event, executed at a specific time.
  56. * The difference to event is it can be used to **interrupt** an action, by return `undefined` or `null` in a node.
  57. */
  58. var Flow = /** @class */ (function () {
  59. function Flow() {
  60. /**
  61. * All node functions, if you want to adjust the sort you can modify this.
  62. */
  63. this.nodes = [];
  64. /**
  65. * Event when error throwed from a `FlowNode` function.
  66. * By default, it does nothing except print a `Uncaught FlowError` error log.
  67. * @param e
  68. * @param last
  69. * @param input
  70. * @param logger
  71. */
  72. this.onError = function (e, last, input, logger) {
  73. logger === null || logger === void 0 ? void 0 : logger.error('Uncaught FlowError:', e);
  74. };
  75. }
  76. /**
  77. * Execute all node function one by one, the previous output is the next input,
  78. * until the last output would be return to the caller.
  79. *
  80. * @remarks
  81. * If any node function return `null | undefined`, or throws an error,
  82. * the latter node functions would not be executed.
  83. * And it would return `null | undefined` immediately to the caller,
  84. * which tell the caller it means a interruption,
  85. * to let the caller stop latter behaviours.
  86. *
  87. * @param input The input of the first `FlowNode`
  88. * @param logger Logger to print log, `undefined` means to hide all log.
  89. * @returns
  90. */
  91. Flow.prototype.exec = function (input, logger) {
  92. return tslib.__awaiter(this, void 0, void 0, function () {
  93. var res, i, e_1;
  94. return tslib.__generator(this, function (_a) {
  95. switch (_a.label) {
  96. case 0:
  97. res = input;
  98. i = 0;
  99. _a.label = 1;
  100. case 1:
  101. if (!(i < this.nodes.length)) return [3 /*break*/, 7];
  102. _a.label = 2;
  103. case 2:
  104. _a.trys.push([2, 4, , 5]);
  105. return [4 /*yield*/, this.nodes[i](res)];
  106. case 3:
  107. res = _a.sent();
  108. return [3 /*break*/, 5];
  109. case 4:
  110. e_1 = _a.sent();
  111. this.onError(e_1, res, input, logger);
  112. return [2 /*return*/, undefined];
  113. case 5:
  114. // Return 非true 表示不继续后续流程 立即中止
  115. if (res === null || res === undefined) {
  116. return [2 /*return*/, res];
  117. }
  118. _a.label = 6;
  119. case 6:
  120. ++i;
  121. return [3 /*break*/, 1];
  122. case 7: return [2 /*return*/, res];
  123. }
  124. });
  125. });
  126. };
  127. /**
  128. * Append a node function to the last
  129. * @param node
  130. * @returns
  131. */
  132. Flow.prototype.push = function (node) {
  133. this.nodes.push(node);
  134. return node;
  135. };
  136. /**
  137. * Remove a node function
  138. * @param node
  139. * @returns
  140. */
  141. Flow.prototype.remove = function (node) {
  142. return this.nodes.remove(function (v) { return v === node; });
  143. };
  144. return Flow;
  145. }());
  146. function getCustomObjectIdTypes(classObjectId) {
  147. var output = {};
  148. // string
  149. if (classObjectId === String) {
  150. output['?mongodb/ObjectId'] = {
  151. type: tsbufferSchema.SchemaType.Custom,
  152. validate: function (value) {
  153. if (typeof value !== 'string') {
  154. return { isSucc: false, errMsg: "Expected type to be `string`, actually `".concat(typeof value, "`.") };
  155. }
  156. if (!/^[0-9a-fA-F]{24}$/.test(value)) {
  157. return { isSucc: false, errMsg: 'ObjectId must be a string of 24 hex characters' };
  158. }
  159. return { isSucc: true };
  160. },
  161. encode: function (value) {
  162. return new Uint8Array(Array.from({ length: 12 }, function (_, i) { return Number.parseInt('0x' + value.substr(i * 2, 2)); }));
  163. },
  164. decode: function (buf) {
  165. return Array.from(buf, function (v) {
  166. var str = v.toString(16);
  167. if (str.length === 1) {
  168. str = '0' + str;
  169. }
  170. return str;
  171. }).join('');
  172. }
  173. };
  174. }
  175. // ObjectId
  176. else {
  177. output['?mongodb/ObjectId'] = {
  178. type: tsbufferSchema.SchemaType.Custom,
  179. validate: function (value) { return (value instanceof classObjectId) ?
  180. { isSucc: true } :
  181. { isSucc: false, errMsg: "Expected to be instance of `ObjectId`, actually not." }; },
  182. encode: function (value) { return new Uint8Array(value.id); },
  183. decode: function (buf) { return new classObjectId(buf); },
  184. decodeJSON: function (json) { return new classObjectId(json); }
  185. };
  186. }
  187. output['?mongodb/ObjectID'] = output['?mongodb/ObjectId'];
  188. output['?bson/ObjectId'] = output['?mongodb/ObjectId'];
  189. output['?bson/ObjectID'] = output['?mongodb/ObjectId'];
  190. return output;
  191. }
  192. /**
  193. * A manager for TSRPC receiving messages
  194. */
  195. var MsgHandlerManager = /** @class */ (function () {
  196. function MsgHandlerManager() {
  197. this._handlers = {};
  198. }
  199. /**
  200. * Execute all handlers parallelly
  201. * @returns handlers count
  202. */
  203. MsgHandlerManager.prototype.forEachHandler = function (msgName, logger) {
  204. var args = [];
  205. for (var _i = 2; _i < arguments.length; _i++) {
  206. args[_i - 2] = arguments[_i];
  207. }
  208. var handlers = this._handlers[msgName];
  209. if (!handlers) {
  210. return [];
  211. }
  212. var output = [];
  213. for (var _a = 0, handlers_1 = handlers; _a < handlers_1.length; _a++) {
  214. var handler = handlers_1[_a];
  215. try {
  216. output.push(handler.apply(void 0, args));
  217. }
  218. catch (e) {
  219. logger === null || logger === void 0 ? void 0 : logger.error('[MsgHandlerError]', e);
  220. }
  221. }
  222. return output;
  223. };
  224. /**
  225. * Add message handler, duplicate handlers to the same `msgName` would be ignored.
  226. * @param msgName
  227. * @param handler
  228. * @returns
  229. */
  230. MsgHandlerManager.prototype.addHandler = function (msgName, handler) {
  231. var handlers = this._handlers[msgName];
  232. // 初始化Handlers
  233. if (!handlers) {
  234. handlers = this._handlers[msgName] = [];
  235. }
  236. // 防止重复监听
  237. else if (handlers.some(function (v) { return v === handler; })) {
  238. return;
  239. }
  240. handlers.push(handler);
  241. };
  242. /**
  243. * Remove handler from the specific `msgName`
  244. * @param msgName
  245. * @param handler
  246. * @returns
  247. */
  248. MsgHandlerManager.prototype.removeHandler = function (msgName, handler) {
  249. var handlers = this._handlers[msgName];
  250. if (!handlers) {
  251. return;
  252. }
  253. handlers.removeOne(function (v) { return v === handler; });
  254. };
  255. /**
  256. * Remove all handlers for the specific `msgName`
  257. * @param msgName
  258. */
  259. MsgHandlerManager.prototype.removeAllHandlers = function (msgName) {
  260. this._handlers[msgName] = undefined;
  261. };
  262. return MsgHandlerManager;
  263. }());
  264. /** A utility for generate `ServiceMap` */
  265. var ServiceMapUtil = /** @class */ (function () {
  266. function ServiceMapUtil() {
  267. }
  268. ServiceMapUtil.getServiceMap = function (proto) {
  269. var map = {
  270. id2Service: {},
  271. apiName2Service: {},
  272. msgName2Service: {}
  273. };
  274. for (var _i = 0, _a = proto.services; _i < _a.length; _i++) {
  275. var v = _a[_i];
  276. var match = v.name.match(/(.+\/)?([^\/]+)$/);
  277. var path = match[1] || '';
  278. var name_1 = match[2];
  279. if (v.type === 'api') {
  280. var svc = tslib.__assign(tslib.__assign({}, v), { reqSchemaId: "".concat(path, "Ptl").concat(name_1, "/Req").concat(name_1), resSchemaId: "".concat(path, "Ptl").concat(name_1, "/Res").concat(name_1) });
  281. map.apiName2Service[v.name] = svc;
  282. map.id2Service[v.id] = svc;
  283. }
  284. else {
  285. var svc = tslib.__assign(tslib.__assign({}, v), { msgSchemaId: "".concat(path, "Msg").concat(name_1, "/Msg").concat(name_1) });
  286. map.msgName2Service[v.name] = svc;
  287. map.id2Service[v.id] = svc;
  288. }
  289. }
  290. return map;
  291. };
  292. return ServiceMapUtil;
  293. }());
  294. var TransportDataUtil = /** @class */ (function () {
  295. function TransportDataUtil() {
  296. }
  297. Object.defineProperty(TransportDataUtil, "tsbuffer", {
  298. get: function () {
  299. if (!this._tsbuffer) {
  300. this._tsbuffer = new tsbuffer.TSBuffer(tsrpcProto.TransportDataProto);
  301. }
  302. return this._tsbuffer;
  303. },
  304. enumerable: false,
  305. configurable: true
  306. });
  307. TransportDataUtil.encodeClientMsg = function (tsbuffer, service, msg, type, connType) {
  308. if (type === 'buffer') {
  309. var op = tsbuffer.encode(msg, service.msgSchemaId);
  310. if (!op.isSucc) {
  311. return op;
  312. }
  313. var serverInputData = {
  314. serviceId: service.id,
  315. buffer: op.buf
  316. };
  317. var opOut = this.tsbuffer.encode(serverInputData, 'ServerInputData');
  318. return opOut.isSucc ? { isSucc: true, output: opOut.buf } : { isSucc: false, errMsg: opOut.errMsg };
  319. }
  320. else {
  321. var op = tsbuffer.encodeJSON(msg, service.msgSchemaId);
  322. if (!op.isSucc) {
  323. return op;
  324. }
  325. var json = connType === 'SHORT' ? op.json : [service.name, op.json];
  326. return { isSucc: true, output: type === 'json' ? json : JSON.stringify(json) };
  327. }
  328. };
  329. TransportDataUtil.encodeApiReq = function (tsbuffer, service, req, type, sn) {
  330. if (type === 'buffer') {
  331. var op = tsbuffer.encode(req, service.reqSchemaId);
  332. if (!op.isSucc) {
  333. return op;
  334. }
  335. var serverInputData = {
  336. serviceId: service.id,
  337. buffer: op.buf,
  338. sn: sn
  339. };
  340. var opOut = this.tsbuffer.encode(serverInputData, 'ServerInputData');
  341. return opOut.isSucc ? { isSucc: true, output: opOut.buf } : { isSucc: false, errMsg: opOut.errMsg };
  342. }
  343. else {
  344. var op = tsbuffer.encodeJSON(req, service.reqSchemaId);
  345. if (!op.isSucc) {
  346. return op;
  347. }
  348. var json = sn === undefined ? op.json : [service.name, op.json, sn];
  349. return { isSucc: true, output: type === 'json' ? json : JSON.stringify(json) };
  350. }
  351. };
  352. TransportDataUtil.encodeServerMsg = function (tsbuffer, service, msg, type, connType) {
  353. if (type === 'buffer') {
  354. var op = tsbuffer.encode(msg, service.msgSchemaId);
  355. if (!op.isSucc) {
  356. return op;
  357. }
  358. var serverOutputData = {
  359. serviceId: service.id,
  360. buffer: op.buf
  361. };
  362. var opOut = this.tsbuffer.encode(serverOutputData, 'ServerOutputData');
  363. return opOut.isSucc ? { isSucc: true, output: opOut.buf } : { isSucc: false, errMsg: opOut.errMsg };
  364. }
  365. else {
  366. var op = tsbuffer.encodeJSON(msg, service.msgSchemaId);
  367. if (!op.isSucc) {
  368. return op;
  369. }
  370. var json = connType === 'SHORT' ? op.json : [service.name, op.json];
  371. return { isSucc: true, output: type === 'json' ? json : JSON.stringify(json) };
  372. }
  373. };
  374. TransportDataUtil.parseServerOutout = function (tsbuffer, serviceMap, data, serviceId) {
  375. if (data instanceof Uint8Array) {
  376. var opServerOutputData = this.tsbuffer.decode(data, 'ServerOutputData');
  377. if (!opServerOutputData.isSucc) {
  378. return opServerOutputData;
  379. }
  380. var serverOutputData = opServerOutputData.value;
  381. serviceId = serviceId !== null && serviceId !== void 0 ? serviceId : serverOutputData.serviceId;
  382. if (serviceId === undefined) {
  383. return { isSucc: false, errMsg: "Missing 'serviceId' in ServerOutput" };
  384. }
  385. var service = serviceMap.id2Service[serviceId];
  386. if (!service) {
  387. return { isSucc: false, errMsg: "Invalid service ID: ".concat(serviceId, " (from ServerOutput)") };
  388. }
  389. if (service.type === 'msg') {
  390. if (!serverOutputData.buffer) {
  391. return { isSucc: false, errMsg: 'Empty msg buffer (from ServerOutput)' };
  392. }
  393. var opMsg = tsbuffer.decode(serverOutputData.buffer, service.msgSchemaId);
  394. if (!opMsg.isSucc) {
  395. return opMsg;
  396. }
  397. return {
  398. isSucc: true,
  399. result: {
  400. type: 'msg',
  401. service: service,
  402. msg: opMsg.value
  403. }
  404. };
  405. }
  406. else {
  407. if (serverOutputData.error) {
  408. return {
  409. isSucc: true,
  410. result: {
  411. type: 'api',
  412. service: service,
  413. sn: serverOutputData.sn,
  414. ret: {
  415. isSucc: false,
  416. err: new tsrpcProto.TsrpcError(serverOutputData.error)
  417. }
  418. }
  419. };
  420. }
  421. else {
  422. if (!serverOutputData.buffer) {
  423. return { isSucc: false, errMsg: 'Empty API res buffer (from ServerOutput)' };
  424. }
  425. var opRes = tsbuffer.decode(serverOutputData.buffer, service.resSchemaId);
  426. if (!opRes.isSucc) {
  427. return opRes;
  428. }
  429. return {
  430. isSucc: true,
  431. result: {
  432. type: 'api',
  433. service: service,
  434. sn: serverOutputData.sn,
  435. ret: {
  436. isSucc: true,
  437. res: opRes.value,
  438. }
  439. }
  440. };
  441. }
  442. }
  443. }
  444. else {
  445. var json = void 0;
  446. if (typeof data === 'string') {
  447. try {
  448. json = JSON.parse(data);
  449. }
  450. catch (e) {
  451. return { isSucc: false, errMsg: "Invalid input JSON: ".concat(e.message) };
  452. }
  453. }
  454. else {
  455. json = data;
  456. }
  457. var body = void 0;
  458. var sn = void 0;
  459. var service = void 0;
  460. if (serviceId == undefined) {
  461. if (!Array.isArray(json)) {
  462. return { isSucc: false, errMsg: "Invalid server output format" };
  463. }
  464. var serviceName = json[0];
  465. body = json[1];
  466. sn = json[2];
  467. // 有 SN 是 Api,没 SN 是 Msg
  468. service = sn ? serviceMap.apiName2Service[serviceName] : serviceMap.msgName2Service[serviceName];
  469. if (!service) {
  470. return { isSucc: false, errMsg: "Invalid service name: ".concat(serviceName, " (from ServerOutputData)") };
  471. }
  472. }
  473. else {
  474. service = serviceMap.id2Service[serviceId];
  475. if (!service) {
  476. return { isSucc: false, errMsg: "Invalid service ID: ".concat(serviceId) };
  477. }
  478. body = json;
  479. }
  480. if (service.type === 'api') {
  481. if (body.isSucc && 'res' in body) {
  482. var op = tsbuffer.decodeJSON(body.res, service.resSchemaId);
  483. if (!op.isSucc) {
  484. return op;
  485. }
  486. body.res = op.value;
  487. }
  488. else if (body.err) {
  489. body.err = new tsrpcProto.TsrpcError(body.err);
  490. }
  491. else {
  492. return { isSucc: false, errMsg: "Invalid server output format" };
  493. }
  494. return {
  495. isSucc: true,
  496. result: {
  497. type: 'api',
  498. service: service,
  499. sn: sn,
  500. ret: body
  501. }
  502. };
  503. }
  504. else {
  505. var op = tsbuffer.decodeJSON(body, service.msgSchemaId);
  506. if (!op.isSucc) {
  507. return op;
  508. }
  509. return {
  510. isSucc: true,
  511. result: {
  512. type: 'msg',
  513. service: service,
  514. msg: op.value
  515. }
  516. };
  517. }
  518. }
  519. };
  520. // 心跳包(Ping & Pong),所有开头为 0 的 Buffer,均为控制指令
  521. TransportDataUtil.HeartbeatPacket = new Uint8Array([0]);
  522. return TransportDataUtil;
  523. }());
  524. /**
  525. * An abstract base class for TSRPC Client,
  526. * which includes some common buffer process flows.
  527. *
  528. * @remarks
  529. * You can implement a client on a specific transportation protocol (like HTTP, WebSocket, QUIP) by extend this.
  530. *
  531. * @typeParam ServiceType - `ServiceType` from generated `proto.ts`
  532. *
  533. * @see
  534. * {@link https://github.com/k8w/tsrpc}
  535. * {@link https://github.com/k8w/tsrpc-browser}
  536. * {@link https://github.com/k8w/tsrpc-miniapp}
  537. */
  538. var BaseClient = /** @class */ (function () {
  539. function BaseClient(proto, options) {
  540. this._msgHandlers = new MsgHandlerManager();
  541. /**
  542. * {@link Flow} to process `callApi`, `sendMsg`, buffer input/output, etc...
  543. */
  544. this.flows = {
  545. // callApi
  546. preCallApiFlow: new Flow(),
  547. preApiReturnFlow: new Flow(),
  548. postApiReturnFlow: new Flow(),
  549. // sendMsg
  550. preSendMsgFlow: new Flow(),
  551. postSendMsgFlow: new Flow(),
  552. preRecvMsgFlow: new Flow(),
  553. postRecvMsgFlow: new Flow(),
  554. // buffer
  555. preSendDataFlow: new Flow(),
  556. preRecvDataFlow: new Flow(),
  557. /**
  558. * @deprecated Please use `preSendDataFlow` instead
  559. */
  560. preSendBufferFlow: new Flow(),
  561. /**
  562. * @deprecated Please use `preRecvDataFlow` instead
  563. */
  564. preRecvBufferFlow: new Flow(),
  565. // Connection Flows (Only for WebSocket)
  566. /** Before connect to WebSocket server */
  567. preConnectFlow: new Flow(),
  568. /** After WebSocket connect successfully */
  569. postConnectFlow: new Flow(),
  570. /** After WebSocket disconnected (from connected status) */
  571. postDisconnectFlow: new Flow(),
  572. };
  573. this._apiSnCounter = new Counter(1);
  574. /**
  575. * Pending API Requests
  576. */
  577. this._pendingApis = [];
  578. /** @deprecated Please use `_onRecvData` instead */
  579. this._onRecvBuf = this._onRecvData;
  580. this.options = options;
  581. this.serviceMap = ServiceMapUtil.getServiceMap(proto);
  582. this.dataType = this.options.json ? 'text' : 'buffer';
  583. var types = tslib.__assign({}, proto.types);
  584. // Custom ObjectId handler
  585. if (options.customObjectIdClass) {
  586. types = tslib.__assign(tslib.__assign({}, types), getCustomObjectIdTypes(options.customObjectIdClass));
  587. }
  588. this.tsbuffer = new tsbuffer.TSBuffer(types);
  589. this.logger = this.options.logger;
  590. if (this.logger) {
  591. this.logger = tsrpcProto.setLogLevel(this.logger, this.options.logLevel);
  592. }
  593. }
  594. Object.defineProperty(BaseClient.prototype, "lastSN", {
  595. /**
  596. * The `SN` number of the last `callApi()`,
  597. * which can be passed to `abort()` to abort an API request.
  598. * @example
  599. * ```ts
  600. * client.callApi('xxx', { value: 'xxx' })
  601. * .then(ret=>{ console.log('succ', ret) });
  602. * let lastSN = client.lastSN;
  603. * client.abort(lastSN);
  604. * ```
  605. */
  606. get: function () {
  607. return this._apiSnCounter.last;
  608. },
  609. enumerable: false,
  610. configurable: true
  611. });
  612. Object.defineProperty(BaseClient.prototype, "nextSN", {
  613. /**
  614. * The `SN` number of the next `callApi()`,
  615. * which can be passed to `abort()` to abort an API request.
  616. * @example
  617. * ```ts
  618. * let nextSN = client.nextSN;
  619. * client.callApi('xxx', { value: 'xxx' })
  620. * ```
  621. */
  622. get: function () {
  623. return this._apiSnCounter.getNext(true);
  624. },
  625. enumerable: false,
  626. configurable: true
  627. });
  628. /**
  629. * Send request and wait for the return
  630. * @param apiName
  631. * @param req - Request body
  632. * @param options - Transport options
  633. * @returns return a `ApiReturn`, all error (network error, business error, code exception...) is unified as `TsrpcError`.
  634. * The promise is never rejected, so you just need to process all error in one place.
  635. */
  636. BaseClient.prototype.callApi = function (apiName, req, options) {
  637. if (options === void 0) { options = {}; }
  638. return tslib.__awaiter(this, void 0, void 0, function () {
  639. var sn, pendingItem, promise;
  640. var _this = this;
  641. return tslib.__generator(this, function (_a) {
  642. sn = this._apiSnCounter.getNext();
  643. pendingItem = {
  644. sn: sn,
  645. abortKey: options.abortKey,
  646. service: this.serviceMap.apiName2Service[apiName]
  647. };
  648. this._pendingApis.push(pendingItem);
  649. promise = new Promise(function (rs) { return tslib.__awaiter(_this, void 0, void 0, function () {
  650. var pre, ret, preReturn;
  651. var _a, _b;
  652. return tslib.__generator(this, function (_c) {
  653. switch (_c.label) {
  654. case 0: return [4 /*yield*/, this.flows.preCallApiFlow.exec({
  655. apiName: apiName,
  656. req: req,
  657. options: options
  658. }, this.logger)];
  659. case 1:
  660. pre = _c.sent();
  661. if (!pre || pendingItem.isAborted) {
  662. this.abort(pendingItem.sn);
  663. return [2 /*return*/];
  664. }
  665. if (!pre.return) return [3 /*break*/, 2];
  666. ret = pre.return;
  667. return [3 /*break*/, 4];
  668. case 2: return [4 /*yield*/, this._doCallApi(pre.apiName, pre.req, pre.options, pendingItem)];
  669. case 3:
  670. // do call means it will send buffer via network
  671. ret = _c.sent();
  672. _c.label = 4;
  673. case 4:
  674. if (pendingItem.isAborted) {
  675. return [2 /*return*/];
  676. }
  677. // Log Original Return
  678. if (ret.isSucc) {
  679. this.options.logApi && ((_a = this.logger) === null || _a === void 0 ? void 0 : _a.log("[ApiRes] #".concat(pendingItem.sn, " ").concat(apiName), ret.res));
  680. }
  681. else {
  682. this.options.logApi && ((_b = this.logger) === null || _b === void 0 ? void 0 : _b[ret.err.type === tsrpcProto.TsrpcError.Type.ApiError ? 'log' : 'error']("[ApiErr] #".concat(pendingItem.sn, " ").concat(apiName), ret.err));
  683. }
  684. return [4 /*yield*/, this.flows.preApiReturnFlow.exec(tslib.__assign(tslib.__assign({}, pre), { return: ret }), this.logger)];
  685. case 5:
  686. preReturn = _c.sent();
  687. if (!preReturn) {
  688. this.abort(pendingItem.sn);
  689. return [2 /*return*/];
  690. }
  691. rs(preReturn.return);
  692. // Post Flow
  693. this.flows.postApiReturnFlow.exec(preReturn, this.logger);
  694. return [2 /*return*/];
  695. }
  696. });
  697. }); });
  698. // Finally clear pendings
  699. promise.catch().then(function () {
  700. _this._pendingApis.removeOne(function (v) { return v.sn === pendingItem.sn; });
  701. });
  702. return [2 /*return*/, promise];
  703. });
  704. });
  705. };
  706. BaseClient.prototype._doCallApi = function (apiName, req, options, pendingItem) {
  707. var _a;
  708. if (options === void 0) { options = {}; }
  709. return tslib.__awaiter(this, void 0, void 0, function () {
  710. var promise;
  711. var _this = this;
  712. return tslib.__generator(this, function (_b) {
  713. this.options.logApi && ((_a = this.logger) === null || _a === void 0 ? void 0 : _a.log("[ApiReq] #".concat(pendingItem.sn), apiName, req));
  714. promise = new Promise(function (rs) { return tslib.__awaiter(_this, void 0, void 0, function () {
  715. var service, opEncode, promiseReturn, promiseSend, opSend, ret;
  716. var _a;
  717. return tslib.__generator(this, function (_b) {
  718. switch (_b.label) {
  719. case 0:
  720. service = this.serviceMap.apiName2Service[apiName];
  721. if (!service) {
  722. rs({
  723. isSucc: false,
  724. err: new tsrpcProto.TsrpcError('Invalid api name: ' + apiName, {
  725. code: 'INVALID_API_NAME',
  726. type: tsrpcProto.TsrpcErrorType.ClientError
  727. })
  728. });
  729. return [2 /*return*/];
  730. }
  731. pendingItem.service = service;
  732. opEncode = TransportDataUtil.encodeApiReq(this.tsbuffer, service, req, this.dataType, this.type === 'LONG' ? pendingItem.sn : undefined);
  733. if (!opEncode.isSucc) {
  734. rs({
  735. isSucc: false, err: new tsrpcProto.TsrpcError(opEncode.errMsg, {
  736. type: tsrpcProto.TsrpcErrorType.ClientError,
  737. code: 'INPUT_DATA_ERR'
  738. })
  739. });
  740. return [2 /*return*/];
  741. }
  742. promiseReturn = this._waitApiReturn(pendingItem, (_a = options.timeout) !== null && _a !== void 0 ? _a : this.options.timeout);
  743. promiseSend = this.sendData(opEncode.output, options, service.id, pendingItem);
  744. return [4 /*yield*/, promiseSend];
  745. case 1:
  746. opSend = _b.sent();
  747. if (opSend.err) {
  748. rs({
  749. isSucc: false,
  750. err: opSend.err
  751. });
  752. return [2 /*return*/];
  753. }
  754. return [4 /*yield*/, promiseReturn];
  755. case 2:
  756. ret = _b.sent();
  757. if (pendingItem.isAborted) {
  758. return [2 /*return*/];
  759. }
  760. rs(ret);
  761. return [2 /*return*/];
  762. }
  763. });
  764. }); });
  765. return [2 /*return*/, promise];
  766. });
  767. });
  768. };
  769. /**
  770. * Send message, without response, not ensuring the server is received and processed correctly.
  771. * @param msgName
  772. * @param msg - Message body
  773. * @param options - Transport options
  774. * @returns If the promise is resolved, it means the request is sent to system kernel successfully.
  775. * Notice that not means the server received and processed the message correctly.
  776. */
  777. BaseClient.prototype.sendMsg = function (msgName, msg, options) {
  778. var _this = this;
  779. if (options === void 0) { options = {}; }
  780. var promise = new Promise(function (rs) { return tslib.__awaiter(_this, void 0, void 0, function () {
  781. var pre, service, opEncode, promiseSend, opSend;
  782. var _a, _b;
  783. return tslib.__generator(this, function (_c) {
  784. switch (_c.label) {
  785. case 0: return [4 /*yield*/, this.flows.preSendMsgFlow.exec({
  786. msgName: msgName,
  787. msg: msg,
  788. options: options
  789. }, this.logger)];
  790. case 1:
  791. pre = _c.sent();
  792. if (!pre) {
  793. return [2 /*return*/];
  794. }
  795. // The msg is not prevented by pre flow
  796. this.options.logMsg && ((_a = this.logger) === null || _a === void 0 ? void 0 : _a.log("[SendMsg]", msgName, msg));
  797. service = this.serviceMap.msgName2Service[msgName];
  798. if (!service) {
  799. (_b = this.logger) === null || _b === void 0 ? void 0 : _b.error('Invalid msg name: ' + msgName);
  800. rs({
  801. isSucc: false,
  802. err: new tsrpcProto.TsrpcError('Invalid msg name: ' + msgName, {
  803. code: 'INVALID_MSG_NAME',
  804. type: tsrpcProto.TsrpcErrorType.ClientError
  805. })
  806. });
  807. return [2 /*return*/];
  808. }
  809. opEncode = TransportDataUtil.encodeClientMsg(this.tsbuffer, service, msg, this.dataType, this.type);
  810. if (!opEncode.isSucc) {
  811. rs({
  812. isSucc: false,
  813. err: new tsrpcProto.TsrpcError(opEncode.errMsg, {
  814. type: tsrpcProto.TsrpcErrorType.ClientError,
  815. code: 'ENCODE_MSG_ERR'
  816. })
  817. });
  818. return [2 /*return*/];
  819. }
  820. promiseSend = this.sendData(opEncode.output, options, service.id);
  821. return [4 /*yield*/, promiseSend];
  822. case 2:
  823. opSend = _c.sent();
  824. if (opSend.err) {
  825. rs({
  826. isSucc: false,
  827. err: opSend.err
  828. });
  829. return [2 /*return*/];
  830. }
  831. rs({ isSucc: true });
  832. // Post Flow
  833. this.flows.postSendMsgFlow.exec(pre, this.logger);
  834. return [2 /*return*/];
  835. }
  836. });
  837. }); });
  838. promise.then(function (v) {
  839. var _a;
  840. if (!v.isSucc) {
  841. ((_a = _this.logger) !== null && _a !== void 0 ? _a : console).error('[SendMsgErr]', v.err);
  842. }
  843. });
  844. return promise;
  845. };
  846. /**
  847. * Add a message handler,
  848. * duplicate handlers to the same `msgName` would be ignored.
  849. * @param msgName
  850. * @param handler
  851. * @returns
  852. */
  853. // listenMsg<T extends keyof ServiceType['msg']>(msgName: T, handler: ClientMsgHandler<ServiceType, T, this>): ClientMsgHandler<ServiceType, T, this>;
  854. // listenMsg(msgName: RegExp, handler: ClientMsgHandler<ServiceType, keyof ServiceType['msg'], this>): ClientMsgHandler<ServiceType, keyof ServiceType['msg'], this>;
  855. // listenMsg(msgName: string | RegExp, handler: ClientMsgHandler<ServiceType, string, this>): ClientMsgHandler<ServiceType, string, this> {
  856. BaseClient.prototype.listenMsg = function (msgName, handler) {
  857. var _this = this;
  858. if (msgName instanceof RegExp) {
  859. Object.keys(this.serviceMap.msgName2Service).filter(function (k) { return msgName.test(k); }).forEach(function (k) {
  860. _this._msgHandlers.addHandler(k, handler);
  861. });
  862. }
  863. else {
  864. this._msgHandlers.addHandler(msgName, handler);
  865. }
  866. return handler;
  867. };
  868. /**
  869. * Remove a message handler
  870. */
  871. BaseClient.prototype.unlistenMsg = function (msgName, handler) {
  872. var _this = this;
  873. if (msgName instanceof RegExp) {
  874. Object.keys(this.serviceMap.msgName2Service).filter(function (k) { return msgName.test(k); }).forEach(function (k) {
  875. _this._msgHandlers.removeHandler(k, handler);
  876. });
  877. }
  878. else {
  879. this._msgHandlers.removeHandler(msgName, handler);
  880. }
  881. };
  882. /**
  883. * Remove all handlers from a message
  884. */
  885. BaseClient.prototype.unlistenMsgAll = function (msgName) {
  886. var _this = this;
  887. if (msgName instanceof RegExp) {
  888. Object.keys(this.serviceMap.msgName2Service).filter(function (k) { return msgName.test(k); }).forEach(function (k) {
  889. _this._msgHandlers.removeAllHandlers(k);
  890. });
  891. }
  892. else {
  893. this._msgHandlers.removeAllHandlers(msgName);
  894. }
  895. };
  896. /**
  897. * Abort a pending API request, it makes the promise returned by `callApi()` neither resolved nor rejected forever.
  898. * @param sn - Every api request has a unique `sn` number, you can get it by `this.lastSN`
  899. */
  900. BaseClient.prototype.abort = function (sn) {
  901. var _a, _b;
  902. // Find
  903. var index = this._pendingApis.findIndex(function (v) { return v.sn === sn; });
  904. if (index === -1) {
  905. return;
  906. }
  907. var pendingItem = this._pendingApis[index];
  908. // Clear
  909. this._pendingApis.splice(index, 1);
  910. pendingItem.onReturn = undefined;
  911. pendingItem.isAborted = true;
  912. // Log
  913. (_a = this.logger) === null || _a === void 0 ? void 0 : _a.log("[ApiAbort] #".concat(pendingItem.sn, " ").concat(pendingItem.service.name));
  914. // onAbort
  915. (_b = pendingItem.onAbort) === null || _b === void 0 ? void 0 : _b.call(pendingItem);
  916. };
  917. /**
  918. * Abort all API requests that has the `abortKey`.
  919. * It makes the promise returned by `callApi` neither resolved nor rejected forever.
  920. * @param abortKey - The `abortKey` of options when `callApi()`, see {@link TransportOptions.abortKey}.
  921. * @example
  922. * ```ts
  923. * // Send API request many times
  924. * client.callApi('SendData', { data: 'AAA' }, { abortKey: 'Session#123' });
  925. * client.callApi('SendData', { data: 'BBB' }, { abortKey: 'Session#123' });
  926. * client.callApi('SendData', { data: 'CCC' }, { abortKey: 'Session#123' });
  927. *
  928. * // And abort the at once
  929. * client.abortByKey('Session#123');
  930. * ```
  931. */
  932. BaseClient.prototype.abortByKey = function (abortKey) {
  933. var _this = this;
  934. this._pendingApis.filter(function (v) { return v.abortKey === abortKey; }).forEach(function (v) { _this.abort(v.sn); });
  935. };
  936. /**
  937. * Abort all pending API requests.
  938. * It makes the promise returned by `callApi` neither resolved nor rejected forever.
  939. */
  940. BaseClient.prototype.abortAll = function () {
  941. var _this = this;
  942. this._pendingApis.slice().forEach(function (v) { return _this.abort(v.sn); });
  943. };
  944. /**
  945. * Send data (binary or text)
  946. * @remarks
  947. * Long connection: wait res by listenning `conn.onmessage`
  948. * Short connection: wait res by waitting response
  949. * @param data
  950. * @param options
  951. * @param sn
  952. */
  953. BaseClient.prototype.sendData = function (data, options, serviceId, pendingApiItem) {
  954. var _a, _b, _c;
  955. return tslib.__awaiter(this, void 0, void 0, function () {
  956. var pre, preBuf;
  957. return tslib.__generator(this, function (_d) {
  958. switch (_d.label) {
  959. case 0: return [4 /*yield*/, this.flows.preSendDataFlow.exec({ data: data, sn: pendingApiItem === null || pendingApiItem === void 0 ? void 0 : pendingApiItem.sn }, this.logger)];
  960. case 1:
  961. pre = _d.sent();
  962. if (!pre) {
  963. return [2 /*return*/, new Promise(function (rs) { })];
  964. }
  965. data = pre.data;
  966. if (!(data instanceof Uint8Array)) return [3 /*break*/, 3];
  967. return [4 /*yield*/, this.flows.preSendBufferFlow.exec({ buf: data, sn: pendingApiItem === null || pendingApiItem === void 0 ? void 0 : pendingApiItem.sn }, this.logger)];
  968. case 2:
  969. preBuf = _d.sent();
  970. if (!preBuf) {
  971. return [2 /*return*/, new Promise(function (rs) { })];
  972. }
  973. data = preBuf.buf;
  974. _d.label = 3;
  975. case 3:
  976. // debugBuf log
  977. if (this.options.debugBuf) {
  978. if (typeof data === 'string') {
  979. (_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug('[SendText]' + (pendingApiItem ? (' #' + pendingApiItem.sn) : '') + " length=".concat(data.length), data);
  980. }
  981. else if (data instanceof Uint8Array) {
  982. (_b = this.logger) === null || _b === void 0 ? void 0 : _b.debug('[SendBuf]' + (pendingApiItem ? (' #' + pendingApiItem.sn) : '') + " length=".concat(data.length), data);
  983. }
  984. else {
  985. (_c = this.logger) === null || _c === void 0 ? void 0 : _c.debug('[SendJSON]' + (pendingApiItem ? (' #' + pendingApiItem.sn) : ''), data);
  986. }
  987. }
  988. return [2 /*return*/, this._sendData(data, options, serviceId, pendingApiItem)];
  989. }
  990. });
  991. });
  992. };
  993. // 信道可传输二进制或字符串
  994. BaseClient.prototype._onRecvData = function (data, pendingApiItem) {
  995. var _a, _b, _c, _d, _e, _f, _g, _h, _j;
  996. return tslib.__awaiter(this, void 0, void 0, function () {
  997. var sn, pre, pre_1, opParsed, parsed, pre_2;
  998. return tslib.__generator(this, function (_k) {
  999. switch (_k.label) {
  1000. case 0:
  1001. sn = pendingApiItem === null || pendingApiItem === void 0 ? void 0 : pendingApiItem.sn;
  1002. return [4 /*yield*/, this.flows.preRecvDataFlow.exec({ data: data, sn: sn }, this.logger)];
  1003. case 1:
  1004. pre = _k.sent();
  1005. if (!pre) {
  1006. return [2 /*return*/];
  1007. }
  1008. data = pre.data;
  1009. if (!(typeof data === 'string')) return [3 /*break*/, 2];
  1010. this.options.debugBuf && ((_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug('[RecvText]' + (sn ? (' #' + sn) : ''), data));
  1011. return [3 /*break*/, 5];
  1012. case 2:
  1013. if (!(data instanceof Uint8Array)) return [3 /*break*/, 4];
  1014. this.options.debugBuf && ((_b = this.logger) === null || _b === void 0 ? void 0 : _b.debug('[RecvBuf]' + (sn ? (' #' + sn) : ''), 'length=' + data.length, data));
  1015. return [4 /*yield*/, this.flows.preRecvBufferFlow.exec({ buf: data, sn: sn }, this.logger)];
  1016. case 3:
  1017. pre_1 = _k.sent();
  1018. if (!pre_1) {
  1019. return [2 /*return*/];
  1020. }
  1021. data = pre_1.buf;
  1022. return [3 /*break*/, 5];
  1023. case 4:
  1024. this.options.debugBuf && ((_c = this.logger) === null || _c === void 0 ? void 0 : _c.debug('[RecvJSON]' + (sn ? (' #' + sn) : ''), data));
  1025. _k.label = 5;
  1026. case 5:
  1027. opParsed = TransportDataUtil.parseServerOutout(this.tsbuffer, this.serviceMap, data, pendingApiItem === null || pendingApiItem === void 0 ? void 0 : pendingApiItem.service.id);
  1028. if (!opParsed.isSucc) {
  1029. (_d = this.logger) === null || _d === void 0 ? void 0 : _d.error('ParseServerOutputError: ' + opParsed.errMsg);
  1030. if (data instanceof Uint8Array) {
  1031. (_e = this.logger) === null || _e === void 0 ? void 0 : _e.error('Please check the version of serviceProto between server and client');
  1032. }
  1033. if (pendingApiItem) {
  1034. (_f = pendingApiItem.onReturn) === null || _f === void 0 ? void 0 : _f.call(pendingApiItem, {
  1035. isSucc: false,
  1036. err: new tsrpcProto.TsrpcError('Parse server output error', { type: tsrpcProto.TsrpcErrorType.ServerError })
  1037. });
  1038. }
  1039. return [2 /*return*/];
  1040. }
  1041. parsed = opParsed.result;
  1042. if (!(parsed.type === 'api')) return [3 /*break*/, 6];
  1043. sn = sn !== null && sn !== void 0 ? sn : parsed.sn;
  1044. // call ApiReturn listeners
  1045. (_h = (_g = this._pendingApis.find(function (v) { return v.sn === sn; })) === null || _g === void 0 ? void 0 : _g.onReturn) === null || _h === void 0 ? void 0 : _h.call(_g, parsed.ret);
  1046. return [3 /*break*/, 9];
  1047. case 6:
  1048. if (!(parsed.type === 'msg')) return [3 /*break*/, 9];
  1049. this.options.logMsg && ((_j = this.logger) === null || _j === void 0 ? void 0 : _j.log("[RecvMsg] ".concat(parsed.service.name), parsed.msg));
  1050. return [4 /*yield*/, this.flows.preRecvMsgFlow.exec({ msgName: parsed.service.name, msg: parsed.msg }, this.logger)];
  1051. case 7:
  1052. pre_2 = _k.sent();
  1053. if (!pre_2) {
  1054. return [2 /*return*/];
  1055. }
  1056. this._msgHandlers.forEachHandler(pre_2.msgName, this.logger, pre_2.msg, pre_2.msgName);
  1057. // Post Flow
  1058. return [4 /*yield*/, this.flows.postRecvMsgFlow.exec(pre_2, this.logger)];
  1059. case 8:
  1060. // Post Flow
  1061. _k.sent();
  1062. _k.label = 9;
  1063. case 9: return [2 /*return*/];
  1064. }
  1065. });
  1066. });
  1067. };
  1068. /**
  1069. * @param sn
  1070. * @param timeout
  1071. * @returns `undefined` 代表 canceled
  1072. */
  1073. BaseClient.prototype._waitApiReturn = function (pendingItem, timeout) {
  1074. return tslib.__awaiter(this, void 0, void 0, function () {
  1075. var _this = this;
  1076. return tslib.__generator(this, function (_a) {
  1077. return [2 /*return*/, new Promise(function (rs) {
  1078. // Timeout
  1079. var timer;
  1080. if (timeout) {
  1081. timer = setTimeout(function () {
  1082. timer = undefined;
  1083. _this._pendingApis.removeOne(function (v) { return v.sn === pendingItem.sn; });
  1084. rs({
  1085. isSucc: false,
  1086. err: new tsrpcProto.TsrpcError('Request Timeout', {
  1087. type: tsrpcProto.TsrpcErrorType.NetworkError,
  1088. code: 'TIMEOUT'
  1089. })
  1090. });
  1091. }, timeout);
  1092. }
  1093. // Listener (trigger by `this._onRecvBuf`)
  1094. pendingItem.onReturn = function (ret) {
  1095. if (timer) {
  1096. clearTimeout(timer);
  1097. timer = undefined;
  1098. }
  1099. _this._pendingApis.removeOne(function (v) { return v.sn === pendingItem.sn; });
  1100. rs(ret);
  1101. };
  1102. })];
  1103. });
  1104. });
  1105. };
  1106. return BaseClient;
  1107. }());
  1108. var defaultBaseClientOptions = {
  1109. logLevel: 'debug',
  1110. logApi: true,
  1111. logMsg: true,
  1112. json: false,
  1113. timeout: 15000,
  1114. debugBuf: false
  1115. };
  1116. /**
  1117. * Base HTTP Client
  1118. */
  1119. var BaseHttpClient = /** @class */ (function (_super) {
  1120. tslib.__extends(BaseHttpClient, _super);
  1121. function BaseHttpClient(proto, http, options) {
  1122. var _this = this;
  1123. var _a;
  1124. _this = _super.call(this, proto, tslib.__assign(tslib.__assign({}, defaultBaseHttpClientOptions), options)) || this;
  1125. _this.type = 'SHORT';
  1126. _this._http = http;
  1127. _this._jsonServer = _this.options.server + (_this.options.server.endsWith('/') ? '' : '/');
  1128. (_a = _this.logger) === null || _a === void 0 ? void 0 : _a.log('TSRPC HTTP Client :', _this.options.server);
  1129. return _this;
  1130. }
  1131. BaseHttpClient.prototype._sendData = function (data, options, serviceId, pendingApiItem) {
  1132. return tslib.__awaiter(this, void 0, void 0, function () {
  1133. var promise;
  1134. var _this = this;
  1135. return tslib.__generator(this, function (_a) {
  1136. promise = (function () { return tslib.__awaiter(_this, void 0, void 0, function () {
  1137. var service, urlSearch, url, _a, fetchPromise, abort, fetchRes;
  1138. return tslib.__generator(this, function (_b) {
  1139. switch (_b.label) {
  1140. case 0:
  1141. service = this.serviceMap.id2Service[serviceId];
  1142. urlSearch = service.type === 'msg' ? '?type=msg' : '';
  1143. url = typeof data === 'string' ? (this._jsonServer + service.name + urlSearch) : this.options.server;
  1144. _a = this._http.fetch({
  1145. url: url,
  1146. data: data,
  1147. method: 'POST',
  1148. timeout: options.timeout || this.options.timeout,
  1149. headers: { 'Content-Type': typeof data === 'string' ? 'application/json' : 'application/octet-stream' },
  1150. transportOptions: options,
  1151. responseType: typeof data === 'string' ? 'text' : 'arraybuffer',
  1152. }), fetchPromise = _a.promise, abort = _a.abort;
  1153. if (pendingApiItem) {
  1154. pendingApiItem.onAbort = function () {
  1155. abort();
  1156. };
  1157. }
  1158. // Aborted
  1159. if (pendingApiItem === null || pendingApiItem === void 0 ? void 0 : pendingApiItem.isAborted) {
  1160. return [2 /*return*/, new Promise(function (rs) { })];
  1161. }
  1162. return [4 /*yield*/, fetchPromise];
  1163. case 1:
  1164. fetchRes = _b.sent();
  1165. if (!fetchRes.isSucc) {
  1166. return [2 /*return*/, { err: fetchRes.err }];
  1167. }
  1168. return [2 /*return*/, { res: fetchRes.res }];
  1169. }
  1170. });
  1171. }); })();
  1172. promise.then(function (v) {
  1173. // Msg 不需要 onRecvData
  1174. if (pendingApiItem && v.res) {
  1175. _this._onRecvData(v.res, pendingApiItem);
  1176. }
  1177. });
  1178. // Finally
  1179. promise.catch(function (e) { }).then(function () {
  1180. if (pendingApiItem) {
  1181. pendingApiItem.onAbort = undefined;
  1182. }
  1183. });
  1184. return [2 /*return*/, promise];
  1185. });
  1186. });
  1187. };
  1188. return BaseHttpClient;
  1189. }(BaseClient));
  1190. var defaultBaseHttpClientOptions = tslib.__assign(tslib.__assign({}, defaultBaseClientOptions), { server: 'http://localhost:3000',
  1191. // logger: new TerminalColorLogger(),
  1192. jsonPrune: true });
  1193. /**
  1194. * WebSocket Client for TSRPC.
  1195. * It uses native `WebSocket` of browser.
  1196. * @typeParam ServiceType - `ServiceType` from generated `proto.ts`
  1197. */
  1198. var BaseWsClient = /** @class */ (function (_super) {
  1199. tslib.__extends(BaseWsClient, _super);
  1200. function BaseWsClient(proto, wsp, options) {
  1201. var _this = this;
  1202. var _a;
  1203. _this = _super.call(this, proto, tslib.__assign(tslib.__assign({}, defaultBaseWsClientOptions), options)) || this;
  1204. _this.type = 'LONG';
  1205. _this._onWsOpen = function () {
  1206. var _a;
  1207. if (!_this._connecting) {
  1208. return;
  1209. }
  1210. _this._status = exports.WsClientStatus.Opened;
  1211. _this._connecting.rs({ isSucc: true });
  1212. _this._connecting = undefined;
  1213. (_a = _this.logger) === null || _a === void 0 ? void 0 : _a.log('WebSocket connection to server successful');
  1214. _this.flows.postConnectFlow.exec({}, _this.logger);
  1215. // First heartbeat
  1216. if (_this.options.heartbeat) {
  1217. _this._heartbeat();
  1218. }
  1219. };
  1220. _this._onWsClose = function (code, reason) {
  1221. var _a, _b, _c;
  1222. // 防止重复执行
  1223. if (_this._status === exports.WsClientStatus.Closed) {
  1224. return;
  1225. }
  1226. var isManual = !!_this._rsDisconnecting;
  1227. var isConnectedBefore = _this.isConnected || isManual;
  1228. _this._status = exports.WsClientStatus.Closed;
  1229. // 连接中,返回连接失败
  1230. if (_this._connecting) {
  1231. _this._connecting.rs({
  1232. isSucc: false,
  1233. errMsg: "Failed to connect to WebSocket server: ".concat(_this.options.server)
  1234. });
  1235. _this._connecting = undefined;
  1236. (_a = _this.logger) === null || _a === void 0 ? void 0 : _a.error("Failed to connect to WebSocket server: ".concat(_this.options.server));
  1237. }
  1238. // Clear heartbeat
  1239. if (_this._pendingHeartbeat) {
  1240. clearTimeout(_this._pendingHeartbeat.timeoutTimer);
  1241. _this._pendingHeartbeat = undefined;
  1242. }
  1243. if (_this._nextHeartbeatTimer) {
  1244. clearTimeout(_this._nextHeartbeatTimer);
  1245. }
  1246. // disconnect中,返回成功
  1247. if (_this._rsDisconnecting) {
  1248. _this._rsDisconnecting();
  1249. _this._rsDisconnecting = undefined;
  1250. (_b = _this.logger) === null || _b === void 0 ? void 0 : _b.log('Disconnected succ', "code=".concat(code, " reason=").concat(reason));
  1251. }
  1252. // 非 disconnect 中,从连接中意外断开
  1253. else if (isConnectedBefore) {
  1254. (_c = _this.logger) === null || _c === void 0 ? void 0 : _c.log("Lost connection to ".concat(_this.options.server), "code=".concat(code, " reason=").concat(reason));
  1255. }
  1256. // postDisconnectFlow,仅从连接状态断开时触发
  1257. if (isConnectedBefore) {
  1258. _this.flows.postDisconnectFlow.exec({
  1259. reason: reason,
  1260. isManual: isManual
  1261. }, _this.logger);
  1262. }
  1263. // 对所有请求中的 API 报错
  1264. _this._pendingApis.slice().forEach(function (v) {
  1265. var _a;
  1266. (_a = v.onReturn) === null || _a === void 0 ? void 0 : _a.call(v, {
  1267. isSucc: false,
  1268. err: new tsrpcProto.TsrpcError(reason || 'Lost connection to server', { type: tsrpcProto.TsrpcErrorType.NetworkError, code: 'LOST_CONN' })
  1269. });
  1270. });
  1271. };
  1272. _this._onWsError = function (e) {
  1273. var _a, _b;
  1274. (_a = _this.logger) === null || _a === void 0 ? void 0 : _a.error('[WebSocket Error]', e);
  1275. // 连接中,返回连接失败
  1276. if (_this._connecting) {
  1277. _this._connecting.rs({
  1278. isSucc: false,
  1279. errMsg: "Failed to connect to WebSocket server: ".concat(_this.options.server)
  1280. });
  1281. _this._connecting = undefined;
  1282. (_b = _this.logger) === null || _b === void 0 ? void 0 : _b.error("Failed to connect to WebSocket server: ".concat(_this.options.server));
  1283. }
  1284. };
  1285. _this._onWsMessage = function (data) {
  1286. if (_this._status !== exports.WsClientStatus.Opened) {
  1287. return;
  1288. }
  1289. // 心跳包回包
  1290. if (data instanceof Uint8Array && data.length === TransportDataUtil.HeartbeatPacket.length && data.every(function (v, i) { return v === TransportDataUtil.HeartbeatPacket[i]; })) {
  1291. _this._onHeartbeatAnswer(data);
  1292. return;
  1293. }
  1294. _this._onRecvData(data);
  1295. };
  1296. // #region Heartbeat
  1297. /**
  1298. * Last latency time (ms) of heartbeat test
  1299. */
  1300. _this.lastHeartbeatLatency = 0;
  1301. // #endregion
  1302. _this._status = exports.WsClientStatus.Closed;
  1303. _this._wsp = wsp;
  1304. wsp.options = {
  1305. onOpen: _this._onWsOpen,
  1306. onClose: _this._onWsClose,
  1307. onError: _this._onWsError,
  1308. onMessage: _this._onWsMessage,
  1309. logger: _this.logger
  1310. };
  1311. (_a = _this.logger) === null || _a === void 0 ? void 0 : _a.log('TSRPC WebSocket Client :', _this.options.server);
  1312. return _this;
  1313. }
  1314. BaseWsClient.prototype._sendData = function (data) {
  1315. return tslib.__awaiter(this, void 0, void 0, function () {
  1316. var _this = this;
  1317. return tslib.__generator(this, function (_a) {
  1318. return [2 /*return*/, new Promise(function (rs) { return tslib.__awaiter(_this, void 0, void 0, function () {
  1319. return tslib.__generator(this, function (_a) {
  1320. if (!this.isConnected) {
  1321. rs({
  1322. err: new tsrpcProto.TsrpcError('WebSocket is not connected', {
  1323. code: 'WS_NOT_OPEN',
  1324. type: tsrpcProto.TsrpcError.Type.ClientError
  1325. })
  1326. });
  1327. return [2 /*return*/];
  1328. }
  1329. // Do Send
  1330. rs(this._wsp.send(data));
  1331. return [2 /*return*/];
  1332. });
  1333. }); })];
  1334. });
  1335. });
  1336. };
  1337. /**
  1338. * Send a heartbeat packet
  1339. */
  1340. BaseWsClient.prototype._heartbeat = function () {
  1341. var _this = this;
  1342. var _a;
  1343. if (this._pendingHeartbeat || this._status !== exports.WsClientStatus.Opened || !this.options.heartbeat) {
  1344. return;
  1345. }
  1346. this._pendingHeartbeat = {
  1347. startTime: Date.now(),
  1348. timeoutTimer: setTimeout(function () {
  1349. var _a;
  1350. _this._pendingHeartbeat = undefined;
  1351. // heartbeat timeout, disconnect if still connected
  1352. (_a = _this.logger) === null || _a === void 0 ? void 0 : _a.error('[Heartbeat] Heartbeat timeout, the connection disconnected automatically.');
  1353. _this._wsClose(3000, 'Heartbeat timeout');
  1354. _this._wsp.options.onClose(3000, 'Heartbeat timeout');
  1355. }, this.options.heartbeat.timeout)
  1356. };
  1357. this.options.debugBuf && ((_a = this.logger) === null || _a === void 0 ? void 0 : _a.log('[Heartbeat] Send ping', TransportDataUtil.HeartbeatPacket));
  1358. this._sendData(TransportDataUtil.HeartbeatPacket);
  1359. };
  1360. BaseWsClient.prototype._onHeartbeatAnswer = function (data) {
  1361. var _this = this;
  1362. var _a;
  1363. if (!this._pendingHeartbeat || this._status !== exports.WsClientStatus.Opened || !this.options.heartbeat) {
  1364. return;
  1365. }
  1366. // heartbeat succ
  1367. this.lastHeartbeatLatency = Date.now() - this._pendingHeartbeat.startTime;
  1368. this.options.debugBuf && ((_a = this.logger) === null || _a === void 0 ? void 0 : _a.log("[Heartbeat] Recv pong, latency=".concat(this.lastHeartbeatLatency, "ms"), data));
  1369. clearTimeout(this._pendingHeartbeat.timeoutTimer);
  1370. this._pendingHeartbeat = undefined;
  1371. // next heartbeat timer
  1372. this._nextHeartbeatTimer = setTimeout(function () {
  1373. _this._heartbeat();
  1374. }, this.options.heartbeat.interval);
  1375. };
  1376. Object.defineProperty(BaseWsClient.prototype, "status", {
  1377. get: function () {
  1378. return this._status;
  1379. },
  1380. enumerable: false,
  1381. configurable: true
  1382. });
  1383. Object.defineProperty(BaseWsClient.prototype, "isConnected", {
  1384. get: function () {
  1385. return this._status === exports.WsClientStatus.Opened;
  1386. },
  1387. enumerable: false,
  1388. configurable: true
  1389. });
  1390. /**
  1391. * Start connecting, you must connect first before `callApi()` and `sendMsg()`.
  1392. * @throws never
  1393. */
  1394. BaseWsClient.prototype.connect = function () {
  1395. var _a, _b;
  1396. return tslib.__awaiter(this, void 0, void 0, function () {
  1397. var pre, promiseConnect;
  1398. var _this = this;
  1399. return tslib.__generator(this, function (_c) {
  1400. switch (_c.label) {
  1401. case 0:
  1402. // 已连接成功
  1403. if (this.isConnected) {
  1404. return [2 /*return*/, { isSucc: true }];
  1405. }
  1406. // 已连接中
  1407. if (this._connecting) {
  1408. return [2 /*return*/, this._connecting.promise];
  1409. }
  1410. return [4 /*yield*/, this.flows.preConnectFlow.exec({}, this.logger)];
  1411. case 1:
  1412. pre = _c.sent();
  1413. // Pre return
  1414. if (pre === null || pre === void 0 ? void 0 : pre.return) {
  1415. return [2 /*return*/, pre.return];
  1416. }
  1417. // Canceled
  1418. if (!pre) {
  1419. return [2 /*return*/, new Promise(function (rs) { })];
  1420. }
  1421. try {
  1422. this._wsp.connect(this.options.server, [this.options.json ? 'text' : 'buffer']);
  1423. }
  1424. catch (e) {
  1425. (_a = this.logger) === null || _a === void 0 ? void 0 : _a.error(e);
  1426. return [2 /*return*/, { isSucc: false, errMsg: e.message }];
  1427. }
  1428. this._status = exports.WsClientStatus.Opening;
  1429. (_b = this.logger) === null || _b === void 0 ? void 0 : _b.log("Start connecting ".concat(this.options.server, "..."));
  1430. this._connecting = {};
  1431. promiseConnect = new Promise(function (rs) {
  1432. _this._connecting.rs = rs;
  1433. });
  1434. this._connecting.promise = promiseConnect;
  1435. return [2 /*return*/, promiseConnect];
  1436. }
  1437. });
  1438. });
  1439. };
  1440. /**
  1441. * Disconnect immediately
  1442. * @throws never
  1443. */
  1444. BaseWsClient.prototype.disconnect = function (code, reason) {
  1445. var _a;
  1446. return tslib.__awaiter(this, void 0, void 0, function () {
  1447. var isClosed;
  1448. var _this = this;
  1449. return tslib.__generator(this, function (_b) {
  1450. if (this._status === exports.WsClientStatus.Closed) {
  1451. return [2 /*return*/];
  1452. }
  1453. this._status = exports.WsClientStatus.Closing;
  1454. (_a = this.logger) === null || _a === void 0 ? void 0 : _a.log('Start disconnecting...');
  1455. isClosed = false;
  1456. return [2 /*return*/, Promise.race([
  1457. // 正常等待 onClose 关闭
  1458. new Promise(function (rs) {
  1459. _this._rsDisconnecting = function () {
  1460. if (isClosed) {
  1461. return;
  1462. }
  1463. isClosed = true;
  1464. rs();
  1465. };
  1466. _this._wsClose(code !== null && code !== void 0 ? code : 1000, reason !== null && reason !== void 0 ? reason : '');
  1467. }),
  1468. // 超时保护,1 秒未收到关闭请求的,直接 onClose 掉
  1469. new Promise(function (rs) {
  1470. setTimeout(function () {
  1471. if (isClosed) {
  1472. return;
  1473. }
  1474. isClosed = true;
  1475. _this._onWsClose(1005, 'Connection closed, but not received ws.onClose event.');
  1476. }, 1000);
  1477. })
  1478. ])];
  1479. });
  1480. });
  1481. };
  1482. BaseWsClient.prototype._wsClose = function (code, reason) {
  1483. var _a;
  1484. try {
  1485. this._wsp.close(code !== null && code !== void 0 ? code : 1000, reason !== null && reason !== void 0 ? reason : '');
  1486. }
  1487. catch (e) {
  1488. (_a = this.logger) === null || _a === void 0 ? void 0 : _a.error('[WsCloseError]', e);
  1489. }
  1490. };
  1491. return BaseWsClient;
  1492. }(BaseClient));
  1493. var defaultBaseWsClientOptions = tslib.__assign(tslib.__assign({}, defaultBaseClientOptions), { server: 'ws://localhost:3000' });
  1494. exports.WsClientStatus = void 0;
  1495. (function (WsClientStatus) {
  1496. WsClientStatus["Opening"] = "OPENING";
  1497. WsClientStatus["Opened"] = "OPENED";
  1498. WsClientStatus["Closing"] = "CLOSING";
  1499. WsClientStatus["Closed"] = "CLOSED";
  1500. })(exports.WsClientStatus || (exports.WsClientStatus = {}));
  1501. exports.BaseClient = BaseClient;
  1502. exports.BaseHttpClient = BaseHttpClient;
  1503. exports.BaseWsClient = BaseWsClient;
  1504. exports.Counter = Counter;
  1505. exports.Flow = Flow;
  1506. exports.MsgHandlerManager = MsgHandlerManager;
  1507. exports.ServiceMapUtil = ServiceMapUtil;
  1508. exports.TransportDataUtil = TransportDataUtil;
  1509. exports.defaultBaseClientOptions = defaultBaseClientOptions;
  1510. exports.defaultBaseHttpClientOptions = defaultBaseHttpClientOptions;
  1511. exports.defaultBaseWsClientOptions = defaultBaseWsClientOptions;
  1512. exports.getCustomObjectIdTypes = getCustomObjectIdTypes;