@cloudbase/database 0.9.17-beta → 0.9.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/README.md +32 -10
  2. package/dist/commonjs/ObjectId/index.d.ts +11 -0
  3. package/dist/commonjs/ObjectId/index.js +21 -0
  4. package/dist/commonjs/aggregate.d.ts +29 -29
  5. package/dist/commonjs/aggregate.js +156 -146
  6. package/dist/commonjs/collection.d.ts +9 -9
  7. package/dist/commonjs/collection.js +46 -46
  8. package/dist/commonjs/command.d.ts +175 -175
  9. package/dist/commonjs/command.js +298 -298
  10. package/dist/commonjs/commands/logic.d.ts +24 -24
  11. package/dist/commonjs/commands/logic.js +88 -88
  12. package/dist/commonjs/commands/query.d.ts +68 -68
  13. package/dist/commonjs/commands/query.js +157 -157
  14. package/dist/commonjs/commands/update.d.ts +29 -29
  15. package/dist/commonjs/commands/update.js +50 -50
  16. package/dist/commonjs/config/app.config.d.ts +6 -6
  17. package/dist/commonjs/config/app.config.js +7 -7
  18. package/dist/commonjs/config/error.config.d.ts +3 -3
  19. package/dist/commonjs/config/error.config.js +15 -15
  20. package/dist/commonjs/const/code.d.ts +30 -30
  21. package/dist/commonjs/const/code.js +32 -32
  22. package/dist/commonjs/constant.d.ts +51 -51
  23. package/dist/commonjs/constant.js +74 -74
  24. package/dist/commonjs/document.d.ts +11 -11
  25. package/dist/commonjs/document.js +252 -263
  26. package/dist/commonjs/geo/index.d.ts +6 -6
  27. package/dist/commonjs/geo/index.js +11 -11
  28. package/dist/commonjs/geo/interface.d.ts +24 -24
  29. package/dist/commonjs/geo/interface.js +2 -2
  30. package/dist/commonjs/geo/lineString.d.ts +19 -19
  31. package/dist/commonjs/geo/lineString.js +85 -85
  32. package/dist/commonjs/geo/multiLineString.d.ts +18 -18
  33. package/dist/commonjs/geo/multiLineString.js +94 -94
  34. package/dist/commonjs/geo/multiPoint.d.ts +18 -18
  35. package/dist/commonjs/geo/multiPoint.js +78 -78
  36. package/dist/commonjs/geo/multiPolygon.d.ts +18 -18
  37. package/dist/commonjs/geo/multiPolygon.js +121 -121
  38. package/dist/commonjs/geo/point.d.ts +19 -19
  39. package/dist/commonjs/geo/point.js +49 -49
  40. package/dist/commonjs/geo/polygon.d.ts +19 -19
  41. package/dist/commonjs/geo/polygon.js +108 -108
  42. package/dist/commonjs/helper/symbol.d.ts +14 -14
  43. package/dist/commonjs/helper/symbol.js +19 -19
  44. package/dist/commonjs/index.d.ts +33 -32
  45. package/dist/commonjs/index.js +46 -46
  46. package/dist/commonjs/lib/util.d.ts +1 -1
  47. package/dist/commonjs/lib/util.js +25 -25
  48. package/dist/commonjs/operator-map.d.ts +4 -4
  49. package/dist/commonjs/operator-map.js +23 -23
  50. package/dist/commonjs/query.d.ts +22 -22
  51. package/dist/commonjs/query.js +251 -262
  52. package/dist/commonjs/realtime/error.d.ts +7 -7
  53. package/dist/commonjs/realtime/error.js +11 -27
  54. package/dist/commonjs/realtime/listener.d.ts +14 -14
  55. package/dist/commonjs/realtime/listener.js +17 -18
  56. package/dist/commonjs/realtime/message.d.ts +3 -3
  57. package/dist/commonjs/realtime/message.js +10 -11
  58. package/dist/commonjs/realtime/snapshot.d.ts +16 -16
  59. package/dist/commonjs/realtime/snapshot.js +42 -43
  60. package/dist/commonjs/realtime/virtual-websocket-client.d.ts +63 -63
  61. package/dist/commonjs/realtime/virtual-websocket-client.js +736 -990
  62. package/dist/commonjs/realtime/websocket-client.d.ts +78 -78
  63. package/dist/commonjs/realtime/websocket-client.js +567 -788
  64. package/dist/commonjs/realtime/ws-event.d.ts +126 -126
  65. package/dist/commonjs/realtime/ws-event.js +139 -139
  66. package/dist/commonjs/regexp/index.d.ts +14 -14
  67. package/dist/commonjs/regexp/index.js +32 -32
  68. package/dist/commonjs/serializer/common.d.ts +11 -11
  69. package/dist/commonjs/serializer/common.js +121 -121
  70. package/dist/commonjs/serializer/datatype.d.ts +7 -7
  71. package/dist/commonjs/serializer/datatype.js +126 -126
  72. package/dist/commonjs/serializer/query.d.ts +7 -7
  73. package/dist/commonjs/serializer/query.js +231 -231
  74. package/dist/commonjs/serializer/update.d.ts +15 -15
  75. package/dist/commonjs/serializer/update.js +141 -141
  76. package/dist/commonjs/serverDate/index.d.ts +13 -13
  77. package/dist/commonjs/serverDate/index.js +29 -29
  78. package/dist/commonjs/transaction/collection.d.ts +7 -7
  79. package/dist/commonjs/transaction/collection.js +46 -46
  80. package/dist/commonjs/transaction/document.d.ts +27 -27
  81. package/dist/commonjs/transaction/document.js +205 -205
  82. package/dist/commonjs/transaction/index.d.ts +30 -30
  83. package/dist/commonjs/transaction/index.js +214 -214
  84. package/dist/commonjs/transaction/query.d.ts +5 -5
  85. package/dist/commonjs/transaction/query.js +10 -10
  86. package/dist/commonjs/transaction.d.ts +42 -42
  87. package/dist/commonjs/transaction.js +126 -126
  88. package/dist/commonjs/typings/index.d.ts +40 -40
  89. package/dist/commonjs/typings/index.js +2 -2
  90. package/dist/commonjs/typings/realtime.d.ts +219 -219
  91. package/dist/commonjs/typings/realtime.js +2 -2
  92. package/dist/commonjs/util.d.ts +9 -9
  93. package/dist/commonjs/util.js +144 -144
  94. package/dist/commonjs/utils/error.d.ts +37 -37
  95. package/dist/commonjs/utils/error.js +85 -85
  96. package/dist/commonjs/utils/symbol.d.ts +8 -8
  97. package/dist/commonjs/utils/symbol.js +57 -57
  98. package/dist/commonjs/utils/type.d.ts +13 -13
  99. package/dist/commonjs/utils/type.js +22 -22
  100. package/dist/commonjs/utils/utils.d.ts +4 -2
  101. package/dist/commonjs/utils/utils.js +36 -14
  102. package/dist/commonjs/validate.d.ts +1 -1
  103. package/dist/commonjs/validate.js +59 -59
  104. package/dist/esm/ObjectId/index.d.ts +11 -0
  105. package/dist/esm/ObjectId/index.js +17 -0
  106. package/dist/esm/aggregate.d.ts +29 -29
  107. package/dist/esm/aggregate.js +154 -144
  108. package/dist/esm/collection.d.ts +9 -9
  109. package/dist/esm/collection.js +44 -44
  110. package/dist/esm/command.d.ts +175 -175
  111. package/dist/esm/command.js +296 -296
  112. package/dist/esm/commands/logic.d.ts +24 -24
  113. package/dist/esm/commands/logic.js +84 -84
  114. package/dist/esm/commands/query.d.ts +68 -68
  115. package/dist/esm/commands/query.js +152 -152
  116. package/dist/esm/commands/update.d.ts +29 -29
  117. package/dist/esm/commands/update.js +46 -46
  118. package/dist/esm/config/app.config.d.ts +6 -6
  119. package/dist/esm/config/app.config.js +5 -5
  120. package/dist/esm/config/error.config.d.ts +3 -3
  121. package/dist/esm/config/error.config.js +13 -13
  122. package/dist/esm/const/code.d.ts +30 -30
  123. package/dist/esm/const/code.js +30 -30
  124. package/dist/esm/constant.d.ts +51 -51
  125. package/dist/esm/constant.js +65 -65
  126. package/dist/esm/document.d.ts +11 -11
  127. package/dist/esm/document.js +250 -261
  128. package/dist/esm/geo/index.d.ts +6 -6
  129. package/dist/esm/geo/index.js +6 -6
  130. package/dist/esm/geo/interface.d.ts +24 -24
  131. package/dist/esm/geo/lineString.d.ts +19 -19
  132. package/dist/esm/geo/lineString.js +83 -83
  133. package/dist/esm/geo/multiLineString.d.ts +18 -18
  134. package/dist/esm/geo/multiLineString.js +92 -92
  135. package/dist/esm/geo/multiPoint.d.ts +18 -18
  136. package/dist/esm/geo/multiPoint.js +76 -76
  137. package/dist/esm/geo/multiPolygon.d.ts +18 -18
  138. package/dist/esm/geo/multiPolygon.js +119 -119
  139. package/dist/esm/geo/point.d.ts +19 -19
  140. package/dist/esm/geo/point.js +47 -47
  141. package/dist/esm/geo/polygon.d.ts +19 -19
  142. package/dist/esm/geo/polygon.js +106 -106
  143. package/dist/esm/helper/symbol.d.ts +14 -14
  144. package/dist/esm/helper/symbol.js +14 -14
  145. package/dist/esm/index.d.ts +33 -32
  146. package/dist/esm/index.js +41 -41
  147. package/dist/esm/lib/util.d.ts +1 -1
  148. package/dist/esm/lib/util.js +23 -23
  149. package/dist/esm/operator-map.d.ts +4 -4
  150. package/dist/esm/operator-map.js +20 -20
  151. package/dist/esm/query.d.ts +22 -22
  152. package/dist/esm/query.js +249 -260
  153. package/dist/esm/realtime/error.d.ts +7 -7
  154. package/dist/esm/realtime/error.js +8 -25
  155. package/dist/esm/realtime/listener.d.ts +14 -14
  156. package/dist/esm/realtime/listener.js +14 -16
  157. package/dist/esm/realtime/message.d.ts +3 -3
  158. package/dist/esm/realtime/message.js +6 -7
  159. package/dist/esm/realtime/snapshot.d.ts +16 -16
  160. package/dist/esm/realtime/snapshot.js +39 -41
  161. package/dist/esm/realtime/virtual-websocket-client.d.ts +63 -63
  162. package/dist/esm/realtime/virtual-websocket-client.js +733 -988
  163. package/dist/esm/realtime/websocket-client.d.ts +78 -78
  164. package/dist/esm/realtime/websocket-client.js +564 -786
  165. package/dist/esm/realtime/ws-event.d.ts +126 -126
  166. package/dist/esm/realtime/ws-event.js +137 -137
  167. package/dist/esm/regexp/index.d.ts +14 -14
  168. package/dist/esm/regexp/index.js +29 -29
  169. package/dist/esm/serializer/common.d.ts +11 -11
  170. package/dist/esm/serializer/common.js +113 -113
  171. package/dist/esm/serializer/datatype.d.ts +7 -7
  172. package/dist/esm/serializer/datatype.js +122 -122
  173. package/dist/esm/serializer/query.d.ts +7 -7
  174. package/dist/esm/serializer/query.js +229 -229
  175. package/dist/esm/serializer/update.d.ts +15 -15
  176. package/dist/esm/serializer/update.js +139 -139
  177. package/dist/esm/serverDate/index.d.ts +13 -13
  178. package/dist/esm/serverDate/index.js +26 -26
  179. package/dist/esm/transaction/collection.d.ts +7 -7
  180. package/dist/esm/transaction/collection.js +44 -44
  181. package/dist/esm/transaction/document.d.ts +27 -27
  182. package/dist/esm/transaction/document.js +203 -203
  183. package/dist/esm/transaction/index.d.ts +30 -30
  184. package/dist/esm/transaction/index.js +210 -210
  185. package/dist/esm/transaction/query.d.ts +5 -5
  186. package/dist/esm/transaction/query.js +8 -8
  187. package/dist/esm/transaction.d.ts +42 -42
  188. package/dist/esm/transaction.js +121 -121
  189. package/dist/esm/typings/index.d.ts +40 -40
  190. package/dist/esm/typings/realtime.d.ts +219 -219
  191. package/dist/esm/util.d.ts +9 -9
  192. package/dist/esm/util.js +142 -142
  193. package/dist/esm/utils/error.d.ts +37 -37
  194. package/dist/esm/utils/error.js +82 -82
  195. package/dist/esm/utils/symbol.d.ts +8 -8
  196. package/dist/esm/utils/symbol.js +55 -55
  197. package/dist/esm/utils/type.d.ts +13 -13
  198. package/dist/esm/utils/type.js +20 -20
  199. package/dist/esm/utils/utils.d.ts +4 -2
  200. package/dist/esm/utils/utils.js +33 -12
  201. package/dist/esm/validate.d.ts +1 -1
  202. package/dist/esm/validate.js +57 -57
  203. package/package.json +4 -1
  204. package/src/aggregate.ts +11 -0
  205. package/src/document.ts +3 -15
  206. package/src/index.ts +2 -0
  207. package/src/query.ts +4 -16
  208. package/src/utils/utils.ts +28 -0
  209. package/.DS_Store +0 -0
  210. package/src/.DS_Store +0 -0
  211. package/src/realtime/error.ts +0 -19
  212. package/src/realtime/listener.ts +0 -35
  213. package/src/realtime/message.ts +0 -14
  214. package/src/realtime/snapshot.ts +0 -60
  215. package/src/realtime/virtual-websocket-client.ts +0 -1195
  216. package/src/realtime/websocket-client.ts +0 -995
  217. package/src/realtime/ws-event.ts +0 -163
  218. package/src/regexp/.DS_Store +0 -0
