@droponair/sdk-js 0.35.0 → 0.36.0
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/CHANGELOG.md +8 -0
- package/dist/attachment/attachment-client.js +45 -11
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.36.0
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Downloads carry on where they stopped.** A download that breaks keeps what it
|
|
8
|
+
already had and asks the storage for the rest by range, retrying six times with a
|
|
9
|
+
growing wait. Nothing to change in an app: it happens inside `downloadAttachment`.
|
|
10
|
+
|
|
3
11
|
## 0.35.0
|
|
4
12
|
|
|
5
13
|
### Added
|
|
@@ -40,6 +40,9 @@ async function readWithProgress(resp, expectedBytes, onProgress) {
|
|
|
40
40
|
}
|
|
41
41
|
return out;
|
|
42
42
|
}
|
|
43
|
+
/** How many times a broken download is tried again, and how long between tries. */
|
|
44
|
+
const DOWNLOAD_ATTEMPTS = 6;
|
|
45
|
+
const DOWNLOAD_BACKOFF_MS = [2000, 4000, 8000, 15000, 30000];
|
|
43
46
|
async function sha256Hex(bytes) {
|
|
44
47
|
const digest = await crypto.subtle.digest('SHA-256', asBufferSource(bytes));
|
|
45
48
|
const hex = [];
|
|
@@ -225,18 +228,49 @@ class AttachmentClient {
|
|
|
225
228
|
* current device, unwraps it, then decrypts the stored bytes.
|
|
226
229
|
*/
|
|
227
230
|
async downloadAttachment(ref, opts = {}) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
231
|
+
// What has already arrived is kept between attempts, and the rest asked for by
|
|
232
|
+
// range, so a download that breaks does not start the file again. A fresh link
|
|
233
|
+
// is asked for each attempt, since a link lasts minutes.
|
|
234
|
+
let had = new Uint8Array(0);
|
|
235
|
+
let info;
|
|
236
|
+
for (let attempt = 1;; attempt++) {
|
|
237
|
+
try {
|
|
238
|
+
info = await this.getDownloadUrl(ref.attachmentId);
|
|
239
|
+
const headers = { ...info.headers };
|
|
240
|
+
if (had.length > 0)
|
|
241
|
+
headers.Range = `bytes=${had.length}-`;
|
|
242
|
+
const resp = await this.deps.fetchFn(info.url, { method: info.method, headers });
|
|
243
|
+
if (resp.status === 416 && had.length > 0)
|
|
244
|
+
break;
|
|
245
|
+
if (!resp.ok) {
|
|
246
|
+
const text = await resp.text().catch(() => '');
|
|
247
|
+
const message = `Failed to download attachment bytes (HTTP ${resp.status}): ${text}`;
|
|
248
|
+
// The link was good and the bytes are not there: deleted from storage
|
|
249
|
+
// underneath a record that still existed.
|
|
250
|
+
if (resp.status === 404)
|
|
251
|
+
throw new attachment_types_1.AttachmentUnavailableError(ref.attachmentId, 404, message);
|
|
252
|
+
throw new Error(message);
|
|
253
|
+
}
|
|
254
|
+
const resuming = resp.status === 206 && had.length > 0;
|
|
255
|
+
const base = resuming ? had : new Uint8Array(0);
|
|
256
|
+
const rest = await readWithProgress(resp, Math.max(0, info.sizeBytes - base.length), opts.onProgress
|
|
257
|
+
? (received, total) => opts.onProgress(base.length + received, base.length + total)
|
|
258
|
+
: undefined);
|
|
259
|
+
const joined = new Uint8Array(base.length + rest.length);
|
|
260
|
+
joined.set(base, 0);
|
|
261
|
+
joined.set(rest, base.length);
|
|
262
|
+
had = joined;
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
if (error instanceof attachment_types_1.AttachmentUnavailableError)
|
|
267
|
+
throw error;
|
|
268
|
+
if (attempt >= DOWNLOAD_ATTEMPTS)
|
|
269
|
+
throw error;
|
|
270
|
+
await new Promise((resolve) => setTimeout(resolve, DOWNLOAD_BACKOFF_MS[Math.min(attempt - 1, DOWNLOAD_BACKOFF_MS.length - 1)]));
|
|
271
|
+
}
|
|
238
272
|
}
|
|
239
|
-
let stored =
|
|
273
|
+
let stored = had;
|
|
240
274
|
if (ref.encryptionType === 'CLEARTEXT') {
|
|
241
275
|
await this.confirmReceived(ref.attachmentId);
|
|
242
276
|
return { attachmentId: ref.attachmentId, mimeType: info.mimeType, sizeBytes: info.sizeBytes, sha256: info.sha256, bytes: stored };
|
package/dist/version.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* MINOR, additive feature (e.g. multi-device payloads, new call event type)
|
|
8
8
|
* PATCH, bug-fix / perf improvement with no wire or API change
|
|
9
9
|
*/
|
|
10
|
-
export declare const SDK_VERSION = "0.
|
|
10
|
+
export declare const SDK_VERSION = "0.36.0";
|
|
11
11
|
/**
|
|
12
12
|
* Binary encrypted-payload format version.
|
|
13
13
|
* Included as the first byte of every encrypted payload so receivers can
|
package/dist/version.js
CHANGED
|
@@ -10,7 +10,7 @@ exports.PROTOCOL_VERSION = exports.PAYLOAD_FORMAT_VERSION = exports.SDK_VERSION
|
|
|
10
10
|
* MINOR, additive feature (e.g. multi-device payloads, new call event type)
|
|
11
11
|
* PATCH, bug-fix / perf improvement with no wire or API change
|
|
12
12
|
*/
|
|
13
|
-
exports.SDK_VERSION = '0.
|
|
13
|
+
exports.SDK_VERSION = '0.36.0';
|
|
14
14
|
/**
|
|
15
15
|
* Binary encrypted-payload format version.
|
|
16
16
|
* Included as the first byte of every encrypted payload so receivers can
|
package/package.json
CHANGED