react-native-mosquito-transport 0.0.52 → 0.0.53

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-mosquito-transport",
3
- "version": "0.0.52",
3
+ "version": "0.0.53",
4
4
  "description": "React native javascript sdk for mosquito-transport (https://github.com/brainbehindx/mosquito-transport)",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -1,5 +1,4 @@
1
1
  import { Buffer } from "buffer";
2
- import { ServerReachableListener } from "./listeners";
3
2
  import naclPkg from 'tweetnacl';
4
3
  import { deserialize, serialize } from "entity-serializer";
5
4
  import { sha256 } from 'react-native-sha256';
@@ -8,14 +7,6 @@ import { grab } from "poke-object";
8
7
 
9
8
  const { box, randomBytes } = naclPkg;
10
9
 
11
- export const listenReachableServer = (callback, projectUrl) => {
12
- let lastValue;
13
- return ServerReachableListener.listenToPersist(projectUrl, t => {
14
- if (typeof t === 'boolean' && t !== lastValue) callback?.(t);
15
- lastValue = t;
16
- });
17
- };
18
-
19
10
  export const prefixStoragePath = (path, prefix = 'file:///') => {
20
11
  let cleanedPath = path.replace(/^[^/]+:\/{1,3}/, '');
21
12
 
@@ -30,13 +21,6 @@ export const prefixStoragePath = (path, prefix = 'file:///') => {
30
21
  return `${prefix}${cleanedPath}`;
31
22
  };
32
23
 
33
- export const niceTry = (promise) => new Promise(async resolve => {
34
- try {
35
- const r = await promise();
36
- resolve(r);
37
- } catch (e) { resolve(); }
38
- });
39
-
40
24
  export const normalizeRoute = (route = '') => route.split('').map((v, i, a) =>
41
25
  ((!i && v === '/') || (i === a.length - 1 && v === '/') || (i && a[i - 1] === '/' && v === '/')) ? '' : v
42
26
  ).join('');
@@ -7,6 +7,8 @@ import { breakDbMap, purgeRedundantRecords } from "./purger";
7
7
  import { FS_PATH, getSystem } from "./fs_manager";
8
8
  import { Buffer } from "buffer";
9
9
  import { basicClone } from "./basic_clone";
10
+ import engine_api from "./engine_api";
11
+ import { AppState } from "react-native";
10
12
 
11
13
  const { FILE_NAME, TABLE_NAME } = FS_PATH;
12
14
 
@@ -153,31 +155,76 @@ export const awaitStore = () => new Promise(resolve => {
153
155
  });
154
156
  });
155
157
 
