LiveQueryClient.js 14 KB

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