index.mjs 67 KB

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