core-3nweb-client-lib 0.43.9 → 0.43.12

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.
Files changed (58) hide show
  1. package/build/api-defs/files.d.ts +32 -8
  2. package/build/api-defs/web3n.d.ts +2 -0
  3. package/build/core/asmail/inbox/index.js +1 -1
  4. package/build/core/asmail/inbox/msg-downloader.d.ts +2 -12
  5. package/build/core/asmail/inbox/msg-downloader.js +13 -46
  6. package/build/core/storage/synced/downloader.d.ts +6 -15
  7. package/build/core/storage/synced/downloader.js +25 -48
  8. package/build/core/storage/synced/obj-files.d.ts +4 -2
  9. package/build/core/storage/synced/obj-files.js +7 -7
  10. package/build/core/storage/synced/storage.d.ts +4 -2
  11. package/build/core/storage/synced/storage.js +2 -2
  12. package/build/core/storage/synced/upsyncer.d.ts +2 -4
  13. package/build/core/storage/synced/upsyncer.js +19 -13
  14. package/build/core-ipc/file.d.ts +10 -0
  15. package/build/core-ipc/file.js +23 -13
  16. package/build/core-ipc/fs.js +15 -8
  17. package/build/lib-client/3nstorage/storage-owner.js +36 -29
  18. package/build/lib-client/3nweb-signup.js +7 -7
  19. package/build/lib-client/asmail/recipient.js +14 -11
  20. package/build/lib-client/asmail/sender.js +24 -25
  21. package/build/lib-client/asmail/service-config.js +3 -6
  22. package/build/lib-client/cryptor/cryptor-wasm.js +1 -1
  23. package/build/lib-client/cryptor/cryptor.wasm +0 -0
  24. package/build/lib-client/fs-utils/files.js +4 -4
  25. package/build/lib-client/mailer-id/login.js +7 -7
  26. package/build/lib-client/mailer-id/provisioner.js +9 -7
  27. package/build/lib-client/objs-on-disk/file-writing-proc.d.ts +1 -1
  28. package/build/lib-client/objs-on-disk/obj-on-disk.d.ts +51 -3
  29. package/build/lib-client/objs-on-disk/obj-on-disk.js +414 -34
  30. package/build/lib-client/request-utils.d.ts +0 -7
  31. package/build/lib-client/request-utils.js +16 -11
  32. package/build/lib-client/service-locator.js +11 -8
  33. package/build/lib-client/user-with-mid-session.js +2 -6
  34. package/build/lib-client/user-with-pkl-session.js +25 -24
  35. package/build/lib-client/xsp-fs/common.d.ts +8 -3
  36. package/build/lib-client/xsp-fs/common.js +1 -1
  37. package/build/lib-client/xsp-fs/file.d.ts +3 -1
  38. package/build/lib-client/xsp-fs/file.js +4 -4
  39. package/build/lib-client/xsp-fs/folder-node.d.ts +1 -1
  40. package/build/lib-client/xsp-fs/folder-node.js +4 -4
  41. package/build/lib-client/xsp-fs/fs.d.ts +3 -1
  42. package/build/lib-client/xsp-fs/fs.js +4 -4
  43. package/build/lib-client/xsp-fs/node-in-fs.d.ts +6 -4
  44. package/build/lib-client/xsp-fs/node-in-fs.js +14 -9
  45. package/build/lib-common/buffer-utils.js +4 -1
  46. package/build/lib-common/exceptions/http.d.ts +11 -1
  47. package/build/lib-common/exceptions/http.js +10 -2
  48. package/build/lib-common/objs-on-disk/utils.d.ts +1 -1
  49. package/build/lib-common/processes/labelled-exec-pools.d.ts +1 -1
  50. package/build/lib-common/processes/labelled-exec-pools.js +8 -2
  51. package/build/protos/asmail.proto.js +545 -116
  52. package/build/protos/file.proto.js +485 -56
  53. package/build/protos/fs.proto.js +545 -116
  54. package/package.json +1 -1
  55. package/protos/file.proto +8 -2
  56. package/protos/fs.proto +3 -3
  57. /package/build/lib-common/objs-on-disk/{obj-file.d.ts → obj-version-file.d.ts} +0 -0
  58. /package/build/lib-common/objs-on-disk/{obj-file.js → obj-version-file.js} +0 -0
@@ -16,41 +16,54 @@
16
16
  this program. If not, see <http://www.gnu.org/licenses/>.