156
- export const awaitReachableServer = (projectUrl) => new Promise(resolve => {
157
- if (Scoped.IS_CONNECTED[projectUrl]) {
158
- resolve();
159
- return;
158
+ export const checkAreYouOk = (projectUrl) => {
159
+ if (!Scoped.AreYouOkPromise[projectUrl]) {
160
+ const signal = new AbortController();
161
+ const timer = setTimeout(() => {
162
+ signal.abort();
163
+ }, 9000);
164
+ const promise = fetch(engine_api._areYouOk(projectUrl), { credentials: 'omit', signal })
165
+ .then(async r => (await r.json()).status === 'yes')
166
+ .catch(() => false)
167
+ .then(async connected => {
168
+ Scoped.IS_CONNECTED[projectUrl] = connected;
169
+ ServerReachableListener.dispatchPersist(projectUrl, connected);
170
+
171
+ clearTimeout(timer);
172
+ delete Scoped.AreYouOkPromise[projectUrl];
173
+ return connected;
174
+ });
175
+
176
+ Scoped.AreYouOkPromise[projectUrl] = promise;
160
177
  }
161
- const l = ServerReachableListener.listenToPersist(projectUrl, t => {
162
- if (t) {
178
+
179
+ return Scoped.AreYouOkPromise[projectUrl];
180
+ }
181
+
182
+ export const listenReachableServer = (callback, projectUrl) => {
183
+ let lastValue;
184
+ return ServerReachableListener.listenToPersist(projectUrl, t => {
185
+ if (typeof t === 'boolean' && t !== lastValue) callback?.(t);
186
+ lastValue = t;
187
+ });
188
+ };
189
+
190
+ export const awaitReachableServer = (projectUrl) =>
191
+ new Promise(async resolve => {
192
+ if (AppState.currentState !== 'active') {
193
+ if (await checkAreYouOk(projectUrl)) {
194
+ resolve();
195
+ return;
196
+ }
197
+ }
198
+
199
+ if (Scoped.IS_CONNECTED[projectUrl]) {
163
200
  resolve();
164
- l();
201
+ return;
165
202
  }
203
+
204
+ const l = listenReachableServer(t => {
205
+ if (!t) return;
206
+ resolve();
207
+ l();
208
+ }, projectUrl);
166
209
  });
167
- });
168
210
 
169
- export const getReachableServer = (projectUrl) => new Promise(resolve => {
170
- if (typeof Scoped.IS_CONNECTED[projectUrl] === 'boolean') {
171
- resolve(Scoped.IS_CONNECTED[projectUrl]);
172
- return;
173
- }
174
- const l = ServerReachableListener.listenToPersist(projectUrl, t => {
175
- if (typeof t === 'boolean') {
211
+ export const getReachableServer = (projectUrl) =>
212
+ new Promise(async resolve => {
213
+ if (AppState.currentState !== 'active') {
214
+ resolve(await checkAreYouOk(projectUrl));
215
+ return;
216
+ }
217
+
218
+ if (typeof Scoped.IS_CONNECTED[projectUrl] === 'boolean') {
219
+ resolve(Scoped.IS_CONNECTED[projectUrl]);
220
+ return;
221
+ }
222
+
223
+ const l = listenReachableServer(t => {
176
224
  resolve(t);
177
225
  l();
178
- }
226
+ }, projectUrl);
179
227
  });
180
- });
181
228
 
182
229
  export const buildFetchInterface = async ({ body, authToken, method, uglify, serverE2E_PublicKey, extraHeaders }) => {
183
230
  if (!uglify) body = JSON.stringify({ ...body });
@@ -4,6 +4,7 @@ export const Scoped = {
4
4
  PendingIte: 0,
5
5
  AnyProcessIte: 0,
6
6
  IS_CONNECTED: {},
7
+ AreYouOkPromise: {},
7
8
  InitializedProject: {},
8
9
  ReleaseCacheData: undefined,
9
10
  AuthJWTToken: {},
package/src/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import 'react-native-get-random-values';
2
- import { deserializeE2E, listenReachableServer, serializeE2E } from "./helpers/peripherals";
3
- import { awaitReachableServer, awaitStore, releaseCacheStore } from "./helpers/utils";
2
+ import { deserializeE2E, serializeE2E } from "./helpers/peripherals";
3
+ import { awaitReachableServer, awaitStore, checkAreYouOk, listenReachableServer, releaseCacheStore } from "./helpers/utils";
4
4
  import { CacheStore, Scoped } from "./helpers/variables";
5
5
  import { MTCollection, batchWrite, onCollectionConnect, trySendPendingWrite } from "./products/database";
6
6
  import { MTStorage } from "./products/storage";
@@ -23,8 +23,7 @@ const {
23
23
  _listenDocument,
24
24
  _startDisconnectWriteTask,
25
25
  _cancelDisconnectWriteTask,
26
- _listenUserVerification,
27
- _areYouOk
26
+ _listenUserVerification
28
27
  } = EngineApi;
29
28
 
30
29
  // https://socket.io/docs/v3/emit-cheatsheet/#reserved-events
@@ -63,7 +62,7 @@ class RNMT {
63
62
  triggerAuthToken(projectUrl);
64
63
  initTokenRefresher({ config: this.config, forceRefresh: true });
65
64
 
66
- let isConnected, recentToken, isVirtualMachineFocused = true;
65
+ let isConnected, recentToken;
67
66
 
68
67
  const socket = io(`${this.config.wsPrefix}://${this.config.baseUrl}`, {
69
68
  transports: ['websocket', 'polling', 'flashsocket'],
@@ -91,28 +90,19 @@ class RNMT {
91
90
  });
92
91
  };
93
92
 
94
- const onDisconnect = () => {
95
- ++connectionIte;
96
- setConnected(isVirtualMachineFocused ? false : null);
97
- }
98
-
99
93
  const manualCheckConnection = () => {
100
94
  if (chainedPromise) return;
101
95
  const ref = ++connectionIte;
102
- const signal = new AbortController();
103
- const timer = setTimeout(() => {
104
- signal.abort();
105
- }, 7000);
106
- chainedPromise = fetch(_areYouOk(projectUrl), { credentials: 'omit', signal }).then(async r => {
107
- clearTimeout(timer);
108
- chainedPromise = undefined;
109
- if ((await r.json()).status === 'yes') {
110
- if (ref === connectionIte) onConnect();
111
- } else throw null;
112
- }).catch(() => {
113
- clearTimeout(timer);
96
+
97
+ checkAreYouOk(projectUrl).then(ok => {
114
98
  chainedPromise = undefined;
115
- if (ref === connectionIte) onDisconnect();
99
+ if (ref !== connectionIte) return;
100
+ if (ok) {
101
+ onConnect();
102
+ } else {
103
+ ++connectionIte;
104
+ isConnected = false;
105
+ }
116
106
  });
117
107
  }
118
108
 
@@ -128,7 +118,6 @@ class RNMT {
128
118
  });
129
119
 
130
120
  AppState.addEventListener('change', s => {
131
- isVirtualMachineFocused = s === 'active';
132
121
  manualCheckConnection();
133
122
  });
134
123
 
@@ -352,7 +341,7 @@ class RNMT {
352
341
  makeSocketCallback();
353
342
  const reloadIntance = async () => {
354
343
  if (!disableAuth) await awaitRefreshToken(projectUrl);
355
- if (initIte === instance_id) remountInit();
344
+ if (initIte === instance_id && !hasCancelled) remountInit();
356
345
  }
357
346
 
358
347
  if (AppState.currentState === 'active') {
@@ -387,8 +376,7 @@ class RNMT {
387
376
  if (initIte !== instance_id || wasHandled) return;
388
377
  wasHandled = true;
389
378
  clearSocket();
390
- if (r === 'io client disconnect') return;
391
- if (r === 'io server disconnect') {
379
+ if (r === 'io client disconnect' || r === 'io server disconnect') {
392
380
  resultant.destroy();
393
381
  } else reconnect(0);
394
382
  });
@@ -478,6 +466,7 @@ class RNMT {
478
466
  }
479
467
  },
480
468
  destroy: () => {
469
+ if (hasCancelled) return;
481
470
  hasCancelled = true;
482
471
  tokenListener?.();
483
472
  clearForegroundListener();
@@ -1,8 +1,8 @@
1
1
  import { doSignOut, revokeAuthIntance } from "./index.js";
2
2
  import EngineApi from "../../helpers/engine_api";
3
3
  import { AuthTokenListener, TokenRefreshListener } from "../../helpers/listeners";
4
- import { decodeBinary, deserializeE2E, listenReachableServer } from "../../helpers/peripherals";
5
- import { awaitStore, buildFetchInterface, buildFetchResult, updateCacheStore } from "../../helpers/utils";
4
+ import { decodeBinary, deserializeE2E } from "../../helpers/peripherals";
5
+ import { awaitReachableServer, awaitStore, buildFetchInterface, buildFetchResult, updateCacheStore } from "../../helpers/utils";
6
6
  import { CacheStore, Scoped } from "../../helpers/variables";
7
7
  import { simplifyError } from "simplify-error";
8
8
  import { Validator } from "guard-object";
@@ -208,12 +208,9 @@ const refreshToken = (builder, remainRetries = 1, isForceRefresh) =>
208
208
  );
209
209
  console.error(`refreshToken retry limit exceeded err:`, e);
210
210
  } else {
211
- const l = listenReachableServer(c => {
212
- if (c) {
213
- l();
214
- refreshToken(builder, remainRetries - 1, isForceRefresh).then(resolve, reject);
215
- }
216
- }, projectUrl);
211
+ awaitReachableServer(projectUrl).then(() => {
212
+ refreshToken(builder, remainRetries - 1, isForceRefresh).then(resolve, reject);
213
+ });
217
214
  }
218
215
  }
219
216
  });
@@ -14,8 +14,7 @@ const {
14
14
  _customSignin,
15
15
  _customSignup,
16
16
  _googleSignin,
17
- _appleSignin,
18
- _areYouOk
17
+ _appleSignin
19
18
  } = EngineApi;
20
19
 
21
20
  export default class MTAuth {
@@ -291,12 +290,7 @@ export const purgePendingToken = async (nodeId) => {
291
290
 
292
291
  if (!token) return;
293
292
  try {
294
- let isConnected;
295
- try {
296
- isConnected = (await (await fetch(_areYouOk(projectUrl), { credentials: 'omit' })).json()).status === 'yes';
297
- } catch (_) { }
298
-
299
- if (!isConnected) await awaitReachableServer(projectUrl);
293
+ await awaitReachableServer(projectUrl);
300
294
 
301
295
  const [reqBuilder] = await buildFetchInterface({
302
296
  body: { token, r_token },
@@ -1,7 +1,7 @@
1
1
  import { io } from "socket.io-client";
2
2
  import EngineApi from "../../helpers/engine_api";
3
3
  import { DatabaseRecordsListener } from "../../helpers/listeners";
4
- import { deserializeE2E, listenReachableServer, niceTry, serializeE2E } from "../../helpers/peripherals";
4
+ import { deserializeE2E, serializeE2E } from "../../helpers/peripherals";
5
5
  import { awaitReachableServer, awaitStore, buildFetchInterface, buildFetchResult, getReachableServer, updateCacheStore } from "../../helpers/utils";
6
6
  import { CacheStore, Scoped } from "../../helpers/variables";
7
7
  import { addPendingWrites, generateRecordID, getCountQuery, getRecord, insertCountQuery, insertRecord, listenQueryEntry, removePendingWrite, validateWriteValue } from "./accessor";
@@ -158,7 +158,6 @@ const listenDocument = (callback, onError, builder, config) => {
158
158
  hasRespond,
159
159
  cacheListener,
160
160
  lastInitRef = 0,
161
- connectedListener,
162
161
  lastSnapshot;
163
162
 
164
163
  const dispatchSnapshot = s => {
@@ -179,11 +178,10 @@ const listenDocument = (callback, onError, builder, config) => {
179
178
 
180
179
  awaitStore().then(() => {
181
180
  if (hasCancelled) return;
182
- connectedListener = listenReachableServer(async connected => {
183
- connectedListener();
181
+ getReachableServer(projectUrl).then(connected => {
184
182
  if (!connected && !hasRespond && !hasCancelled && shouldCache)
185
183
  DatabaseRecordsListener.dispatch('d', processId);
186
- }, projectUrl);
184
+ });
187
185
  });
188
186
  }
189
187
 
@@ -260,7 +258,7 @@ const listenDocument = (callback, onError, builder, config) => {
260
258
  if (processID !== lastInitRef || hasCancelled) return;
261
259
 
262
260
  const reloadIntance = async () => {
263
- if (processID !== lastInitRef && !hasCancelled) remountInit();
261
+ if (processID === lastInitRef && !hasCancelled) remountInit();
264
262
  }
265
263
 
266
264
  if (AppState.currentState === 'active') {
@@ -289,8 +287,9 @@ const listenDocument = (callback, onError, builder, config) => {
289
287
  if (processID !== lastInitRef || wasHandled) return;
290
288
  wasHandled = true;
291
289
  clearSocket();
292
- if (r === 'io client disconnect' || r === 'io server disconnect') return;
293
- reconnect(0);
290
+ if (r === 'io client disconnect' || r === 'io server disconnect') {
291
+ canceller();
292
+ } else reconnect(0);
294
293
  });
295
294
  };
296
295
 
@@ -321,15 +320,16 @@ const listenDocument = (callback, onError, builder, config) => {
321
320
  }, projectUrl);
322
321
  }
323
322
 
324
- return () => {
323
+ const canceller = () => {
325
324
  if (hasCancelled) return;
326
325
  hasCancelled = true;
327
- connectedListener?.();
328
326
  cacheListener?.();
329
327
  tokenListener?.();
330
328
  clearForegroundListener();
331
329
  clearSocket();
332
330
  }
331
+
332
+ return canceller;
333
333
  };
334
334
 
335
335
  const initOnDisconnectionTask = ({ builder, connectData, disconnectData }) => {
@@ -416,7 +416,7 @@ const initOnDisconnectionTask = ({ builder, connectData, disconnectData }) => {
416
416
 
417
417
  const reloadIntance = async () => {
418
418
  if (!disableAuth) await awaitRefreshToken(projectUrl);
419
- if (processID !== lastInitRef && !hasCancelled) remountInit();
419
+ if (processID === lastInitRef && !hasCancelled) remountInit();
420
420
  }
421
421
 
422
422
  if (AppState.currentState === 'active') {
@@ -445,8 +445,9 @@ const initOnDisconnectionTask = ({ builder, connectData, disconnectData }) => {
445
445
  if (processID !== lastInitRef || wasHandled) return;
446
446
  wasHandled = true;
447
447
  clearSocket();
448
- if (r === 'io client disconnect' || r === 'io server disconnect') return;
449
- reconnect(0);
448
+ if (r === 'io client disconnect' || r === 'io server disconnect') {
449
+ canceller();
450
+ } else reconnect(0);
450
451
  });
451
452
  };
452
453
 
@@ -477,18 +478,24 @@ const initOnDisconnectionTask = ({ builder, connectData, disconnectData }) => {
477
478
  }, projectUrl);
478
479
  }
479
480
 
480
- return () => {
481
+ const canceller = () => {
481
482
  if (hasCancelled) return;
482
483
  hasCancelled = true;
483
484
  tokenListener?.();
484
485
  clearForegroundListener();
485
486
  if (socket) {
486
487
  const thisSocket = socket;
487
- return niceTry(() => thisSocket.timeout(5000).emitWithAck(_cancelDisconnectWriteTask(uglify))).finally(() => {
488
- thisSocket.close();
489
- });
488
+ try {
489
+ thisSocket.timeout(5000).emitWithAck(_cancelDisconnectWriteTask(uglify)).finally(() => {
490
+ thisSocket.close();
491
+ });
492
+ } catch (error) {
493
+ console.warn('socket closure error:', error);
494
+ }
490
495
  }
491
496
  };
497
+
498
+ return canceller;
492
499
  };
493
500
 
494
501
  const countCollection = async (builder, config) => {
@@ -552,15 +559,12 @@ const countCollection = async (builder, config) => {
552
559
  } else if (retries > maxRetries) {
553
560
  finalize(undefined, { error: 'retry_limit_exceeded', message: `retry exceed limit(${maxRetries})` });
554
561
  } else {
555
- const onlineListener = listenReachableServer(connected => {
556
- if (connected) {
557
- onlineListener();
558
- readValue().then(
559
- e => { finalize(e); },
560
- e => { finalize(undefined, e); }
561
- );
562
- }
563
- }, projectUrl);
562
+ awaitReachableServer(projectUrl).then(() => {
563
+ readValue().then(
564
+ e => { finalize(e); },
565
+ e => { finalize(undefined, e); }
566
+ );
567
+ });
564
568
  }
565
569
  }
566
570
  });
@@ -730,20 +734,18 @@ const findObject = async (builder, initConfig) => {
730
734
  } else if (retries > maxRetries) {
731
735
  finalize(undefined, { error: 'retry_limit_exceeded', message: `retry exceed limit(${maxRetries})` });
732
736
  } else {
733
- const onlineListener = listenReachableServer(connected => {
734
- if (connected) {
737
+ awaitReachableServer(projectUrl).then(() => {
738
+ if (intruder) {
735
739
  intruder.resolve = undefined;
736
740
  intruder.reject = undefined;
737
- onlineListener();
738
741
  readValue().then(
739
742
  e => { finalize(e); },
740
743
  e => { finalize(undefined, e); }
741
744
  );
742
745
  }
743
- }, projectUrl);
746
+ });
744
747
 
745
748
  const cleanseIntruder = () => {
746
- onlineListener?.();
747
749
  intruder = undefined;
748
750
  }
749
751
 
@@ -879,15 +881,12 @@ const commitData = async (builder, value, type, config) => {
879
881
  );
880
882
  } else {
881
883
  if (delivery === DELIVERY.NO_CACHE_AWAIT) {
882
- const onlineListener = listenReachableServer(connected => {
883
- if (connected) {
884
- onlineListener();
885
- sendValue().then(
886
- e => { finalize(e.a, undefined, e.c); },
887
- e => { finalize(undefined, e.b, e.c); }
888
- );
889
- }
890
- }, projectUrl);
884
+ awaitReachableServer(projectUrl).then(() => {
885
+ sendValue().then(
886
+ e => { finalize(e.a, undefined, e.c); },
887
+ e => { finalize(undefined, e.b, e.c); }
888
+ );
889
+ });
891
890
  } else if (shouldCache) finalize({ status: 'queued' });
892
891
  else finalize(undefined, simplifyCaughtError(e).simpleError);
893
892
  }
@@ -1,6 +1,6 @@
1
1
  import { Buffer } from "buffer";
2
- import { deserializeE2E, listenReachableServer, niceHash, normalizeRoute, serializeE2E } from "../../helpers/peripherals";
3
- import { awaitStore, getReachableServer } from "../../helpers/utils";
2
+ import { deserializeE2E, niceHash, normalizeRoute, serializeE2E } from "../../helpers/peripherals";
3
+ import { awaitReachableServer, awaitStore, getReachableServer } from "../../helpers/utils";
4
4
  import { RETRIEVAL } from "../../helpers/values";
5
5
  import { Scoped } from "../../helpers/variables";
6
6
  import { awaitRefreshToken, parseToken } from "../auth/accessor";
@@ -216,15 +216,12 @@ export const mfetch = async (input = '', init, config) => {
216
216
  } else if (retries > maxRetries) {
217
217
  finalize(undefined, simplifyCaughtError(e).simpleError);
218
218
  } else {
219
- const listener = listenReachableServer(async online => {
220
- if (online) {
221
- listener();
222
- callFetch().then(
223
- e => finalize(e),
224
- e => finalize(undefined, e)
225
- );
226
- }
227
- }, projectUrl);
219
+ awaitReachableServer(projectUrl).then(() => {
220
+ callFetch().then(
221
+ e => finalize(e),
222
+ e => finalize(undefined, e)
223
+ );
224
+ });
228
225
  }
229
226
  }
230
227
  });