react-native-mosquito-transport 0.0.26 → 0.0.28

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/README.md CHANGED
@@ -13,6 +13,7 @@ or using yarn
13
13
  ```sh
14
14
  yarn add react-native-mosquito-transport
15
15
  ```
16
+ internal bson
16
17
 
17
18
  ## Usage
18
19
 
package/TODO CHANGED
@@ -20,4 +20,5 @@
20
20
  - lodashes ✅
21
21
  - switch to events package
22
22
  - serverTimeOffset
23
+ - avoid sending cookies
23
24
  <!-- - error: "refreshToken retry limit exceeded" <--- no need -->
@@ -1,16 +1,25 @@
1
1
  package com.mosquitodb;
2
2
 
3
+ import android.util.ArrayMap;
4
+
3
5
  import androidx.annotation.NonNull;
6
+ import androidx.annotation.Nullable;
4
7
 
5
- import com.facebook.react.bridge.Promise;
6
8
  import com.facebook.react.bridge.ReactApplicationContext;
7
9
  import com.facebook.react.bridge.ReactContextBaseJavaModule;
8
10
  import com.facebook.react.bridge.ReactMethod;
11
+ import com.facebook.react.bridge.ReadableMap;
12
+ import com.facebook.react.bridge.WritableMap;
13
+ import com.facebook.react.bridge.WritableNativeMap;
9
14
  import com.facebook.react.module.annotations.ReactModule;
15
+ import com.facebook.react.modules.core.DeviceEventManagerModule;
16
+ import com.mosquitodb.utils.FileUploader;
17
+ import com.mosquitodb.utils.UploadCallback;
10
18
 
11
19
  @ReactModule(name = MosquitodbModule.NAME)