17
17
  */
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.ObjOnDisk = void 0;
19
+ exports.DownloadsRunner = exports.Download = exports.ObjOnDisk = void 0;
20
+ exports.splitSegsDownloads = splitSegsDownloads;
21
+ exports.generateSectionsFrom = generateSectionsFrom;
20
22
  const buffer_utils_1 = require("../../lib-common/buffer-utils");
21
23
  const wrapping_1 = require("../../lib-common/byte-streaming/wrapping");
22
24
  const assert_1 = require("../../lib-common/assert");
23
25
  const file_writing_proc_1 = require("./file-writing-proc");
24
26
  const operators_1 = require("rxjs/operators");
25
- const obj_file_1 = require("../../lib-common/objs-on-disk/obj-file");
27
+ const obj_version_file_1 = require("../../lib-common/objs-on-disk/obj-version-file");
26
28
  const utils_for_observables_1 = require("../../lib-common/utils-for-observables");
29
+ const types_1 = require("util/types");
30
+ const deferred_1 = require("../../lib-common/processes/deferred");
27
31
  class ObjOnDisk {
28
- constructor(objId, version, objFile, downloader, readable, getBaseSegsOnDisk) {
32
+ constructor(objId, version, objFile, downloader, readable, getBaseSegsOnDisk, downloadsInProgress = undefined) {
29
33
  this.objId = objId;
30
34
  this.version = version;
31
35
  this.objFile = objFile;
32
36
  this.downloader = downloader;
33
37
  this.readable = readable;
34
38
  this.getBaseSegsOnDisk = getBaseSegsOnDisk;
39
+ this.downloadsInProgress = downloadsInProgress;
35
40
  this.proxiedHeader = undefined;
41
+ if (this.downloadsInProgress) {
42
+ this.downloadsInProgress.saveSegs = this.objFile.saveSegs.bind(this.objFile);
43
+ this.downloadsInProgress.segsThatNeedDownload = this.segsThatNeedDownload.bind(this);
44
+ }
36
45
  Object.seal(this);
37
46
  }
38
47
  static async forExistingFile(objId, version, path, downloader, getBase) {
39
- const objFile = await obj_file_1.ObjVersionFile.forExisting(path);
48
+ const objFile = await obj_version_file_1.ObjVersionFile.forExisting(path);
40
49
  return new ObjOnDisk(objId, version, objFile, downloader, true, getBase);
41
50
  }
42
51
  static async createFileForExistingVersion(objId, version, path, downloader, getBase, initDownload) {
52
+ let download;
43
53
  if (!initDownload) {
44
- initDownload =
45
- await downloader.getLayoutWithHeaderAndFirstSegs(objId, version);
54
+ download = new Download(objId, version, downloader);
55
+ initDownload = await download.getInitParts();
56
+ }
57
+ else {
58
+ download = undefined;
46
59
  }
47
- const { layout, header, segs } = initDownload;
60
+ const { header, layout, segs } = initDownload;
48
61
  if (layout.base !== undefined) {
49
62
  // XXX with diff-ed downloads can't assume segs' offset to be 0
50
63
  throw new Error(`Current implementation cannot consume diff-ed downloads`);
51
64
  }
52
- const objFile = await obj_file_1.ObjVersionFile.createNew(path);
53
- const obj = new ObjOnDisk(objId, version, objFile, downloader, true, getBase);
65
+ const objFile = await obj_version_file_1.ObjVersionFile.createNew(path);
66
+ const obj = new ObjOnDisk(objId, version, objFile, downloader, true, getBase, download);
54
67
  await objFile.setSegsLayout(layout, false);
55
68
  await objFile.saveHeader(header, !segs);
56
69
  if (segs) {
@@ -59,7 +72,7 @@ class ObjOnDisk {
59
72
  return obj;
60
73
  }
61
74
  static async createFileForWriteOfNewVersion(objId, version, path, encSub, downloader, getBase) {
62
- const objFile = await obj_file_1.ObjVersionFile.createNew(path);
75
+ const objFile = await obj_version_file_1.ObjVersionFile.createNew(path);
63
76
  const obj = new ObjOnDisk(objId, version, objFile, downloader, false, getBase);
64
77
  const write$ = file_writing_proc_1.FileWritingProc.makeFor(objFile, encSub)
65
78
  .pipe((0, operators_1.tap)({
@@ -104,12 +117,21 @@ class ObjOnDisk {
104
117
  bytes.push(chunk);
105
118
  }
106
119
  else {
107
- const chunkBytes = await this.downloadAndSaveSegsChunk(chunk);
120
+ const chunkBytes = await this.downloads().downloadAndSaveSegsChunk(chunk);
108
121
  bytes.push(chunkBytes);
109
122
  }
110
123
  }
111
124
  return (0, buffer_utils_1.joinByteArrs)(bytes);
112
125
  }
126
+ downloads() {
127
+ if (!this.downloadsInProgress) {
128
+ if (!this.downloader) {
129
+ throw new Error(`Object ${this.objId}, version ${this.version}, is not on a disk.`);
130
+ }
131
+ this.downloadsInProgress = new Download(this.objId, this.version, this.downloader, this.objFile.saveSegs.bind(this.objFile), this.segsThatNeedDownload.bind(this));
132
+ }
133
+ return this.downloadsInProgress;
134
+ }
113
135
  async readSegsOnlyFromDisk(offset, len) {
114
136
  const segsLocations = this.objFile.segsLocations(offset, len);
115
137
  const bytesAndChunks = [];
@@ -158,26 +180,13 @@ class ObjOnDisk {
158
180
  }
159
181
  return bytesAndChunks;
160
182
  }
161
- async downloadAndSaveSegsChunk(chunk) {
162
- if (!this.downloader) {
163
- throw new Error(`Object ${this.objId}, version ${this.version}, segments section ofs=${chunk.thisVerOfs}, len=${chunk.len} is not on a disk.`);
164
- }
165
- const chunkBytes = await this.downloader.getSegs(this.objId, this.version, chunk.thisVerOfs, chunk.thisVerOfs + chunk.len);
166
- if (chunkBytes.length !== chunk.len) {
167
- throw new Error(`Download yielded a different length of a segment section`);
168
- }
169
- const baseVerOfs = ((chunk.type === 'base') ?
170
- chunk.baseVerOfs : undefined);
171
- await this.objFile.saveSegs(chunkBytes, chunk.thisVerOfs, baseVerOfs, true);
172
- return chunkBytes;
173
- }
174
183
  getSrc() {
175
184
  if (!this.readable) {
176
185
  throw new Error(`Version ${this.version} of obj ${this.objId} is not readable, yet`);
177
186
  }
178
- const segSrc = (0, wrapping_1.wrapAndSyncSource)(new ByteSourceFromObjOnDisk((ofs, len) => this.readSegs(ofs, len), () => this.objFile.getTotalSegsLen()));
187
+ const segSrc = (0, wrapping_1.wrapAndSyncSource)(new ByteSourceFromObjOnDisk(this.readSegs.bind(this), this.objFile.getTotalSegsLen.bind(this.objFile)));
179
188
  const objSrc = {
180
- readHeader: () => this.readHeader(),
189
+ readHeader: this.readHeader.bind(this),
181
190
  segSrc,
182
191
  version: this.version
183
192
  };
@@ -195,10 +204,10 @@ class ObjOnDisk {
195
204
  segsThatNeedDownload() {
196
205
  const totalLen = this.objFile.getTotalSegsLen();
197
206
  const allSegs = this.objFile.segsLocations(0, totalLen);
198
- return allSegs.filter(({ type }) => (type === 'new'));
207
+ return allSegs.filter(({ type }) => ((type === 'new') || (type === 'base')));
199
208
  }
200
209
  doesFileNeedDownload() {
201
- return (this.segsThatNeedDownload().length === 0);
210
+ return (this.segsThatNeedDownload().length !== 0);
202
211
  }
203
212
  numOfBytesNeedingDownload() {
204
213
  let totalLen = 0;
@@ -207,16 +216,387 @@ class ObjOnDisk {
207
216
  }
208
217
  return totalLen;
209
218
  }
210
- async downloadMissingSections() {
211
- const needDownload = this.segsThatNeedDownload();
212
- for (const chunk of needDownload) {
213
- await this.downloadAndSaveSegsChunk(chunk);
214
- }
219
+ startDownloadInBackground(eventSink) {
220
+ return this.downloads().downloadAllInBackground(eventSink);
215
221
  }
216
222
  }
217
223
  exports.ObjOnDisk = ObjOnDisk;
218
224
  Object.freeze(ObjOnDisk.prototype);
219
225
  Object.freeze(ObjOnDisk);
226
+ class Download {
227
+ constructor(objId, version, downloader, saveSegs, segsThatNeedDownload) {
228
+ this.objId = objId;
229
+ this.version = version;
230
+ this.downloader = downloader;
231
+ this.saveSegs = saveSegs;
232
+ this.segsThatNeedDownload = segsThatNeedDownload;
233
+ this.segsAsapRequest = [];
234
+ this.initDataRequest = undefined;
235
+ this.inBkgrnd = undefined;
236
+ Object.seal(this);
237
+ }
238
+ getInitParts() {
239
+ if (!this.initDataRequest) {
240
+ this.initDataRequest = (0, deferred_1.defer)();
241
+ }
242
+ this.downloader.schedule(this);
243
+ return this.initDataRequest.promise;
244
+ }
245
+ downloadAndSaveSegsChunk(chunk) {
246
+ if (!this.saveSegs) {
247
+ throw new Error(`saveSegs is not initialized`);
248
+ }
249
+ // XXX
250
+ // - check existing requests for overlaps and if there
251
+ // - overlaps are cut out into promise only section
252
+ // - resulting sections' deferred/promised bytes are all awaited, and combined in returned promise
253
+ const segments = [];
254
+ const deferred = (0, deferred_1.defer)();
255
+ this.segsAsapRequest.push({
256
+ chunk,
257
+ deferred,
258
+ chunkBytes: [],
259
+ segments: segments
260
+ });
261
+ const { thisVerOfs: ofs, len } = chunk;
262
+ const generator = generateSectionsFrom(this.downloader.splitSegsDownloads(ofs, ofs + len));
263
+ const next = generator.next();
264
+ segments.push({
265
+ deferred: (0, deferred_1.defer)(),
266
+ sectionBytes: [],
267
+ generator,
268
+ nextSection: next.value
269
+ });
270
+ this.downloader.schedule(this);
271
+ return deferred.promise;
272
+ }
273
+ downloadAllInBackground(eventSink) {
274
+ if (!this.segsThatNeedDownload) {
275
+ throw new Error(`segsThatNeedDownload is not initialized`);
276
+ }
277
+ if (this.inBkgrnd) {
278
+ return this.inBkgrnd.downloadTaskId;
279
+ }
280
+ const chunks = this.segsThatNeedDownload();
281
+ if (chunks.length === 0) {
282
+ return;
283
+ }
284
+ this.inBkgrnd = {
285
+ downloadTaskId: Math.floor(Math.random() * Number.MAX_SAFE_INTEGER),
286
+ eventSink,
287
+ totalBytesToDownload: chunks.reduce((total, chunk) => (total + chunk.len), 0)
288
+ };
289
+ eventSink({
290
+ type: 'download-started',
291
+ downloadTaskId: this.inBkgrnd.downloadTaskId,
292
+ path: '',
293
+ version: this.version,
294
+ totalBytesToDownload: this.inBkgrnd.totalBytesToDownload
295
+ });
296
+ if (this.segsAsapRequest.length === 0) {
297
+ this.inBkgrnd.chunks = chunks;
298
+ }
299
+ this.downloader.schedule(this);
300
+ return this.inBkgrnd.downloadTaskId;
301
+ }
302
+ nextActionType() {
303
+ if (this.initDataRequest) {
304
+ return { runASAP: true };
305
+ }
306
+ else if (this.segsAsapRequest.length > 0) {
307
+ return { runASAP: true };
308
+ }
309
+ else if (this.inBkgrnd) {
310
+ return { runASAP: false };
311
+ }
312
+ else {
313
+ return;
314
+ }
315
+ }
316
+ startNextAction() {
317
+ if (this.initDataRequest) {
318
+ return this.processInitDataRequest();
319
+ }
320
+ else if (this.segsAsapRequest.length > 0) {
321
+ return this.processSomeAsapSegs();
322
+ }
323
+ else if (this.inBkgrnd) {
324
+ return this.processBkgrnd();
325
+ }
326
+ else {
327
+ return;
328
+ }
329
+ }
330
+ async processInitDataRequest() {
331
+ var _a, _b;
332
+ try {
333
+ const parts = await this.downloader.getLayoutWithHeaderAndFirstSegs(this.objId, this.version);
334
+ (_a = this.initDataRequest) === null || _a === void 0 ? void 0 : _a.resolve(parts);
335
+ }
336
+ catch (exc) {
337
+ (_b = this.initDataRequest) === null || _b === void 0 ? void 0 : _b.reject(exc);
338
+ }
339
+ finally {
340
+ this.initDataRequest = undefined;
341
+ }
342
+ }
343
+ async processSomeAsapSegs() {
344
+ var _a;
345
+ if ((_a = this.inBkgrnd) === null || _a === void 0 ? void 0 : _a.runData) {
346
+ this.inBkgrnd.runData = undefined;
347
+ this.inBkgrnd.chunks = undefined;
348
+ }
349
+ const { chunk, chunkBytes, deferred, segments } = this.segsAsapRequest[0];
350
+ const segment = segments[0];
351
+ try {
352
+ if ((0, types_1.isPromise)(segment)) {
353
+ chunkBytes.push(await segment);
354
+ segments.shift();
355
+ }
356
+ else if (segment.nextSection) {
357
+ const baseVerOfs = ((chunk.type === 'base') ? chunk.baseVerOfs : undefined);
358
+ const { ofs, len } = segment.nextSection;
359
+ const bytes = await this.downloader.getSegs(this.objId, this.version, ofs, ofs + len);
360
+ await this.saveSegs(bytes, ofs, baseVerOfs, true);
361
+ segment.sectionBytes.push(bytes);
362
+ const next = segment.generator.next();
363
+ if (next.done) {
364
+ chunkBytes.push(...segment.sectionBytes);
365
+ segments.shift();
366
+ }
367
+ else {
368
+ segment.nextSection = next.value;
369
+ }
370
+ }
371
+ else {
372
+ chunkBytes.push(...segment.sectionBytes);
373
+ segments.shift();
374
+ }
375
+ }
376
+ catch (err) {
377
+ deferred.reject(err);
378
+ this.segsAsapRequest.shift();
379
+ }
380
+ if (segments.length === 0) {
381
+ deferred.resolve((0, buffer_utils_1.joinByteArrs)(chunkBytes));
382
+ this.segsAsapRequest.shift();
383
+ }
384
+ }
385
+ async processBkgrnd() {
386
+ if (!this.inBkgrnd) {
387
+ return;
388
+ }
389
+ if (!this.inBkgrnd.chunks) {
390
+ this.inBkgrnd.chunks = this.segsThatNeedDownload();
391
+ if (this.inBkgrnd.chunks.length === 0) {
392
+ this.completeBkgrnd();
393
+ return;
394
+ }
395
+ }
396
+ else if (this.inBkgrnd.chunks.length === 0) {
397
+ this.completeBkgrnd();
398
+ return;
399
+ }
400
+ const chunk = this.inBkgrnd.chunks[0];
401
+ if (!this.inBkgrnd.runData) {
402
+ const { thisVerOfs: ofs, len } = chunk;
403
+ this.inBkgrnd.runData = {
404
+ generator: generateSectionsFrom(this.downloader.splitSegsDownloads(ofs, ofs + len))
405
+ };
406
+ }
407
+ const next = this.inBkgrnd.runData.generator.next();
408
+ if (next.done) {
409
+ this.inBkgrnd.chunks.shift();
410
+ return;
411
+ }
412
+ const baseVerOfs = ((chunk.type === 'base') ? chunk.baseVerOfs : undefined);
413
+ const { len, ofs } = next.value;
414
+ this.inBkgrnd.runData.currentDownload = { ofs, len, deferred: (0, deferred_1.defer)() };
415
+ this.inBkgrnd.runData.currentDownload.deferred.promise.catch(noop);
416
+ try {
417
+ const bytes = await this.downloader.getSegs(this.objId, this.version, ofs, ofs + len);
418
+ await this.saveSegs(bytes, ofs, baseVerOfs, true);
419
+ this.emitDownloadEvent('download-progress', {
420
+ totalBytesToDownload: this.inBkgrnd.totalBytesToDownload,
421
+ bytesLeftToDownload: this.inBkgrnd.chunks.slice(1).reduce((total, chunk) => (total + chunk.len), 0) + (chunk.len - (ofs + len - chunk.thisVerOfs))
422
+ });
423
+ this.inBkgrnd.runData.currentDownload.deferred.resolve(bytes);
424
+ }
425
+ catch (exc) {
426
+ this.inBkgrnd.runData.currentDownload.deferred.reject(exc);
427
+ }
428
+ finally {
429
+ this.inBkgrnd.runData.currentDownload = undefined;
430
+ }
431
+ }
432
+ completeBkgrnd() {
433
+ this.emitDownloadEvent('download-done', {});
434
+ this.inBkgrnd = undefined;
435
+ }
436
+ emitDownloadEvent(type, field) {
437
+ var _a;
438
+ (_a = this.inBkgrnd) === null || _a === void 0 ? void 0 : _a.eventSink({
439
+ type,
440
+ path: '',
441
+ version: this.version,
442
+ downloadTaskId: this.inBkgrnd.downloadTaskId,
443
+ ...field
444
+ });
445
+ }
446
+ }
447
+ exports.Download = Download;
448
+ Object.freeze(Download.prototype);
449
+ Object.freeze(Download);
450
+ class DownloadsRunner {
451
+ constructor(asapPoolMax = 5, longPoolMax = 1) {
452
+ this.downloads = new Map();
453
+ this.asapPool = makeExecPool(asapPoolMax);
454
+ this.longRunsPool = makeExecPool(longPoolMax);
455
+ Object.seal(this);
456
+ }
457
+ schedule(download) {
458
+ const found = this.downloads.get(download);
459
+ if (found) {
460
+ if (found.isRunning) {
461
+ return;
462
+ }
463
+ else {
464
+ const next = download.nextActionType();
465
+ if (!next) {
466
+ this.removeDownload(download);
467
+ return;
468
+ }
469
+ const pool = (next.runASAP ? this.asapPool : this.longRunsPool);
470
+ if (found.pool !== pool) {
471
+ removeFromArray(found.pool.queue, download);
472
+ found.pool = pool;
473
+ found.pool.queue.push(download);
474
+ }
475
+ }
476
+ }
477
+ else {
478
+ const next = download.nextActionType();
479
+ if (!next) {
480
+ this.removeDownload(download);
481
+ return;
482
+ }
483
+ const pool = (next.runASAP ? this.asapPool : this.longRunsPool);
484
+ this.downloads.set(download, { isRunning: false, pool });
485
+ pool.queue.push(download);
486
+ }
487
+ this.triggerRuns();
488
+ }
489
+ removeDownload(download) {
490
+ const found = this.downloads.get(download);
491
+ if (found) {
492
+ this.downloads.delete(download);
493
+ removeFromArray(found.pool.queue, download);
494
+ }
495
+ }
496
+ triggerRuns() {
497
+ this.triggerRunsInPool(this.asapPool);
498
+ this.triggerRunsInPool(this.longRunsPool);
499
+ }
500
+ triggerRunsInPool(pool) {
501
+ while ((pool.queue.length > 0) && (pool.numOfRunning < pool.max)) {
502
+ const download = pool.queue.shift();
503
+ const info = this.downloads.get(download);
504
+ if (!info) {
505
+ continue;
506
+ }
507
+ let promise = download.startNextAction();
508
+ if (!promise) {
509
+ this.removeDownload(download);
510
+ continue;
511
+ }
512
+ info.isRunning = true;
513
+ pool.numOfRunning += 1;
514
+ if (pool === this.asapPool) {
515
+ promise = promise.then(() => {
516
+ const next = download.nextActionType();
517
+ if (!next) {
518
+ this.removeDownload(download);
519
+ return;
520
+ }
521
+ if (next.runASAP) {
522
+ this.asapPool.queue.unshift(download);
523
+ }
524
+ else {
525
+ this.longRunsPool.queue.push(download);
526
+ info.pool = this.longRunsPool;
527
+ }
528
+ });
529
+ }
530
+ else {
531
+ promise = promise.then(() => {
532
+ const next = download.nextActionType();
533
+ if (!next) {
534
+ this.removeDownload(download);
535
+ return;
536
+ }
537
+ if (next.runASAP) {
538
+ this.asapPool.queue.push(download);
539
+ info.pool = this.asapPool;
540
+ }
541
+ else {
542
+ this.longRunsPool.queue.unshift(download);
543
+ }
544
+ }, (_exc) => {
545
+ this.longRunsPool.queue.unshift(download);
546
+ });
547
+ }
548
+ promise.finally(() => {
549
+ info.isRunning = false;
550
+ pool.numOfRunning -= 1;
551
+ this.triggerRuns();
552
+ });
553
+ }
554
+ }
555
+ }
556
+ exports.DownloadsRunner = DownloadsRunner;
557
+ Object.freeze(DownloadsRunner.prototype);
558
+ Object.freeze(DownloadsRunner);
559
+ function makeExecPool(max) {
560
+ return { queue: [], max, numOfRunning: 0 };
561
+ }
562
+ function removeFromArray(arr, elem) {
563
+ const ind = arr.indexOf(elem);
564
+ if (ind >= 0) {
565
+ arr.splice(ind, 1);
566
+ }
567
+ }
568
+ function splitSegsDownloads(start, end, max) {
569
+ const parts = [];
570
+ let ofs = start;
571
+ const repeatCount = Math.floor((end - start) / max);
572
+ if (repeatCount > 1) {
573
+ const repeatLen = max * repeatCount;
574
+ parts.push({ ofs, len: max, repeatCount, repeatLen });
575
+ ofs += repeatLen;
576
+ }
577
+ else if (repeatCount === 1) {
578
+ parts.push({ ofs, len: max });
579
+ ofs += max;
580
+ }
581
+ const tailLen = end - ofs;
582
+ if (tailLen > 0) {
583
+ parts.push({ ofs, len: tailLen });
584
+ }
585
+ return parts;
586
+ }
587
+ function* generateSectionsFrom(sections) {
588
+ for (const { ofs, len, repeatCount, repeatLen } of sections) {
589
+ if (repeatCount) {
590
+ for (let i = 0; i < repeatCount; i += 1) {
591
+ yield { ofs: ofs + (i * len), len };
592
+ }
593
+ }
594
+ else {
595
+ yield { ofs, len };
596
+ }
597
+ }
598
+ }
599
+ function noop() { }
220
600
  class ByteSourceFromObjOnDisk {
221
601
  constructor(readSegs, totalSegsLen) {
222
602
  this.readSegs = readSegs;
@@ -225,7 +605,7 @@ class ByteSourceFromObjOnDisk {
225
605
  Object.seal(this);
226
606
  }
227
607
  async readNext(len) {
228
- (0, assert_1.assert)((Number.isInteger(len) && (len >= 0)) || (len === undefined), 'Illegal length parameter given: ' + len);
608
+ (0, assert_1.assert)((len === undefined) || (Number.isInteger(len) && (len >= 0)), 'Illegal length parameter given: ' + len);
229
609
  const start = this.segsPointer;
230
610
  if (len === undefined) {
231
611
  const segsLen = this.totalSegsLen();
@@ -1,4 +1,3 @@
1
- import { HTTPException } from '../lib-common/exceptions/http';
2
1
  import * as https from 'https';
3
2
  import { ClientRequest } from 'http';
4
3
  export declare const SESSION_ID_HEADER = "X-Session-Id";
@@ -30,12 +29,6 @@ export type ContentType = 'application/json' | 'application/octet-stream' | 'tex
30
29
  export type RequestFn<T> = (opts: RequestOpts, contentType?: ContentType, reqBody?: Uint8Array) => Promise<Reply<T>>;
31
30
  export declare function processRequest<T>(requester: (opts: https.RequestOptions) => ClientRequest, httpsOpts: https.RequestOptions, opts: RequestOpts, reqBody: Uint8Array | undefined, attempt?: number): Promise<Reply<T>>;
32
31
  export declare function formHttpsReqOpts(opts: RequestOpts, contentType?: ContentType, reqBody?: Uint8Array): https.RequestOptions;
33
- /**
34
- * @param rep
35
- * @param errMsg
36
- * @return http exception based on given reply, with an optional message
37
- */
38
- export declare function makeException(rep: Reply<any>, errMsg?: string): HTTPException;
39
32
  export declare function extractIntHeader(rep: Reply<any>, headerName: string): number;
40
33
  export interface NetClient {
41
34
  /**
@@ -18,7 +18,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.CONTENT_TYPE_HEADER = exports.SESSION_ID_HEADER = void 0;
19
19
  exports.processRequest = processRequest;
20
20
  exports.formHttpsReqOpts = formHttpsReqOpts;
21
- exports.makeException = makeException;
22
21
  exports.extractIntHeader = extractIntHeader;
23
22
  exports.makeNetClient = makeNetClient;
24
23
  const http_1 = require("../lib-common/exceptions/http");
@@ -134,7 +133,11 @@ function formReply(res, resBody, reqOpts) {
134
133
  }
135
134
  catch (err) {
136
135
  if (resContentType === 'application/json') {
137
- throw (0, http_1.makeHTTPException)(reqOpts.url, reqOpts.method, status, `Cannot parse received bytes`, err);
136
+ throw (0, http_1.makeHTTPException)(reqOpts.url, reqOpts.method, status, {
137
+ message: `Cannot parse received bytes as json`,
138
+ cause: err,
139
+ malformedResponse: true
140
+ });
138
141
  }
139
142
  }
140
143
  }
@@ -168,18 +171,20 @@ function makeHeaders(headers) {
168
171
  }
169
172
  };
170
173
  }
171
- /**
172
- * @param rep
173
- * @param errMsg
174
- * @return http exception based on given reply, with an optional message
175
- */
176
- function makeException(rep, errMsg) {
177
- return (0, http_1.makeHTTPException)(rep.url, rep.method, rep.status, errMsg);
178
- }
174
+ // /**
175
+ // * @param rep
176
+ // * @param errMsg
177
+ // * @return http exception based on given reply, with an optional message
178
+ // */
179
+ // export function makeException(rep: Reply<any>, message?: string): HTTPException {
180
+ // return makeHTTPException(rep.url, rep.method, rep.status, { message });
181
+ // }
179
182
  function extractIntHeader(rep, headerName) {
180
183
  const intHeader = parseInt(rep.headers.get(headerName));
181
184
  if (isNaN(intHeader)) {
182
- throw makeException(rep, `Malformed response: header ${headerName} is missing or malformed`);
185
+ throw (0, http_1.makeMalformedReplyHTTPException)(rep, {
186
+ message: `Malformed response: header ${headerName} is missing or malformed`
187
+ });
183
188
  }
184
189
  return intHeader;
185
190
  }
@@ -23,8 +23,8 @@ exports.makeServiceLocator = makeServiceLocator;
23
23
  exports.getMailerIdInfoFor = getMailerIdInfoFor;
24
24
  const jwkeys_1 = require("../lib-common/jwkeys");
25
25
  const url_1 = require("url");
26
- const request_utils_1 = require("./request-utils");
27
26
  const runtime_1 = require("../lib-common/exceptions/runtime");
27
+ const http_1 = require("../lib-common/exceptions/http");
28
28
  async function readJSONLocatedAt(client, url) {
29
29
  if ((0, url_1.parse)(url).protocol !== 'https:') {
30
30
  throw new Error("Url protocol must be https.");
@@ -36,12 +36,12 @@ async function readJSONLocatedAt(client, url) {
36
36
  });
37
37
  if (rep.status === 200) {
38
38
  if (!rep.data) {
39
- throw (0, request_utils_1.makeException)(rep, 'Malformed reply');
39
+ throw (0, http_1.makeMalformedReplyHTTPException)(rep);
40
40
  }
41
41
  return rep;
42
42
  }
43
43
  else {
44
- throw (0, request_utils_1.makeException)(rep, 'Unexpected status');
44
+ throw (0, http_1.makeUnexpectedStatusHTTPException)(rep);
45
45
  }
46
46
  }
47
47
  function transformPathToCompleteUri(url, path, rep) {
@@ -49,7 +49,7 @@ function transformPathToCompleteUri(url, path, rep) {
49
49
  const protoAndHost = `${uInit.protocol}//${uInit.host}`;
50
50
  const uPath = (0, url_1.parse)(path);
51
51
  if (!uPath.path || !uPath.href || !uPath.href.startsWith(uPath.path)) {
52
- throw (0, request_utils_1.makeException)(rep, `Malformed path parameter ${path}`);
52
+ throw (0, http_1.makeMalformedReplyHTTPException)(rep, { message: `Malformed path parameter ${path}` });
53
53
  }
54
54
  if (uPath.href.startsWith('/')) {
55
55
  return `${protoAndHost}${uPath.href}`;
@@ -92,7 +92,7 @@ async function mailerIdInfoAt(client, url) {
92
92
  transform.provisioning = transformPathToCompleteUri(url, json.provisioning, rep);
93
93
  }
94
94
  else {
95
- throw (0, request_utils_1.makeException)(rep, 'Malformed reply');
95
+ throw (0, http_1.makeMalformedReplyHTTPException)(rep);
96
96
  }
97
97
  if ((0, jwkeys_1.isLikeSignedKeyCert)(json["current-cert"])) {
98
98
  transform.currentCert = json["current-cert"];
@@ -100,7 +100,7 @@ async function mailerIdInfoAt(client, url) {
100
100
  json["previous-certs"].filter(jwkeys_1.isLikeSignedKeyCert) : []);
101
101
  }
102
102
  else {
103
- throw (0, request_utils_1.makeException)(rep, 'Malformed reply');
103
+ throw (0, http_1.makeMalformedReplyHTTPException)(rep);
104
104
  }
105
105
  Object.freeze(transform);
106
106
  return transform;
@@ -224,7 +224,8 @@ const DNS_ERR_CODE = {
224
224
  NODATA: 'ENODATA',
225
225
  NOTFOUND: 'ENOTFOUND',
226
226
  ESERVFAIL: 'ESERVFAIL',
227
- ECONNREFUSED: 'ECONNREFUSED'
227
+ ECONNREFUSED: 'ECONNREFUSED',
228
+ ETIMEOUT: 'ETIMEOUT'
228
229
  };
229
230
  Object.freeze(DNS_ERR_CODE);
230
231
  function makeServiceLocator(resolver) {
@@ -244,7 +245,9 @@ function makeServiceLocator(resolver) {
244
245
  if (code === DNS_ERR_CODE.NODATA) {
245
246
  throw noServiceRecordExc(address);
246
247
  }
247
- else if ((code === DNS_ERR_CODE.ESERVFAIL) || (code === DNS_ERR_CODE.ECONNREFUSED)) {
248
+ else if ((code === DNS_ERR_CODE.ESERVFAIL)
249
+ || (code === DNS_ERR_CODE.ECONNREFUSED)
250
+ || (code === DNS_ERR_CODE.ETIMEOUT)) {
248
251
  throw noConnectionExc({ code, hostname, message });
249
252
  }
250
253
  else if (hostname) {