@@ -1,786 +1,564 @@
1
- var __assign = (this && this.__assign) || function () {
2
- __assign = Object.assign || function(t) {
3
- for (var s, i = 1, n = arguments.length; i < n; i++) {
4
- s = arguments[i];
5
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
- t[p] = s[p];
7
- }
8
- return t;
9
- };
10
- return __assign.apply(this, arguments);
11
- };
12
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
13
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
14
- return new (P || (P = Promise))(function (resolve, reject) {
15
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
16
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
17
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
18
- step((generator = generator.apply(thisArg, _arguments || [])).next());
19
- });
20
- };
21
- var __generator = (this && this.__generator) || function (thisArg, body) {
22
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
23
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
24
- function verb(n) { return function (v) { return step([n, v]); }; }
25
- function step(op) {
26
- if (f) throw new TypeError("Generator is already executing.");
27
- while (_) try {
28
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
29
- if (y = 0, t) op = [op[0] & 2, t.value];
30
- switch (op[0]) {
31
- case 0: case 1: t = op; break;
32
- case 4: _.label++; return { value: op[1], done: false };
33
- case 5: _.label++; y = op[1]; op = [0]; continue;
34
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
35
- default:
36
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
37
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
38
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
39
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
40
- if (t[2]) _.ops.pop();
41
- _.trys.pop(); continue;
42
- }
43
- op = body.call(thisArg, _);
44
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
45
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
46
- }
47
- };
48
- var __values = (this && this.__values) || function(o) {
49
- var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
50
- if (m) return m.call(o);
51
- if (o && typeof o.length === "number") return {
52
- next: function () {
53
- if (o && i >= o.length) o = void 0;
54
- return { value: o && o[i++], done: !o };
55
- }
56
- };
57
- throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
58
- };
59
- var __read = (this && this.__read) || function (o, n) {
60
- var m = typeof Symbol === "function" && o[Symbol.iterator];
61
- if (!m) return o;
62
- var i = m.call(o), r, ar = [], e;
63
- try {
64
- while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
65
- }
66
- catch (error) { e = { error: error }; }
67
- finally {
68
- try {
69
- if (r && !r.done && (m = i["return"])) m.call(i);
70
- }
71
- finally { if (e) throw e.error; }
72
- }
73
- return ar;
74
- };
75
- import { VirtualWebSocketClient } from './virtual-websocket-client';
76
- import { sleep } from '../utils/utils';
77
- import { genRequestId } from './message';
78
- import { CLOSE_EVENT_CODE, CLOSE_EVENT_CODE_INFO, getWSCloseError } from './ws-event';
79
- import { CloudSDKError, TimeoutError } from '../utils/error';
80
- import { RealtimeErrorMessageError } from './error';
81
- import { ERR_CODE } from '../config/error.config';
82
- import { Db } from '../';
83
- var WS_READY_STATE = {
84
- CONNECTING: 0,
85
- OPEN: 1,
86
- CLOSING: 2,
87
- CLOSED: 3
88
- };
89
- var MAX_RTT_OBSERVED = 3;
90
- var DEFAULT_EXPECTED_EVENT_WAIT_TIME = 5000;
91
- var DEFAULT_UNTRUSTED_RTT_THRESHOLD = 10000;
92
- var DEFAULT_MAX_RECONNECT = 5;
93
- var DEFAULT_WS_RECONNECT_INTERVAL = 10000;
94
- var DEFAULT_PING_FAIL_TOLERANCE = 2;
95
- var DEFAULT_PONG_MISS_TOLERANCE = 2;
96
- var DEFAULT_LOGIN_TIMEOUT = 5000;
97
- var RealtimeWebSocketClient = (function () {
98
- function RealtimeWebSocketClient(options) {
99
- var _this = this;
100
- this._virtualWSClient = new Set();
101
- this._queryIdClientMap = new Map();
102
- this._watchIdClientMap = new Map();
103
- this._pingFailed = 0;
104
- this._pongMissed = 0;
105
- this._logins = new Map();
106
- this._wsReadySubsribers = [];
107
- this._wsResponseWait = new Map();
108
- this._rttObserved = [];
109
- this.initWebSocketConnection = function (reconnect, availableRetries) {
110
- if (availableRetries === void 0) { availableRetries = _this._maxReconnect; }
111
- return __awaiter(_this, void 0, void 0, function () {
112
- var e_1;
113
- var _this = this;
114
- return __generator(this, function (_a) {
115
- switch (_a.label) {
116
- case 0:
117
- if (reconnect && this._reconnectState) {
118
- return [2];
119
- }
120
- if (reconnect) {
121
- this._reconnectState = true;
122
- }
123
- if (this._wsInitPromise) {
124
- return [2, this._wsInitPromise];
125
- }
126
- if (reconnect) {
127
- this.pauseClients();
128
- }
129
- this.close(CLOSE_EVENT_CODE.ReconnectWebSocket);
130
- this._wsInitPromise = new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
131
- var wsSign_1, e_2, isConnected;
132
- var _this = this;
133
- return __generator(this, function (_a) {
134
- switch (_a.label) {
135
- case 0:
136
- _a.trys.push([0, 6, , 11]);
137
- return [4, this.getWsSign()];
138
- case 1:
139
- wsSign_1 = _a.sent();
140
- return [4, new Promise(function (success) {
141
- var url = wsSign_1.wsUrl || 'wss://tcb-ws.tencentcloudapi.com';
142
- _this._ws = Db.wsClass ? new Db.wsClass(url) : new WebSocket(url);
143
- success();
144
- })];
145
- case 2:
146
- _a.sent();
147
- if (!this._ws.connect) return [3, 4];
148
- return [4, this._ws.connect()];
149
- case 3:
150
- _a.sent();
151
- _a.label = 4;
152
- case 4: return [4, this.initWebSocketEvent()];
153
- case 5:
154
- _a.sent();
155
- resolve();
156
- if (reconnect) {
157
- this.resumeClients();
158
- this._reconnectState = false;
159
- }
160
- return [3, 11];
161
- case 6:
162
- e_2 = _a.sent();
163
- console.error('[realtime] initWebSocketConnection connect fail', e_2);
164
- if (!(availableRetries > 0)) return [3, 9];
165
- isConnected = true;
166
- this._wsInitPromise = undefined;
167
- if (!isConnected) return [3, 8];
168
- return [4, sleep(this._reconnectInterval)];
169
- case 7:
170
- _a.sent();
171
- if (reconnect) {
172
- this._reconnectState = false;
173
- }
174
- _a.label = 8;
175
- case 8:
176
- resolve(this.initWebSocketConnection(reconnect, availableRetries - 1));
177
- return [3, 10];
178
- case 9:
179
- reject(e_2);
180
- if (reconnect) {
181
- this.closeAllClients(new CloudSDKError({
182
- errCode: ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_RECONNECT_WATCH_FAIL,
183
- errMsg: e_2
184
- }));
185
- }
186
- _a.label = 10;
187
- case 10: return [3, 11];
188
- case 11: return [2];
189
- }
190
- });
191
- }); });
192
- _a.label = 1;
193
- case 1:
194
- _a.trys.push([1, 3, 4, 5]);
195
- return [4, this._wsInitPromise];
196
- case 2:
197
- _a.sent();
198
- this._wsReadySubsribers.forEach(function (_a) {
199
- var resolve = _a.resolve;
200
- return resolve();
201
- });
202
- return [3, 5];
203
- case 3:
204
- e_1 = _a.sent();
205
- this._wsReadySubsribers.forEach(function (_a) {
206
- var reject = _a.reject;
207
- return reject();
208
- });
209
- return [3, 5];
210
- case 4:
211
- this._wsInitPromise = undefined;
212
- this._wsReadySubsribers = [];
213
- return [7];
214
- case 5: return [2];
215
- }
216
- });
217
- });
218
- };
219
- this.initWebSocketEvent = function () {
220
- return new Promise(function (resolve, reject) {
221
- if (!_this._ws) {
222
- throw new Error('can not initWebSocketEvent, ws not exists');
223
- }
224
- var wsOpened = false;
225
- _this._ws.onopen = function (event) {
226
- console.warn('[realtime] ws event: open', event);
227
- wsOpened = true;
228
- resolve();
229
- };
230
- _this._ws.onerror = function (event) {
231
- _this._logins = new Map();
232
- if (!wsOpened) {
233
- console.error('[realtime] ws open failed with ws event: error', event);
234
- reject(event);
235
- }
236
- else {
237
- console.error('[realtime] ws event: error', event);
238
- _this.clearHeartbeat();
239
- _this._virtualWSClient.forEach(function (client) {
240
- return client.closeWithError(new CloudSDKError({
241
- errCode: ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_WEBSOCKET_CONNECTION_ERROR,
242
- errMsg: event
243
- }));
244
- });
245
- }
246
- };
247
- _this._ws.onclose = function (closeEvent) {
248
- console.warn('[realtime] ws event: close', closeEvent);
249
- _this._logins = new Map();
250
- _this.clearHeartbeat();
251
- switch (closeEvent.code) {
252
- case CLOSE_EVENT_CODE.ReconnectWebSocket: {
253
- break;
254
- }
255
- case CLOSE_EVENT_CODE.NoRealtimeListeners: {
256
- break;
257
- }
258
- case CLOSE_EVENT_CODE.HeartbeatPingError:
259
- case CLOSE_EVENT_CODE.HeartbeatPongTimeoutError:
260
- case CLOSE_EVENT_CODE.NormalClosure:
261
- case CLOSE_EVENT_CODE.AbnormalClosure: {
262
- if (_this._maxReconnect > 0) {
263
- _this.initWebSocketConnection(true, _this._maxReconnect);
264
- }
265
- else {
266
- _this.closeAllClients(getWSCloseError(closeEvent.code));
267
- }
268
- break;
269
- }
270
- case CLOSE_EVENT_CODE.NoAuthentication: {
271
- _this.closeAllClients(getWSCloseError(closeEvent.code, closeEvent.reason));
272
- break;
273
- }
274
- default: {
275
- if (_this._maxReconnect > 0) {
276
- _this.initWebSocketConnection(true, _this._maxReconnect);
277
- }
278
- else {
279
- _this.closeAllClients(getWSCloseError(closeEvent.code));
280
- }
281
- }
282
- }
283
- };
284
- _this._ws.onmessage = function (res) {
285
- var e_3, _a;
286
- var rawMsg = res.data;
287
- _this.heartbeat();
288
- var msg;
289
- try {
290
- msg = JSON.parse(rawMsg);
291
- }
292
- catch (e) {
293
- throw new Error("[realtime] onMessage parse res.data error: " + e);
294
- }
295
- if (msg.msgType === 'ERROR') {
296
- var virtualWatch_1 = null;
297
- _this._virtualWSClient.forEach(function (item) {
298
- if (item.watchId === msg.watchId) {
299
- virtualWatch_1 = item;
300
- }
301
- });
302
- if (virtualWatch_1) {
303
- virtualWatch_1.listener.onError(msg);
304
- }
305
- }
306
- var responseWaitSpec = _this._wsResponseWait.get(msg.requestId);
307
- if (responseWaitSpec) {
308
- try {
309
- if (msg.msgType === 'ERROR') {
310
- responseWaitSpec.reject(new RealtimeErrorMessageError(msg));
311
- }
312
- else {
313
- responseWaitSpec.resolve(msg);
314
- }
315
- }
316
- catch (e) {
317
- console.error('ws onMessage responseWaitSpec.resolve(msg) errored:', e);
318
- }
319
- finally {
320
- _this._wsResponseWait.delete(msg.requestId);
321
- }
322
- if (responseWaitSpec.skipOnMessage) {
323
- return;
324
- }
325
- }
326
- if (msg.msgType === 'PONG') {
327
- if (_this._lastPingSendTS) {
328
- var rtt = Date.now() - _this._lastPingSendTS;
329
- if (rtt > DEFAULT_UNTRUSTED_RTT_THRESHOLD) {
330
- console.warn("[realtime] untrusted rtt observed: " + rtt);
331
- return;
332
- }
333
- if (_this._rttObserved.length >= MAX_RTT_OBSERVED) {
334
- _this._rttObserved.splice(0, _this._rttObserved.length - MAX_RTT_OBSERVED + 1);
335
- }
336
- _this._rttObserved.push(rtt);
337
- }
338
- return;
339
- }
340
- var client = msg.watchId && _this._watchIdClientMap.get(msg.watchId);
341
- if (client) {
342
- client.onMessage(msg);
343
- }
344
- else {
345
- console.error("[realtime] no realtime listener found responsible for watchId " + msg.watchId + ": ", msg);
346
- switch (msg.msgType) {
347
- case 'INIT_EVENT':
348
- case 'NEXT_EVENT':
349
- case 'CHECK_EVENT': {
350
- client = _this._queryIdClientMap.get(msg.msgData.queryID);
351
- if (client) {
352
- client.onMessage(msg);
353
- }
354
- break;
355
- }
356
- default: {
357
- try {
358
- for (var _b = __values(_this._watchIdClientMap), _c = _b.next(); !_c.done; _c = _b.next()) {
359
- var _d = __read(_c.value, 2), client_1 = _d[1];
360
- client_1.onMessage(msg);
361
- break;
362
- }
363
- }
364
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
365
- finally {
366
- try {
367
- if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
368
- }
369
- finally { if (e_3) throw e_3.error; }
370
- }
371
- }
372
- }
373
- }
374
- };
375
- _this.heartbeat();
376
- });
377
- };
378
- this.isWSConnected = function () {
379
- return Boolean(_this._ws && _this._ws.readyState === WS_READY_STATE.OPEN);
380
- };
381
- this.onceWSConnected = function () { return __awaiter(_this, void 0, void 0, function () {
382
- var _this = this;
383
- return __generator(this, function (_a) {
384
- if (this.isWSConnected()) {
385
- return [2];
386
- }
387
- if (this._wsInitPromise) {
388
- return [2, this._wsInitPromise];
389
- }
390
- return [2, new Promise(function (resolve, reject) {
391
- _this._wsReadySubsribers.push({
392
- resolve: resolve,
393
- reject: reject
394
- });
395
- })];
396
- });
397
- }); };
398
- this.webLogin = function (envId, refresh) { return __awaiter(_this, void 0, void 0, function () {
399
- var loginInfo_1, emptyEnvLoginInfo, promise, loginInfo, loginStartTS, loginResult, curLoginInfo, e_4;
400
- var _this = this;
401
- return __generator(this, function (_a) {
402
- switch (_a.label) {
403
- case 0:
404
- if (!refresh) {
405
- if (envId) {
406
- loginInfo_1 = this._logins.get(envId);
407
- if (loginInfo_1) {
408
- if (loginInfo_1.loggedIn && loginInfo_1.loginResult) {
409
- return [2, loginInfo_1.loginResult];
410
- }
411
- else if (loginInfo_1.loggingInPromise) {
412
- return [2, loginInfo_1.loggingInPromise];
413
- }
414
- }
415
- }
416
- else {
417
- emptyEnvLoginInfo = this._logins.get('');
418
- if (emptyEnvLoginInfo && emptyEnvLoginInfo.loggingInPromise) {
419
- return [2, emptyEnvLoginInfo.loggingInPromise];
420
- }
421
- }
422
- }
423
- promise = new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
424
- var wsSign, msgData, loginMsg, loginResMsg, e_5;
425
- return __generator(this, function (_a) {
426
- switch (_a.label) {
427
- case 0:
428
- _a.trys.push([0, 3, , 4]);
429
- return [4, this.getWsSign()];
430
- case 1:
431
- wsSign = _a.sent();
432
- msgData = {
433
- envId: wsSign.envId || '',
434
- accessToken: '',
435
- referrer: 'web',
436
- sdkVersion: '',
437
- dataVersion: Db.dataVersion || ''
438
- };
439
- loginMsg = {
440
- watchId: undefined,
441
- requestId: genRequestId(),
442
- msgType: 'LOGIN',
443
- msgData: msgData,
444
- exMsgData: {
445
- runtime: Db.runtime,
446
- signStr: wsSign.signStr,
447
- secretVersion: wsSign.secretVersion
448
- }
449
- };
450
- return [4, this.send({
451
- msg: loginMsg,
452
- waitResponse: true,
453
- skipOnMessage: true,
454
- timeout: DEFAULT_LOGIN_TIMEOUT
455
- })];
456
- case 2:
457
- loginResMsg = _a.sent();
458
- if (!loginResMsg.msgData.code) {
459
- resolve({
460
- envId: wsSign.envId
461
- });
462
- }
463
- else {
464
- reject(new Error(loginResMsg.msgData.code + " " + loginResMsg.msgData.message));
465
- }
466
- return [3, 4];
467
- case 3:
468
- e_5 = _a.sent();
469
- reject(e_5);
470
- return [3, 4];
471
- case 4: return [2];
472
- }
473
- });
474
- }); });
475
- loginInfo = envId && this._logins.get(envId);
476
- loginStartTS = Date.now();
477
- if (loginInfo) {
478
- loginInfo.loggedIn = false;
479
- loginInfo.loggingInPromise = promise;
480
- loginInfo.loginStartTS = loginStartTS;
481
- }
482
- else {
483
- loginInfo = {
484
- loggedIn: false,
485
- loggingInPromise: promise,
486
- loginStartTS: loginStartTS
487
- };
488
- this._logins.set(envId || '', loginInfo);
489
- }
490
- _a.label = 1;
491
- case 1:
492
- _a.trys.push([1, 3, , 4]);
493
- return [4, promise];
494
- case 2:
495
- loginResult = _a.sent();
496
- curLoginInfo = envId && this._logins.get(envId);
497
- if (curLoginInfo &&
498
- curLoginInfo === loginInfo &&
499
- curLoginInfo.loginStartTS === loginStartTS) {
500
- loginInfo.loggedIn = true;
501
- loginInfo.loggingInPromise = undefined;
502
- loginInfo.loginStartTS = undefined;
503
- loginInfo.loginResult = loginResult;
504
- return [2, loginResult];
505
- }
506
- else if (curLoginInfo) {
507
- if (curLoginInfo.loggedIn && curLoginInfo.loginResult) {
508
- return [2, curLoginInfo.loginResult];
509
- }
510
- else if (curLoginInfo.loggingInPromise) {
511
- return [2, curLoginInfo.loggingInPromise];
512
- }
513
- else {
514
- throw new Error('ws unexpected login info');
515
- }
516
- }
517
- else {
518
- throw new Error('ws login info reset');
519
- }
520
- return [3, 4];
521
- case 3:
522
- e_4 = _a.sent();
523
- loginInfo.loggedIn = false;
524
- loginInfo.loggingInPromise = undefined;
525
- loginInfo.loginStartTS = undefined;
526
- loginInfo.loginResult = undefined;
527
- throw e_4;
528
- case 4: return [2];
529
- }
530
- });
531
- }); };
532
- this.getWsSign = function () { return __awaiter(_this, void 0, void 0, function () {
533
- var expiredTs, res, _a, signStr, wsUrl, secretVersion, envId;
534
- return __generator(this, function (_b) {
535
- switch (_b.label) {
536
- case 0:
537
- if (this._wsSign && this._wsSign.expiredTs > Date.now()) {
538
- return [2, this._wsSign];
539
- }
540
- expiredTs = Date.now() + 60000;
541
- return [4, this._context.appConfig.request.send('auth.wsWebSign', { runtime: Db.runtime })];
542
- case 1:
543
- res = _b.sent();
544
- if (res.code) {
545
- throw new Error("[tcb-js-sdk] \u83B7\u53D6\u5B9E\u65F6\u6570\u636E\u63A8\u9001\u767B\u5F55\u7968\u636E\u5931\u8D25: " + res.code);
546
- }
547
- if (res.data) {
548
- _a = res.data, signStr = _a.signStr, wsUrl = _a.wsUrl, secretVersion = _a.secretVersion, envId = _a.envId;
549
- return [2, {
550
- signStr: signStr,
551
- wsUrl: wsUrl,
552
- secretVersion: secretVersion,
553
- envId: envId,
554
- expiredTs: expiredTs
555
- }];
556
- }
557
- else {
558
- throw new Error('[tcb-js-sdk] 获取实时数据推送登录票据失败');
559
- }
560
- return [2];
561
- }
562
- });
563
- }); };
564
- this.getWaitExpectedTimeoutLength = function () {
565
- if (!_this._rttObserved.length) {
566
- return DEFAULT_EXPECTED_EVENT_WAIT_TIME;
567
- }
568
- return ((_this._rttObserved.reduce(function (acc, cur) { return acc + cur; }) /
569
- _this._rttObserved.length) *
570
- 1.5);
571
- };
572
- this.ping = function () { return __awaiter(_this, void 0, void 0, function () {
573
- var msg;
574
- return __generator(this, function (_a) {
575
- switch (_a.label) {
576
- case 0:
577
- msg = {
578
- watchId: undefined,
579
- requestId: genRequestId(),
580
- msgType: 'PING',
581
- msgData: null
582
- };
583
- return [4, this.send({
584
- msg: msg
585
- })];
586
- case 1:
587
- _a.sent();
588
- return [2];
589
- }
590
- });
591
- }); };
592
- this.send = function (opts) { return __awaiter(_this, void 0, void 0, function () {
593
- var _this = this;
594
- return __generator(this, function (_a) {
595
- return [2, new Promise(function (_resolve, _reject) { return __awaiter(_this, void 0, void 0, function () {
596
- var timeoutId, _hasResolved, _hasRejected, resolve, reject, err_1, e_6;
597
- var _this = this;
598
- return __generator(this, function (_a) {
599
- switch (_a.label) {
600
- case 0:
601
- _hasResolved = false;
602
- _hasRejected = false;
603
- resolve = function (value) {
604
- _hasResolved = true;
605
- timeoutId && clearTimeout(timeoutId);
606
- _resolve(value);
607
- };
608
- reject = function (error) {
609
- _hasRejected = true;
610
- timeoutId && clearTimeout(timeoutId);
611
- _reject(error);
612
- };
613
- if (opts.timeout) {
614
- timeoutId = setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
615
- return __generator(this, function (_a) {
616
- switch (_a.label) {
617
- case 0:
618
- if (!(!_hasResolved || !_hasRejected)) return [3, 2];
619
- return [4, sleep(0)];
620
- case 1:
621
- _a.sent();
622
- if (!_hasResolved || !_hasRejected) {
623
- reject(new TimeoutError('wsclient.send timedout'));
624
- }
625
- _a.label = 2;
626
- case 2: return [2];
627
- }
628
- });
629
- }); }, opts.timeout);
630
- }
631
- _a.label = 1;
632
- case 1:
633
- _a.trys.push([1, 8, , 9]);
634
- if (!this._wsInitPromise) return [3, 3];
635
- return [4, this._wsInitPromise];
636
- case 2:
637
- _a.sent();
638
- _a.label = 3;
639
- case 3:
640
- if (!this._ws) {
641
- reject(new Error('invalid state: ws connection not exists, can not send message'));
642
- return [2];
643
- }
644
- if (this._ws.readyState !== WS_READY_STATE.OPEN) {
645
- reject(new Error("ws readyState invalid: " + this._ws.readyState + ", can not send message"));
646
- return [2];
647
- }
648
- if (opts.waitResponse) {
649
- this._wsResponseWait.set(opts.msg.requestId, {
650
- resolve: resolve,
651
- reject: reject,
652
- skipOnMessage: opts.skipOnMessage
653
- });
654
- }
655
- _a.label = 4;
656
- case 4:
657
- _a.trys.push([4, 6, , 7]);
658
- return [4, this._ws.send(JSON.stringify(opts.msg))];
659
- case 5:
660
- _a.sent();
661
- if (!opts.waitResponse) {
662
- resolve();
663
- }
664
- return [3, 7];
665
- case 6:
666
- err_1 = _a.sent();
667
- if (err_1) {
668
- reject(err_1);
669
- if (opts.waitResponse) {
670
- this._wsResponseWait.delete(opts.msg.requestId);
671
- }
672
- }
673
- return [3, 7];
674
- case 7: return [3, 9];
675
- case 8:
676
- e_6 = _a.sent();
677
- reject(e_6);
678
- return [3, 9];
679
- case 9: return [2];
680
- }
681
- });
682
- }); })];
683
- });
684
- }); };
685
- this.closeAllClients = function (error) {
686
- _this._virtualWSClient.forEach(function (client) {
687
- client.closeWithError(error);
688
- });
689
- };
690
- this.pauseClients = function (clients) {
691
- ;
692
- (clients || _this._virtualWSClient).forEach(function (client) {
693
- client.pause();
694
- });
695
- };
696
- this.resumeClients = function (clients) {
697
- ;
698
- (clients || _this._virtualWSClient).forEach(function (client) {
699
- client.resume();
700
- });
701
- };
702
- this.onWatchStart = function (client, queryID) {
703
- _this._queryIdClientMap.set(queryID, client);
704
- };
705
- this.onWatchClose = function (client, queryID) {
706
- if (queryID) {
707
- _this._queryIdClientMap.delete(queryID);
708
- }
709
- _this._watchIdClientMap.delete(client.watchId);
710
- _this._virtualWSClient.delete(client);
711
- if (!_this._virtualWSClient.size) {
712
- _this.close(CLOSE_EVENT_CODE.NoRealtimeListeners);
713
- }
714
- };
715
- this._maxReconnect = options.maxReconnect || DEFAULT_MAX_RECONNECT;
716
- this._reconnectInterval =
717
- options.reconnectInterval || DEFAULT_WS_RECONNECT_INTERVAL;
718
- this._context = options.context;
719
- }
720
- RealtimeWebSocketClient.prototype.heartbeat = function (immediate) {
721
- var _this = this;
722
- this.clearHeartbeat();
723
- this._pingTimeoutId = setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
724
- var e_7;
725
- var _this = this;
726
- return __generator(this, function (_a) {
727
- switch (_a.label) {
728
- case 0:
729
- _a.trys.push([0, 2, , 3]);
730
- if (!this._ws || this._ws.readyState !== WS_READY_STATE.OPEN) {
731
- return [2];
732
- }
733
- this._lastPingSendTS = Date.now();
734
- return [4, this.ping()];
735
- case 1:
736
- _a.sent();
737
- this._pingFailed = 0;
738
- this._pongTimeoutId = setTimeout(function () {
739
- console.error('pong timed out');
740
- if (_this._pongMissed < DEFAULT_PONG_MISS_TOLERANCE) {
741
- _this._pongMissed++;
742
- _this.heartbeat(true);
743
- }
744
- else {
745
- _this.initWebSocketConnection(true);
746
- }
747
- }, this._context.appConfig.realtimePongWaitTimeout);
748
- return [3, 3];
749
- case 2:
750
- e_7 = _a.sent();
751
- if (this._pingFailed < DEFAULT_PING_FAIL_TOLERANCE) {
752
- this._pingFailed++;
753
- this.heartbeat();
754
- }
755
- else {
756
- this.close(CLOSE_EVENT_CODE.HeartbeatPingError);
757
- }
758
- return [3, 3];
759
- case 3: return [2];
760
- }
761
- });
762
- }); }, immediate ? 0 : this._context.appConfig.realtimePingInterval);
763
- };
764
- RealtimeWebSocketClient.prototype.clearHeartbeat = function () {
765
- this._pingTimeoutId && clearTimeout(this._pingTimeoutId);
766
- this._pongTimeoutId && clearTimeout(this._pongTimeoutId);
767
- };
768
- RealtimeWebSocketClient.prototype.close = function (code) {
769
- this.clearHeartbeat();
770
- if (this._ws) {
771
- this._ws.close(code, CLOSE_EVENT_CODE_INFO[code].name);
772
- this._ws = undefined;
773
- }
774
- };
775
- RealtimeWebSocketClient.prototype.watch = function (options) {
776
- if (!this._ws && !this._wsInitPromise) {
777
- this.initWebSocketConnection(false);
778
- }
779
- var virtualClient = new VirtualWebSocketClient(__assign(__assign({}, options), { send: this.send, login: this.webLogin, isWSConnected: this.isWSConnected, onceWSConnected: this.onceWSConnected, getWaitExpectedTimeoutLength: this.getWaitExpectedTimeoutLength, onWatchStart: this.onWatchStart, onWatchClose: this.onWatchClose, debug: true }));
780
- this._virtualWSClient.add(virtualClient);
781
- this._watchIdClientMap.set(virtualClient.watchId, virtualClient);
782
- return virtualClient.listener;
783
- };
784
- return RealtimeWebSocketClient;
785
- }());
786
- export { RealtimeWebSocketClient };
1
+ import { VirtualWebSocketClient } from './virtual-websocket-client';
2
+ import { sleep } from '../utils/utils';
3
+ import { genRequestId } from './message';
4
+ import { CLOSE_EVENT_CODE, CLOSE_EVENT_CODE_INFO, getWSCloseError } from './ws-event';
5
+ import { CloudSDKError, TimeoutError } from '../utils/error';
6
+ import { RealtimeErrorMessageError } from './error';
7
+ import { ERR_CODE } from '../config/error.config';
8
+ import { Db } from '../';
9
+ const WS_READY_STATE = {
10
+ CONNECTING: 0,
11
+ OPEN: 1,
12
+ CLOSING: 2,
13
+ CLOSED: 3
14
+ };
15
+ const MAX_RTT_OBSERVED = 3;
16
+ const DEFAULT_EXPECTED_EVENT_WAIT_TIME = 5000;
17
+ const DEFAULT_UNTRUSTED_RTT_THRESHOLD = 10000;
18
+ const DEFAULT_MAX_RECONNECT = 5;
19
+ const DEFAULT_WS_RECONNECT_INTERVAL = 10000;
20
+ const DEFAULT_PING_FAIL_TOLERANCE = 2;
21
+ const DEFAULT_PONG_MISS_TOLERANCE = 2;
22
+ const DEFAULT_LOGIN_TIMEOUT = 5000;
23
+ export class RealtimeWebSocketClient {
24
+ constructor(options) {
25
+ this._virtualWSClient = new Set();
26
+ this._queryIdClientMap = new Map();
27
+ this._watchIdClientMap = new Map();
28
+ this._pingFailed = 0;
29
+ this._pongMissed = 0;
30
+ this._logins = new Map();
31
+ this._wsReadySubsribers = [];
32
+ this._wsResponseWait = new Map();
33
+ this._rttObserved = [];
34
+ this.initWebSocketConnection = async (reconnect, availableRetries = this._maxReconnect) => {
35
+ if (reconnect && this._reconnectState) {
36
+ return;
37
+ }
38
+ if (reconnect) {
39
+ this._reconnectState = true;
40
+ }
41
+ if (this._wsInitPromise) {
42
+ return this._wsInitPromise;
43
+ }
44
+ if (reconnect) {
45
+ this.pauseClients();
46
+ }
47
+ this.close(CLOSE_EVENT_CODE.ReconnectWebSocket);
48
+ this._wsInitPromise = new Promise(async (resolve, reject) => {
49
+ try {
50
+ const wsSign = await this.getWsSign();
51
+ await new Promise(success => {
52
+ const url = wsSign.wsUrl || 'wss://tcb-ws.tencentcloudapi.com';
53
+ this._ws = Db.wsClass ? new Db.wsClass(url) : new WebSocket(url);
54
+ success();
55
+ });
56
+ if (this._ws.connect) {
57
+ await this._ws.connect();
58
+ }
59
+ await this.initWebSocketEvent();
60
+ resolve();
61
+ if (reconnect) {
62
+ this.resumeClients();
63
+ this._reconnectState = false;
64
+ }
65
+ }
66
+ catch (e) {
67
+ console.error('[realtime] initWebSocketConnection connect fail', e);
68
+ if (availableRetries > 0) {
69
+ const isConnected = true;
70
+ this._wsInitPromise = undefined;
71
+ if (isConnected) {
72
+ await sleep(this._reconnectInterval);
73
+ if (reconnect) {
74
+ this._reconnectState = false;
75
+ }
76
+ }
77
+ resolve(this.initWebSocketConnection(reconnect, availableRetries - 1));
78
+ }
79
+ else {
80
+ reject(e);
81
+ if (reconnect) {
82
+ this.closeAllClients(new CloudSDKError({
83
+ errCode: ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_RECONNECT_WATCH_FAIL,
84
+ errMsg: e
85
+ }));
86
+ }
87
+ }
88
+ }
89
+ });
90
+ try {
91
+ await this._wsInitPromise;
92
+ this._wsReadySubsribers.forEach(({ resolve }) => resolve());
93
+ }
94
+ catch (e) {
95
+ this._wsReadySubsribers.forEach(({ reject }) => reject());
96
+ }
97
+ finally {
98
+ this._wsInitPromise = undefined;
99
+ this._wsReadySubsribers = [];
100
+ }
101
+ };
102
+ this.initWebSocketEvent = () => new Promise((resolve, reject) => {
103
+ if (!this._ws) {
104
+ throw new Error('can not initWebSocketEvent, ws not exists');
105
+ }
106
+ let wsOpened = false;
107
+ this._ws.onopen = event => {
108
+ console.warn('[realtime] ws event: open', event);
109
+ wsOpened = true;
110
+ resolve();
111
+ };
112
+ this._ws.onerror = event => {
113
+ this._logins = new Map();
114
+ if (!wsOpened) {
115
+ console.error('[realtime] ws open failed with ws event: error', event);
116
+ reject(event);
117
+ }
118
+ else {
119
+ console.error('[realtime] ws event: error', event);
120
+ this.clearHeartbeat();
121
+ this._virtualWSClient.forEach(client => client.closeWithError(new CloudSDKError({
122
+ errCode: ERR_CODE.SDK_DATABASE_REALTIME_LISTENER_WEBSOCKET_CONNECTION_ERROR,
123
+ errMsg: event
124
+ })));
125
+ }
126
+ };
127
+ this._ws.onclose = closeEvent => {
128
+ console.warn('[realtime] ws event: close', closeEvent);
129
+ this._logins = new Map();
130
+ this.clearHeartbeat();
131
+ switch (closeEvent.code) {
132
+ case CLOSE_EVENT_CODE.ReconnectWebSocket: {
133
+ break;
134
+ }
135
+ case CLOSE_EVENT_CODE.NoRealtimeListeners: {
136
+ break;
137
+ }
138
+ case CLOSE_EVENT_CODE.HeartbeatPingError:
139
+ case CLOSE_EVENT_CODE.HeartbeatPongTimeoutError:
140
+ case CLOSE_EVENT_CODE.NormalClosure:
141
+ case CLOSE_EVENT_CODE.AbnormalClosure: {
142
+ if (this._maxReconnect > 0) {
143
+ this.initWebSocketConnection(true, this._maxReconnect);
144
+ }
145
+ else {
146
+ this.closeAllClients(getWSCloseError(closeEvent.code));
147
+ }
148
+ break;
149
+ }
150
+ case CLOSE_EVENT_CODE.NoAuthentication: {
151
+ this.closeAllClients(getWSCloseError(closeEvent.code, closeEvent.reason));
152
+ break;
153
+ }
154
+ default: {
155
+ if (this._maxReconnect > 0) {
156
+ this.initWebSocketConnection(true, this._maxReconnect);
157
+ }
158
+ else {
159
+ this.closeAllClients(getWSCloseError(closeEvent.code));
160
+ }
161
+ }
162
+ }
163
+ };
164
+ this._ws.onmessage = res => {
165
+ const rawMsg = res.data;
166
+ this.heartbeat();
167
+ let msg;
168
+ try {
169
+ msg = JSON.parse(rawMsg);
170
+ }
171
+ catch (e) {
172
+ throw new Error(`[realtime] onMessage parse res.data error: ${e}`);
173
+ }
174
+ if (msg.msgType === 'ERROR') {
175
+ let virtualWatch = null;
176
+ this._virtualWSClient.forEach(item => {
177
+ if (item.watchId === msg.watchId) {
178
+ virtualWatch = item;
179
+ }
180
+ });
181
+ if (virtualWatch) {
182
+ virtualWatch.listener.onError(msg);
183
+ }
184
+ }
185
+ const responseWaitSpec = this._wsResponseWait.get(msg.requestId);
186
+ if (responseWaitSpec) {
187
+ try {
188
+ if (msg.msgType === 'ERROR') {
189
+ responseWaitSpec.reject(new RealtimeErrorMessageError(msg));
190
+ }
191
+ else {
192
+ responseWaitSpec.resolve(msg);
193
+ }
194
+ }
195
+ catch (e) {
196
+ console.error('ws onMessage responseWaitSpec.resolve(msg) errored:', e);
197
+ }
198
+ finally {
199
+ this._wsResponseWait.delete(msg.requestId);
200
+ }
201
+ if (responseWaitSpec.skipOnMessage) {
202
+ return;
203
+ }
204
+ }
205
+ if (msg.msgType === 'PONG') {
206
+ if (this._lastPingSendTS) {
207
+ const rtt = Date.now() - this._lastPingSendTS;
208
+ if (rtt > DEFAULT_UNTRUSTED_RTT_THRESHOLD) {
209
+ console.warn(`[realtime] untrusted rtt observed: ${rtt}`);
210
+ return;
211
+ }
212
+ if (this._rttObserved.length >= MAX_RTT_OBSERVED) {
213
+ this._rttObserved.splice(0, this._rttObserved.length - MAX_RTT_OBSERVED + 1);
214
+ }
215
+ this._rttObserved.push(rtt);
216
+ }
217
+ return;
218
+ }
219
+ let client = msg.watchId && this._watchIdClientMap.get(msg.watchId);
220
+ if (client) {
221
+ client.onMessage(msg);
222
+ }
223
+ else {
224
+ console.error(`[realtime] no realtime listener found responsible for watchId ${msg.watchId}: `, msg);
225
+ switch (msg.msgType) {
226
+ case 'INIT_EVENT':
227
+ case 'NEXT_EVENT':
228
+ case 'CHECK_EVENT': {
229
+ client = this._queryIdClientMap.get(msg.msgData.queryID);
230
+ if (client) {
231
+ client.onMessage(msg);
232
+ }
233
+ break;
234
+ }
235
+ default: {
236
+ for (const [, client] of this._watchIdClientMap) {
237
+ client.onMessage(msg);
238
+ break;
239
+ }
240
+ }
241
+ }
242
+ }
243
+ };
244
+ this.heartbeat();
245
+ });
246
+ this.isWSConnected = () => {
247
+ return Boolean(this._ws && this._ws.readyState === WS_READY_STATE.OPEN);
248
+ };
249
+ this.onceWSConnected = async () => {
250
+ if (this.isWSConnected()) {
251
+ return;
252
+ }
253
+ if (this._wsInitPromise) {
254
+ return this._wsInitPromise;
255
+ }
256
+ return new Promise((resolve, reject) => {
257
+ this._wsReadySubsribers.push({
258
+ resolve,
259
+ reject
260
+ });
261
+ });
262
+ };
263
+ this.webLogin = async (envId, refresh) => {
264
+ if (!refresh) {
265
+ if (envId) {
266
+ const loginInfo = this._logins.get(envId);
267
+ if (loginInfo) {
268
+ if (loginInfo.loggedIn && loginInfo.loginResult) {
269
+ return loginInfo.loginResult;
270
+ }
271
+ else if (loginInfo.loggingInPromise) {
272
+ return loginInfo.loggingInPromise;
273
+ }
274
+ }
275
+ }
276
+ else {
277
+ const emptyEnvLoginInfo = this._logins.get('');
278
+ if (emptyEnvLoginInfo && emptyEnvLoginInfo.loggingInPromise) {
279
+ return emptyEnvLoginInfo.loggingInPromise;
280
+ }
281
+ }
282
+ }
283
+ const promise = new Promise(async (resolve, reject) => {
284
+ try {
285
+ const wsSign = await this.getWsSign();
286
+ const msgData = {
287
+ envId: wsSign.envId || '',
288
+ accessToken: '',
289
+ referrer: 'web',
290
+ sdkVersion: '',
291
+ dataVersion: Db.dataVersion || ''
292
+ };
293
+ const loginMsg = {
294
+ watchId: undefined,
295
+ requestId: genRequestId(),
296
+ msgType: 'LOGIN',
297
+ msgData,
298
+ exMsgData: {
299
+ runtime: Db.runtime,
300
+ signStr: wsSign.signStr,
301
+ secretVersion: wsSign.secretVersion
302
+ }
303
+ };
304
+ const loginResMsg = await this.send({
305
+ msg: loginMsg,
306
+ waitResponse: true,
307
+ skipOnMessage: true,
308
+ timeout: DEFAULT_LOGIN_TIMEOUT
309
+ });
310
+ if (!loginResMsg.msgData.code) {
311
+ resolve({
312
+ envId: wsSign.envId
313
+ });
314
+ }
315
+ else {
316
+ reject(new Error(`${loginResMsg.msgData.code} ${loginResMsg.msgData.message}`));
317
+ }
318
+ }
319
+ catch (e) {
320
+ reject(e);
321
+ }
322
+ });
323
+ let loginInfo = envId && this._logins.get(envId);
324
+ const loginStartTS = Date.now();
325
+ if (loginInfo) {
326
+ loginInfo.loggedIn = false;
327
+ loginInfo.loggingInPromise = promise;
328
+ loginInfo.loginStartTS = loginStartTS;
329
+ }
330
+ else {
331
+ loginInfo = {
332
+ loggedIn: false,
333
+ loggingInPromise: promise,
334
+ loginStartTS
335
+ };
336
+ this._logins.set(envId || '', loginInfo);
337
+ }
338
+ try {
339
+ const loginResult = await promise;
340
+ const curLoginInfo = envId && this._logins.get(envId);
341
+ if (curLoginInfo &&
342
+ curLoginInfo === loginInfo &&
343
+ curLoginInfo.loginStartTS === loginStartTS) {
344
+ loginInfo.loggedIn = true;
345
+ loginInfo.loggingInPromise = undefined;
346
+ loginInfo.loginStartTS = undefined;
347
+ loginInfo.loginResult = loginResult;
348
+ return loginResult;
349
+ }
350
+ else if (curLoginInfo) {
351
+ if (curLoginInfo.loggedIn && curLoginInfo.loginResult) {
352
+ return curLoginInfo.loginResult;
353
+ }
354
+ else if (curLoginInfo.loggingInPromise) {
355
+ return curLoginInfo.loggingInPromise;
356
+ }
357
+ else {
358
+ throw new Error('ws unexpected login info');
359
+ }
360
+ }
361
+ else {
362
+ throw new Error('ws login info reset');
363
+ }
364
+ }
365
+ catch (e) {
366
+ loginInfo.loggedIn = false;
367
+ loginInfo.loggingInPromise = undefined;
368
+ loginInfo.loginStartTS = undefined;
369
+ loginInfo.loginResult = undefined;
370
+ throw e;
371
+ }
372
+ };
373
+ this.getWsSign = async () => {
374
+ if (this._wsSign && this._wsSign.expiredTs > Date.now()) {
375
+ return this._wsSign;
376
+ }
377
+ const expiredTs = Date.now() + 60000;
378
+ const res = await this._context.appConfig.request.send('auth.wsWebSign', { runtime: Db.runtime });
379
+ if (res.code) {
380
+ throw new Error(`[tcb-js-sdk] 获取实时数据推送登录票据失败: ${res.code}`);
381
+ }
382
+ if (res.data) {
383
+ const { signStr, wsUrl, secretVersion, envId } = res.data;
384
+ return {
385
+ signStr,
386
+ wsUrl,
387
+ secretVersion,
388
+ envId,
389
+ expiredTs
390
+ };
391
+ }
392
+ else {
393
+ throw new Error('[tcb-js-sdk] 获取实时数据推送登录票据失败');
394
+ }
395
+ };
396
+ this.getWaitExpectedTimeoutLength = () => {
397
+ if (!this._rttObserved.length) {
398
+ return DEFAULT_EXPECTED_EVENT_WAIT_TIME;
399
+ }
400
+ return ((this._rttObserved.reduce((acc, cur) => acc + cur) /
401
+ this._rttObserved.length) *
402
+ 1.5);
403
+ };
404
+ this.ping = async () => {
405
+ const msg = {
406
+ watchId: undefined,
407
+ requestId: genRequestId(),
408
+ msgType: 'PING',
409
+ msgData: null
410
+ };
411
+ await this.send({
412
+ msg
413
+ });
414
+ };
415
+ this.send = async (opts) => new Promise(async (_resolve, _reject) => {
416
+ let timeoutId;
417
+ let _hasResolved = false;
418
+ let _hasRejected = false;
419
+ const resolve = (value) => {
420
+ _hasResolved = true;
421
+ timeoutId && clearTimeout(timeoutId);
422
+ _resolve(value);
423
+ };
424
+ const reject = (error) => {
425
+ _hasRejected = true;
426
+ timeoutId && clearTimeout(timeoutId);
427
+ _reject(error);
428
+ };
429
+ if (opts.timeout) {
430
+ timeoutId = setTimeout(async () => {
431
+ if (!_hasResolved || !_hasRejected) {
432
+ await sleep(0);
433
+ if (!_hasResolved || !_hasRejected) {
434
+ reject(new TimeoutError('wsclient.send timedout'));
435
+ }
436
+ }
437
+ }, opts.timeout);
438
+ }
439
+ try {
440
+ if (this._wsInitPromise) {
441
+ await this._wsInitPromise;
442
+ }
443
+ if (!this._ws) {
444
+ reject(new Error('invalid state: ws connection not exists, can not send message'));
445
+ return;
446
+ }
447
+ if (this._ws.readyState !== WS_READY_STATE.OPEN) {
448
+ reject(new Error(`ws readyState invalid: ${this._ws.readyState}, can not send message`));
449
+ return;
450
+ }
451
+ if (opts.waitResponse) {
452
+ this._wsResponseWait.set(opts.msg.requestId, {
453
+ resolve,
454
+ reject,
455
+ skipOnMessage: opts.skipOnMessage
456
+ });
457
+ }
458
+ try {
459
+ await this._ws.send(JSON.stringify(opts.msg));
460
+ if (!opts.waitResponse) {
461
+ resolve();
462
+ }
463
+ }
464
+ catch (err) {
465
+ if (err) {
466
+ reject(err);
467
+ if (opts.waitResponse) {
468
+ this._wsResponseWait.delete(opts.msg.requestId);
469
+ }
470
+ }
471
+ }
472
+ }
473
+ catch (e) {
474
+ reject(e);
475
+ }
476
+ });
477
+ this.closeAllClients = (error) => {
478
+ this._virtualWSClient.forEach(client => {
479
+ client.closeWithError(error);
480
+ });
481
+ };
482
+ this.pauseClients = (clients) => {
483
+ ;
484
+ (clients || this._virtualWSClient).forEach(client => {
485
+ client.pause();
486
+ });
487
+ };
488
+ this.resumeClients = (clients) => {
489
+ ;
490
+ (clients || this._virtualWSClient).forEach(client => {
491
+ client.resume();
492
+ });
493
+ };
494
+ this.onWatchStart = (client, queryID) => {
495
+ this._queryIdClientMap.set(queryID, client);
496
+ };
497
+ this.onWatchClose = (client, queryID) => {
498
+ if (queryID) {
499
+ this._queryIdClientMap.delete(queryID);
500
+ }
501
+ this._watchIdClientMap.delete(client.watchId);
502
+ this._virtualWSClient.delete(client);
503
+ if (!this._virtualWSClient.size) {
504
+ this.close(CLOSE_EVENT_CODE.NoRealtimeListeners);
505
+ }
506
+ };
507
+ this._maxReconnect = options.maxReconnect || DEFAULT_MAX_RECONNECT;
508
+ this._reconnectInterval =
509
+ options.reconnectInterval || DEFAULT_WS_RECONNECT_INTERVAL;
510
+ this._context = options.context;
511
+ }
512
+ heartbeat(immediate) {
513
+ this.clearHeartbeat();
514
+ this._pingTimeoutId = setTimeout(async () => {
515
+ try {
516
+ if (!this._ws || this._ws.readyState !== WS_READY_STATE.OPEN) {
517
+ return;
518
+ }
519
+ this._lastPingSendTS = Date.now();
520
+ await this.ping();
521
+ this._pingFailed = 0;
522
+ this._pongTimeoutId = setTimeout(() => {
523
+ console.error('pong timed out');
524
+ if (this._pongMissed < DEFAULT_PONG_MISS_TOLERANCE) {
525
+ this._pongMissed++;
526
+ this.heartbeat(true);
527
+ }
528
+ else {
529
+ this.initWebSocketConnection(true);
530
+ }
531
+ }, this._context.appConfig.realtimePongWaitTimeout);
532
+ }
533
+ catch (e) {
534
+ if (this._pingFailed < DEFAULT_PING_FAIL_TOLERANCE) {
535
+ this._pingFailed++;
536
+ this.heartbeat();
537
+ }
538
+ else {
539
+ this.close(CLOSE_EVENT_CODE.HeartbeatPingError);
540
+ }
541
+ }
542
+ }, immediate ? 0 : this._context.appConfig.realtimePingInterval);
543
+ }
544
+ clearHeartbeat() {
545
+ this._pingTimeoutId && clearTimeout(this._pingTimeoutId);
546
+ this._pongTimeoutId && clearTimeout(this._pongTimeoutId);
547
+ }
548
+ close(code) {
549
+ this.clearHeartbeat();
550
+ if (this._ws) {
551
+ this._ws.close(code, CLOSE_EVENT_CODE_INFO[code].name);
552
+ this._ws = undefined;
553
+ }
554
+ }
555
+ watch(options) {
556
+ if (!this._ws && !this._wsInitPromise) {
557
+ this.initWebSocketConnection(false);
558
+ }
559
+ const virtualClient = new VirtualWebSocketClient(Object.assign(Object.assign({}, options), { send: this.send, login: this.webLogin, isWSConnected: this.isWSConnected, onceWSConnected: this.onceWSConnected, getWaitExpectedTimeoutLength: this.getWaitExpectedTimeoutLength, onWatchStart: this.onWatchStart, onWatchClose: this.onWatchClose, debug: true }));
560
+ this._virtualWSClient.add(virtualClient);
561
+ this._watchIdClientMap.set(virtualClient.watchId, virtualClient);
562
+ return virtualClient.listener;
563
+ }
564
+ }