12
20
  public class MosquitodbModule extends ReactContextBaseJavaModule {
13
21
  public static final String NAME = "Mosquitodb";
22
+ private final ArrayMap<String, FileUploader> uploaderMap = new ArrayMap<>();
14
23
 
15
24
  public MosquitodbModule(ReactApplicationContext reactContext) {
16
25
  super(reactContext);
@@ -22,11 +31,52 @@ public class MosquitodbModule extends ReactContextBaseJavaModule {
22
31
  return NAME;
23
32
  }
24
33
 
34
+ @ReactMethod
35
+ public void uploadFile(ReadableMap readable) {
36
+ String processId = readable.getString("processID");
37
+ FileUploader uploader = new FileUploader();
38
+
39
+ uploader.uploadFile(readable, new UploadCallback() {
40
+ @Override
41
+ public void onProgress(long sentBytes, long totalBytes) {
42
+ WritableMap progress = new WritableNativeMap();
43
+ progress.putInt("sentBytes", (int) sentBytes);
44
+ progress.putInt("totalBytes", (int) totalBytes);
45
+ progress.putString("processID", processId);
46
+ sendEvent("mt-uploading-progress", progress);
47
+ }
48
+
49
+ @Override
50
+ public void onComplete(int responseCode, String responseBody) {
51
+ WritableMap statusData = new WritableNativeMap();
52
+ statusData.putString("processID", processId);
53
+ statusData.putString("result", responseBody);
54
+ sendEvent("mt-uploading-status", statusData);
55
+ }
56
+
57
+ @Override
58
+ public void onError(Exception e) {
59
+ WritableMap statusData = new WritableNativeMap();
60
+ statusData.putString("processID", processId);
61
+ statusData.putString("error", "internal_error");
62
+ statusData.putString("errorDes", e.getLocalizedMessage());
63
+ sendEvent("mt-uploading-status", statusData);
64
+ }
65
+ });
66
+ uploaderMap.put(processId, uploader);
67
+ }
25
68
 
26
- // Example method
27
- // See https://reactnative.dev/docs/native-modules-android
28
69
  @ReactMethod
29
- public void multiply(double a, double b, Promise promise) {
30
- promise.resolve(a * b);
70
+ public void cancelUpload(String processID) {
71
+ FileUploader uploader = uploaderMap.get(processID);
72
+ if (uploader != null) {
73
+ uploader.cancelUpload();
74
+ }
75
+ }
76
+
77
+ private void sendEvent(String eventName, @Nullable WritableMap params) {
78
+ getReactApplicationContext()
79
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
80
+ .emit(eventName, params);
31
81
  }
32
82
  }
@@ -0,0 +1,101 @@
1
+ package com.mosquitodb.utils;
2
+
3
+ import java.io.*;
4
+ import java.net.*;
5
+ import java.util.Objects;
6
+
7
+ import android.net.Uri;
8
+
9
+ import com.facebook.react.bridge.ReadableMap;
10
+ import com.facebook.react.bridge.ReadableMapKeySetIterator;
11
+
12
+ public class FileUploader {
13
+
14
+ private volatile boolean isCancelled = false;
15
+
16
+ public void cancelUpload() {
17
+ isCancelled = true;
18
+ }
19
+
20
+ public void uploadFile(ReadableMap config, UploadCallback callback) {
21
+ new Thread(() -> {
22
+ try {
23
+ Uri fileUri = Uri.parse(config.getString("file"));
24
+ File file = new File(Objects.requireNonNull(fileUri.getPath()));
25
+
26
+ if (!file.exists()) {
27
+ throw new FileNotFoundException("File not found: " + file.getAbsolutePath());
28
+ }
29
+
30
+ long totalBytes = file.length();
31
+ HttpURLConnection connection = (HttpURLConnection) new URL(config.getString("url")).openConnection();
32
+ connection.setDoOutput(true);
33
+ connection.setRequestMethod("POST");
34
+
35
+ ReadableMap extraHeaders = config.getMap("extraHeaders");
36
+ ReadableMapKeySetIterator iterator = Objects.requireNonNull(extraHeaders).keySetIterator();
37
+ while (iterator.hasNextKey()) {
38
+ String key = iterator.nextKey();
39
+ connection.setRequestProperty(key, extraHeaders.getString(key));
40
+ }
41
+
42
+ connection.setRequestProperty("Content-Type", "buffer/upload");
43
+ connection.setRequestProperty("hash-upload", config.getString("createHash"));
44
+ connection.setRequestProperty("Mosquito-Destination", config.getString("destination"));
45
+ if (config.hasKey("authToken")) {
46
+ connection.setRequestProperty("Mosquito-Token", config.getString("authToken"));
47
+ }
48
+ connection.setFixedLengthStreamingMode((int) totalBytes);
49
+
50
+ OutputStream out = connection.getOutputStream();
51
+ FileInputStream in = new FileInputStream(file);
52
+
53
+ byte[] buffer = new byte[8192];
54
+ long sentBytes = 0;
55
+ int bytesRead;
56
+
57
+ while ((bytesRead = in.read(buffer)) != -1) {
58
+ if (isCancelled) {
59
+ in.close();
60
+ out.close();
61
+ connection.disconnect();
62
+ callback.onError(new IOException("Upload cancelled"));
63
+ return;
64
+ }
65
+
66
+ out.write(buffer, 0, bytesRead);
67
+ sentBytes += bytesRead;
68
+ callback.onProgress(sentBytes, totalBytes);
69
+ }
70
+
71
+ out.flush();
72
+ in.close();
73
+ out.close();
74
+
75
+ int responseCode = connection.getResponseCode();
76
+ InputStream responseStream = (responseCode >= 200 && responseCode < 400)
77
+ ? connection.getInputStream()
78
+ : connection.getErrorStream();
79
+ String responseBody = readStream(responseStream);
80
+
81
+ callback.onComplete(responseCode, responseBody);
82
+ connection.disconnect();
83
+ } catch (Exception e) {
84
+ callback.onError(e);
85
+ }
86
+ }).start();
87
+ }
88
+
89
+ private String readStream(InputStream stream) throws IOException {
90
+ if (stream == null) return "";
91
+
92
+ BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
93
+ StringBuilder result = new StringBuilder();
94
+ String line;
95
+ while ((line = reader.readLine()) != null) {
96
+ result.append(line).append("\n");
97
+ }
98
+ reader.close();
99
+ return result.toString().trim();
100
+ }
101
+ }
@@ -0,0 +1,7 @@
1
+ package com.mosquitodb.utils;
2
+
3
+ public interface UploadCallback {
4
+ void onProgress(long sentBytes, long totalBytes);
5
+ void onComplete(int responseCode, String responseBody);
6
+ void onError(Exception e);
7
+ }
@@ -100,7 +100,6 @@ class MosquitodbUploadTask: NSObject, URLSessionDataDelegate {
100
100
  request.setValue(value, forHTTPHeaderField: key)
101
101
  }
102
102
  }
103
- request.setValue("application/json", forHTTPHeaderField: "Accept")
104
103
  if options["authToken"] != nil {
105
104
  request.setValue(options["authToken"] as? String, forHTTPHeaderField: "Mosquito-Token")
106
105
  }
@@ -137,7 +136,7 @@ class MosquitodbUploadTask: NSObject, URLSessionDataDelegate {
137
136
 
138
137
  trigger!([
139
138
  "mt-uploading-progress", [
140
- "sentBtyes": Float(totalBytesSent),
139
+ "sentBytes": Float(totalBytesSent),
141
140
  "totalBytes": Float(totalBytesExpectedToSend),
142
141
  "processID": mainProcessID
143
142
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-mosquito-transport",
3
- "version": "0.0.26",
3
+ "version": "0.0.28",
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",
package/src/index.d.ts CHANGED
@@ -531,7 +531,7 @@ interface DownloadProgressStats {
531
531
  }
532
532
 
533
533
  interface UploadProgressStats {
534
- sentBtyes: number;
534
+ sentBytes: number;
535
535
  totalBytes: number;
536
536
  }
537
537
 
@@ -7,7 +7,7 @@ import setLodash from 'lodash/set';
7
7
  import unsetLodash from 'lodash/unset';
8
8
  import { DatabaseRecordsListener } from "../../helpers/listeners";
9
9
  import cloneDeep from "lodash/cloneDeep";
10
- import { BSONRegExp, ObjectId, Timestamp } from "bson";
10
+ import { BSONRegExp, ObjectId, Timestamp } from "bson/lib/bson.rn.cjs";
11
11
  import { niceGuard, Validator } from "guard-object";
12
12
  import { TIMESTAMP } from "../..";
13
13
  import { docSize, incrementDatabaseSize } from "./counter";
@@ -1,4 +1,4 @@
1
- import { deserialize, serialize } from "bson";
1
+ import { deserialize, serialize } from "bson/lib/bson.rn.cjs";
2
2
  import { Buffer } from "buffer";
3
3
 
4
4
  export const deserializeBSON = (data, cast) => {
@@ -8,7 +8,7 @@ import { addPendingWrites, generateRecordID, getCountQuery, getRecord, insertCou
8
8
  import { validateCollectionName, validateFilter, validateFindConfig, validateFindObject, validateListenFindConfig } from "./validator";
9
9
  import { awaitRefreshToken, listenToken } from "../auth/accessor";
10
10
  import { DELIVERY, RETRIEVAL } from "../../helpers/values";
11
- import { ObjectId } from "bson";
11
+ import { ObjectId } from "bson/lib/bson.rn.cjs";
12
12
  import { guardObject, Validator } from "guard-object";
13
13
  import { simplifyCaughtError } from "simplify-error";
14
14
  import cloneDeep from "lodash/cloneDeep";
@@ -2,7 +2,7 @@ import { guardArray, GuardError, guardObject, GuardSignal, niceGuard, Validator
2
2
  import { sameInstance } from "../../helpers/peripherals";
3
3
  import { RETRIEVAL } from "../../helpers/values";
4
4
  import getLodash from 'lodash/get';
5
- import { Binary, BSONRegExp, BSONSymbol, Code, DBRef, Decimal128, Double, Int32, Long, MaxKey, MinKey, ObjectId, Timestamp, UUID } from 'bson';
5
+ import { Binary, BSONRegExp, BSONSymbol, Code, DBRef, Decimal128, Double, Int32, Long, MaxKey, MinKey, ObjectId, Timestamp, UUID } from 'bson/lib/bson.rn.cjs';
6
6
  import { bboxPolygon, booleanIntersects, booleanWithin, circle, distance, polygon } from "@turf/turf";
7
7
 
8
8
  const DirectionList = [1, -1, 'asc', 'desc', 'ascending', 'descending'];
@@ -118,8 +118,14 @@ export class MTStorage {
118
118
  const { createHash, awaitServer } = options || {};
119
119
  let hasFinished, hasCancelled;
120
120
 
121
+ const thisComplete = (...args) => {
122
+ if (hasFinished) return;
123
+ hasFinished = true;
124
+ onComplete?.(...args);
125
+ }
126
+
121
127
  if (typeof file !== 'string' || !file.trim()) {
122
- onComplete?.({ error: 'file_path_invalid', message: 'file must be a non-empty string in uploadFile()' });
128
+ thisComplete?.({ error: 'file_path_invalid', message: 'file must be a non-empty string in uploadFile()' });
123
129
  return () => { };
124
130
  }
125
131
  destination = destination?.trim?.();
@@ -127,12 +133,11 @@ export class MTStorage {
127
133
  try {
128
134
  validateDestination(destination);
129
135
  } catch (error) {
130
- onComplete?.({ error: 'destination_invalid', message: error });
136
+ thisComplete?.({ error: 'destination_invalid', message: error });
131
137
  return () => { };
132
138
  }
133
139
 
134
- const isAsset = (file.startsWith('ph://') || file.startsWith('content://'));
135
-
140
+ const isAsset = file.startsWith('ph://') || file.startsWith('content://');
136
141
  file = isAsset ? file.trim() : prefixStoragePath(file.trim());
137
142
 
138
143
  const { projectUrl, uglify, extraHeaders } = this.builder;
@@ -143,30 +148,28 @@ export class MTStorage {
143
148
  await awaitRefreshToken(projectUrl);
144
149
 
145
150
  if (hasCancelled) return;
146
- const progressListener = emitter.addListener('mt-uploading-progress', ({ processID: ref, sentBtyes, totalBytes }) => {
151
+ const progressListener = emitter.addListener('mt-uploading-progress', ({ processID: ref, sentBytes, totalBytes }) => {
147
152
  if (processID !== ref || hasFinished || hasCancelled) return;
148
- onProgress?.({ sentBtyes, totalBytes });
153
+ onProgress?.({ sentBytes, totalBytes });
149
154
  });
150
155
  const resultListener = emitter.addListener('mt-uploading-status', ({ processID: ref, error, errorDes, result }) => {
151
- if (processID !== ref || hasFinished) return;
156
+ if (processID !== ref) return;
152
157
  if (result)
153
158
  try {
154
159
  result = JSON.parse(result);
155
- } catch (e) { }
160
+ } catch (_) { }
156
161
 
157
162
  const downloadUrl = result?.downloadUrl || undefined;
158
-
159
- if (!hasFinished && !hasCancelled)
160
- onComplete?.(downloadUrl ? undefined : (result?.simpleError || { error, message: errorDes }), downloadUrl);
163
+ thisComplete?.(downloadUrl ? undefined : (result?.simpleError || { error, message: errorDes }), downloadUrl);
161
164
  resultListener.remove();
162
165
  progressListener.remove();
163
- hasFinished = true;
164
166
  });
167
+ const authToken = Scoped.AuthJWTToken[projectUrl];
165
168
 
166
169
  RNMTModule.uploadFile({
167
170
  url: EngineApi._uploadFile(projectUrl, uglify),
168
171
  file: isAsset ? file : file.substring('file://'.length),
169
- authToken: Scoped.AuthJWTToken[projectUrl],
172
+ ...authToken ? { authToken } : {},
170
173
  createHash: createHash ? 'yes' : 'no',
171
174
  destination,
172
175
  processID,
@@ -180,8 +183,8 @@ export class MTStorage {
180
183
  if (hasFinished || hasCancelled) return;
181
184
  hasCancelled = true;
182
185
  setTimeout(() => {
183
- onComplete?.({ error: 'upload_aborted', message: 'The upload process was aborted' });
184
- }, 1);
186
+ thisComplete?.({ error: 'upload_aborted', message: 'The upload process was aborted' });
187
+ }, 0);
185
188
  RNMTModule.cancelUpload(processID);
186
189
  }
187
190
  }