LiveQueryClient.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
  7. var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
  8. var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
  9. var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
  10. var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
  11. var _CoreManager = _interopRequireDefault(require("./CoreManager"));
  12. var _EventEmitter2 = _interopRequireDefault(require("./EventEmitter"));
  13. var _ParseObject = _interopRequireDefault(require("./ParseObject"));
  14. var _LiveQuerySubscription = _interopRequireDefault(require("./LiveQuerySubscription"));
  15. var _promiseUtils = require("./promiseUtils");
  16. var _ParseError = _interopRequireDefault(require("./ParseError"));
  17. function _createSuper(Derived) {
  18. var hasNativeReflectConstruct = _isNativeReflectConstruct();
  19. return function () {
  20. var Super = (0, _getPrototypeOf2.default)(Derived),
  21. result;
  22. if (hasNativeReflectConstruct) {
  23. var NewTarget = (0, _getPrototypeOf2.default)(this).constructor;
  24. result = Reflect.construct(Super, arguments, NewTarget);
  25. } else {
  26. result = Super.apply(this, arguments);
  27. }
  28. return (0, _possibleConstructorReturn2.default)(this, result);
  29. };
  30. }
  31. function _isNativeReflectConstruct() {
  32. if (typeof Reflect === "undefined" || !Reflect.construct) return false;
  33. if (Reflect.construct.sham) return false;
  34. if (typeof Proxy === "function") return true;
  35. try {
  36. Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
  37. return true;
  38. } catch (e) {
  39. return false;
  40. }
  41. }
  42. var CLIENT_STATE = {
  43. INITIALIZED: 'initialized',
  44. CONNECTING: 'connecting',
  45. CONNECTED: 'connected',
  46. CLOSED: 'closed',
  47. RECONNECTING: 'reconnecting',
  48. DISCONNECTED: 'disconnected'
  49. };
  50. var OP_TYPES = {
  51. CONNECT: 'connect',
  52. SUBSCRIBE: 'subscribe',
  53. UNSUBSCRIBE: 'unsubscribe',
  54. ERROR: 'error'
  55. };
  56. var OP_EVENTS = {
  57. CONNECTED: 'connected',
  58. SUBSCRIBED: 'subscribed',
  59. UNSUBSCRIBED: 'unsubscribed',
  60. ERROR: 'error',
  61. CREATE: 'create',
  62. UPDATE: 'update',
  63. ENTER: 'enter',
  64. LEAVE: 'leave',
  65. DELETE: 'delete'
  66. };
  67. var CLIENT_EMMITER_TYPES = {
  68. CLOSE: 'close',
  69. ERROR: 'error',
  70. OPEN: 'open'
  71. };
  72. var SUBSCRIPTION_EMMITER_TYPES = {
  73. OPEN: 'open',
  74. CLOSE: 'close',
  75. ERROR: 'error',
  76. CREATE: 'create',
  77. UPDATE: 'update',
  78. ENTER: 'enter',
  79. LEAVE: 'leave',
  80. DELETE: 'delete'
  81. };
  82. var generateInterval = function (k) {
  83. return Math.random() * Math.min(30, Math.pow(2, k) - 1) * 1000;
  84. };
  85. var LiveQueryClient = function (_EventEmitter) {
  86. (0, _inherits2.default)(LiveQueryClient, _EventEmitter);
  87. var _super = _createSuper(LiveQueryClient);
  88. function LiveQueryClient(_ref) {
  89. var _this;
  90. var applicationId = _ref.applicationId,
  91. serverURL = _ref.serverURL,
  92. javascriptKey = _ref.javascriptKey,
  93. masterKey = _ref.masterKey,
  94. sessionToken = _ref.sessionToken,
  95. installationId = _ref.installationId;
  96. (0, _classCallCheck2.default)(this, LiveQueryClient);
  97. _this = _super.call(this);
  98. if (!serverURL || serverURL.indexOf('ws') !== 0) {
  99. throw new Error('You need to set a proper Parse LiveQuery server url before using LiveQueryClient');
  100. }
  101. _this.reconnectHandle = null;
  102. _this.attempts = 1;
  103. _this.id = 0;
  104. _this.requestId = 1;
  105. _this.serverURL = serverURL;
  106. _this.applicationId = applicationId;
  107. _this.javascriptKey = javascriptKey || undefined;
  108. _this.masterKey = masterKey || undefined;
  109. _this.sessionToken = sessionToken || undefined;
  110. _this.installationId = installationId || undefined;
  111. _this.additionalProperties = true;
  112. _this.connectPromise = (0, _promiseUtils.resolvingPromise)();
  113. _this.subscriptions = new Map();
  114. _this.state = CLIENT_STATE.INITIALIZED;
  115. _this.on('error', function () {});
  116. return _this;
  117. }
  118. (0, _createClass2.default)(LiveQueryClient, [{
  119. key: "shouldOpen",
  120. value: function () {
  121. return this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED;
  122. }
  123. }, {
  124. key: "subscribe",
  125. value: function (query, sessionToken) {
  126. var _queryJSON$keys,
  127. _queryJSON$watch,
  128. _this2 = this;
  129. if (!query) {
  130. return;
  131. }
  132. var className = query.className;
  133. var queryJSON = query.toJSON();
  134. var where = queryJSON.where;
  135. var fields = (_queryJSON$keys = queryJSON.keys) == null ? void 0 : _queryJSON$keys.split(',');
  136. var watch = (_queryJSON$watch = queryJSON.watch) == null ? void 0 : _queryJSON$watch.split(',');
  137. var subscribeRequest = {
  138. op: OP_TYPES.SUBSCRIBE,
  139. requestId: this.requestId,
  140. query: {
  141. className: className,
  142. where: where,
  143. fields: fields,
  144. watch: watch
  145. }
  146. };
  147. if (sessionToken) {
  148. subscribeRequest.sessionToken = sessionToken;
  149. }
  150. var subscription = new _LiveQuerySubscription.default(this.requestId, query, sessionToken);
  151. this.subscriptions.set(this.requestId, subscription);
  152. this.requestId += 1;
  153. this.connectPromise.then(function () {
  154. _this2.socket.send(JSON.stringify(subscribeRequest));
  155. }).catch(function (error) {
  156. subscription.subscribePromise.reject(error);
  157. });
  158. return subscription;
  159. }
  160. }, {
  161. key: "unsubscribe",
  162. value: function (subscription) {
  163. var _this3 = this;
  164. if (!subscription) {
  165. return;
  166. }
  167. var unsubscribeRequest = {
  168. op: OP_TYPES.UNSUBSCRIBE,
  169. requestId: subscription.id
  170. };
  171. return this.connectPromise.then(function () {
  172. return _this3.socket.send(JSON.stringify(unsubscribeRequest));
  173. }).then(function () {
  174. return subscription.unsubscribePromise;
  175. });
  176. }
  177. }, {
  178. key: "open",
  179. value: function () {
  180. var _this4 = this;
  181. var WebSocketImplementation = _CoreManager.default.getWebSocketController();
  182. if (!WebSocketImplementation) {
  183. this.emit(CLIENT_EMMITER_TYPES.ERROR, 'Can not find WebSocket implementation');
  184. return;
  185. }
  186. if (this.state !== CLIENT_STATE.RECONNECTING) {
  187. this.state = CLIENT_STATE.CONNECTING;
  188. }
  189. this.socket = new WebSocketImplementation(this.serverURL);
  190. this.socket.closingPromise = (0, _promiseUtils.resolvingPromise)();
  191. this.socket.onopen = function () {
  192. _this4._handleWebSocketOpen();
  193. };
  194. this.socket.onmessage = function (event) {
  195. _this4._handleWebSocketMessage(event);
  196. };
  197. this.socket.onclose = function (event) {
  198. _this4.socket.closingPromise.resolve(event);
  199. _this4._handleWebSocketClose();
  200. };
  201. this.socket.onerror = function (error) {
  202. _this4._handleWebSocketError(error);
  203. };
  204. }
  205. }, {
  206. key: "resubscribe",
  207. value: function () {
  208. var _this5 = this;
  209. this.subscriptions.forEach(function (subscription, requestId) {
  210. var query = subscription.query;
  211. var queryJSON = query.toJSON();
  212. var where = queryJSON.where;
  213. var fields = queryJSON.keys ? queryJSON.keys.split(',') : undefined;
  214. var className = query.className;
  215. var sessionToken = subscription.sessionToken;
  216. var subscribeRequest = {
  217. op: OP_TYPES.SUBSCRIBE,
  218. requestId: requestId,
  219. query: {
  220. className: className,
  221. where: where,
  222. fields: fields
  223. }
  224. };
  225. if (sessionToken) {
  226. subscribeRequest.sessionToken = sessionToken;
  227. }
  228. _this5.connectPromise.then(function () {
  229. _this5.socket.send(JSON.stringify(subscribeRequest));
  230. });
  231. });
  232. }
  233. }, {
  234. key: "close",
  235. value: function () {
  236. var _this$socket, _this$socket2;
  237. if (this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED) {
  238. return;
  239. }
  240. this.state = CLIENT_STATE.DISCONNECTED;
  241. (_this$socket = this.socket) == null ? void 0 : _this$socket.close();
  242. for (var subscription of this.subscriptions.values()) {
  243. subscription.subscribed = false;
  244. subscription.emit(SUBSCRIPTION_EMMITER_TYPES.CLOSE);
  245. }
  246. this._handleReset();
  247. this.emit(CLIENT_EMMITER_TYPES.CLOSE);
  248. return (_this$socket2 = this.socket) == null ? void 0 : _this$socket2.closingPromise;
  249. }
  250. }, {
  251. key: "_handleReset",
  252. value: function () {
  253. this.attempts = 1;
  254. this.id = 0;
  255. this.requestId = 1;
  256. this.connectPromise = (0, _promiseUtils.resolvingPromise)();
  257. this.subscriptions = new Map();
  258. }
  259. }, {
  260. key: "_handleWebSocketOpen",
  261. value: function () {
  262. this.attempts = 1;
  263. var connectRequest = {
  264. op: OP_TYPES.CONNECT,
  265. applicationId: this.applicationId,
  266. javascriptKey: this.javascriptKey,
  267. masterKey: this.masterKey,
  268. sessionToken: this.sessionToken
  269. };
  270. if (this.additionalProperties) {
  271. connectRequest.installationId = this.installationId;
  272. }
  273. this.socket.send(JSON.stringify(connectRequest));
  274. }
  275. }, {
  276. key: "_handleWebSocketMessage",
  277. value: function (event) {
  278. var data = event.data;
  279. if (typeof data === 'string') {
  280. data = JSON.parse(data);
  281. }
  282. var subscription = null;
  283. if (data.requestId) {
  284. subscription = this.subscriptions.get(data.requestId);
  285. }
  286. var response = {
  287. clientId: data.clientId,
  288. installationId: data.installationId
  289. };
  290. switch (data.op) {
  291. case OP_EVENTS.CONNECTED:
  292. if (this.state === CLIENT_STATE.RECONNECTING) {
  293. this.resubscribe();
  294. }
  295. this.emit(CLIENT_EMMITER_TYPES.OPEN);
  296. this.id = data.clientId;
  297. this.connectPromise.resolve();
  298. this.state = CLIENT_STATE.CONNECTED;
  299. break;
  300. case OP_EVENTS.SUBSCRIBED:
  301. if (subscription) {
  302. subscription.subscribed = true;
  303. subscription.subscribePromise.resolve();
  304. setTimeout(function () {
  305. return subscription.emit(SUBSCRIPTION_EMMITER_TYPES.OPEN, response);
  306. }, 200);
  307. }
  308. break;
  309. case OP_EVENTS.ERROR:
  310. {
  311. var parseError = new _ParseError.default(data.code, data.error);
  312. if (!this.id) {
  313. this.connectPromise.reject(parseError);
  314. this.state = CLIENT_STATE.DISCONNECTED;
  315. }
  316. if (data.requestId) {
  317. if (subscription) {
  318. subscription.subscribePromise.reject(parseError);
  319. setTimeout(function () {
  320. return subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR, data.error);
  321. }, 200);
  322. }
  323. } else {
  324. this.emit(CLIENT_EMMITER_TYPES.ERROR, data.error);
  325. }
  326. if (data.error === 'Additional properties not allowed') {
  327. this.additionalProperties = false;
  328. }
  329. if (data.reconnect) {
  330. this._handleReconnect();
  331. }
  332. break;
  333. }
  334. case OP_EVENTS.UNSUBSCRIBED:
  335. {
  336. if (subscription) {
  337. this.subscriptions.delete(data.requestId);
  338. subscription.subscribed = false;
  339. subscription.unsubscribePromise.resolve();
  340. }
  341. break;
  342. }
  343. default:
  344. {
  345. if (!subscription) {
  346. break;
  347. }
  348. var override = false;
  349. if (data.original) {
  350. override = true;
  351. delete data.original.__type;
  352. for (var field in data.original) {
  353. if (!(field in data.object)) {
  354. data.object[field] = undefined;
  355. }
  356. }
  357. data.original = _ParseObject.default.fromJSON(data.original, false);
  358. }
  359. delete data.object.__type;
  360. var parseObject = _ParseObject.default.fromJSON(data.object, !(subscription.query && subscription.query._select) ? override : false);
  361. if (data.original) {
  362. subscription.emit(data.op, parseObject, data.original, response);
  363. } else {
  364. subscription.emit(data.op, parseObject, response);
  365. }
  366. var localDatastore = _CoreManager.default.getLocalDatastore();
  367. if (override && localDatastore.isEnabled) {
  368. localDatastore._updateObjectIfPinned(parseObject).then(function () {});
  369. }
  370. }
  371. }
  372. }
  373. }, {
  374. key: "_handleWebSocketClose",
  375. value: function () {
  376. if (this.state === CLIENT_STATE.DISCONNECTED) {
  377. return;
  378. }
  379. this.state = CLIENT_STATE.CLOSED;
  380. this.emit(CLIENT_EMMITER_TYPES.CLOSE);
  381. for (var subscription of this.subscriptions.values()) {
  382. subscription.emit(SUBSCRIPTION_EMMITER_TYPES.CLOSE);
  383. }
  384. this._handleReconnect();
  385. }
  386. }, {
  387. key: "_handleWebSocketError",
  388. value: function (error) {
  389. this.emit(CLIENT_EMMITER_TYPES.ERROR, error);
  390. for (var subscription of this.subscriptions.values()) {
  391. subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR, error);
  392. }
  393. this._handleReconnect();
  394. }
  395. }, {
  396. key: "_handleReconnect",
  397. value: function () {
  398. var _this6 = this;
  399. if (this.state === CLIENT_STATE.DISCONNECTED) {
  400. return;
  401. }
  402. this.state = CLIENT_STATE.RECONNECTING;
  403. var time = generateInterval(this.attempts);
  404. if (this.reconnectHandle) {
  405. clearTimeout(this.reconnectHandle);
  406. }
  407. this.reconnectHandle = setTimeout(function () {
  408. _this6.attempts++;
  409. _this6.connectPromise = (0, _promiseUtils.resolvingPromise)();
  410. _this6.open();
  411. }.bind(this), time);
  412. }
  413. }]);
  414. return LiveQueryClient;
  415. }(_EventEmitter2.default);
  416. _CoreManager.default.setWebSocketController(WebSocket);
  417. var _default = LiveQueryClient;
  418. exports.default = _default;