filemail-sdk 4.5.1 → 4.6.1
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/dist/src/client/downloaderCore.js +16 -28
- package/dist/src/client/downloaderCore.js.map +1 -1
- package/dist/src/client/loggers/dummyLogger.d.ts +1 -0
- package/dist/src/client/loggers/dummyLogger.js +1 -0
- package/dist/src/client/loggers/dummyLogger.js.map +1 -1
- package/dist/src/client/loggers/logger.d.ts +7 -0
- package/dist/src/client/node/nodeTransferDownloader.d.ts +3 -1
- package/dist/src/client/node/nodeTransferDownloader.js +13 -4
- package/dist/src/client/node/nodeTransferDownloader.js.map +1 -1
- package/dist/src/client/node/nodeTransferUploader.d.ts +5 -0
- package/dist/src/client/node/nodeTransferUploader.js +46 -28
- package/dist/src/client/node/nodeTransferUploader.js.map +1 -1
- package/dist/src/client/transferDownloader.d.ts +1 -1
- package/dist/src/client/transferUploaderOptions.d.ts +1 -0
- package/dist/src/downloader/chunkDownloader.js +10 -8
- package/dist/src/downloader/chunkDownloader.js.map +1 -1
- package/dist/src/downloader/downloadOptions.d.ts +5 -16
- package/dist/src/downloader/downloadOptions.js +7 -18
- package/dist/src/downloader/downloadOptions.js.map +1 -1
- package/dist/src/downloader/downloadStatus/downloadFileProgress.d.ts +2 -1
- package/dist/src/downloader/downloadStatus/downloadFileProgress.js +2 -1
- package/dist/src/downloader/downloadStatus/downloadFileProgress.js.map +1 -1
- package/dist/src/downloader/downloadStatus/downloadFilePromise.d.ts +6 -0
- package/dist/src/downloader/downloadStatus/downloadFilePromise.js +32 -0
- package/dist/src/downloader/downloadStatus/downloadFilePromise.js.map +1 -0
- package/dist/src/downloader/downloadStatus/downloadState.d.ts +2 -1
- package/dist/src/downloader/downloadStatus/downloadState.js +40 -18
- package/dist/src/downloader/downloadStatus/downloadState.js.map +1 -1
- package/dist/src/downloader/downloadTracker.js +219 -130
- package/dist/src/downloader/downloadTracker.js.map +1 -1
- package/dist/src/downloader/dtos/downloadCommand.d.ts +2 -2
- package/dist/src/downloader/dtos/downloadErrorCode.d.ts +8 -1
- package/dist/src/downloader/dtos/downloadErrorCode.js +7 -0
- package/dist/src/downloader/dtos/downloadErrorCode.js.map +1 -1
- package/dist/src/downloader/dtos/downloadEvent.d.ts +3 -1
- package/dist/src/downloader/dtos/downloadEvent.js +2 -0
- package/dist/src/downloader/dtos/downloadEvent.js.map +1 -1
- package/dist/src/downloader/dtos/downloadFileChunkInfo.d.ts +13 -0
- package/dist/src/downloader/dtos/downloadFileChunkInfo.js.map +1 -1
- package/dist/src/downloader/dtos/downloadFileInfo.d.ts +11 -7
- package/dist/src/downloader/dtos/downloadFileInfo.js +14 -9
- package/dist/src/downloader/dtos/downloadFileInfo.js.map +1 -1
- package/dist/src/downloader/dtos/downloadTrackerFileInfo.d.ts +13 -9
- package/dist/src/downloader/dtos/downloadTrackerFileProgressInfo.d.ts +22 -0
- package/dist/src/downloader/dtos/downloadTrackerFileProgressInfo.js +2 -0
- package/dist/src/downloader/dtos/downloadTrackerFileProgressInfo.js.map +1 -0
- package/dist/src/downloader/dtos/downloadTrackerProgressInfo.d.ts +2 -2
- package/dist/src/downloader/eventArgs/downloadTrackingFailedEventArgs.d.ts +8 -0
- package/dist/src/downloader/eventArgs/downloadTrackingFailedEventArgs.js +2 -0
- package/dist/src/downloader/eventArgs/downloadTrackingFailedEventArgs.js.map +1 -0
- package/dist/src/downloader/filesDownloader.js +169 -80
- package/dist/src/downloader/filesDownloader.js.map +1 -1
- package/dist/src/downloader/filesPreparer.js +2 -6
- package/dist/src/downloader/filesPreparer.js.map +1 -1
- package/dist/src/utils/api/dtos/getTransferRequest.d.ts +2 -0
- package/dist/src/utils/api/node/nodeApiClient.js +11 -1
- package/dist/src/utils/api/node/nodeApiClient.js.map +1 -1
- package/dist/src/utils/fileSystem/fileSystemService.d.ts +6 -1
- package/dist/src/utils/fileSystem/node/nodeFileSystemService.d.ts +6 -1
- package/dist/src/utils/fileSystem/node/nodeFileSystemService.js +39 -7
- package/dist/src/utils/fileSystem/node/nodeFileSystemService.js.map +1 -1
- package/dist/src/utils/fileSystem/parsedPath.d.ts +8 -0
- package/dist/src/utils/fileSystem/parsedPath.js +2 -0
- package/dist/src/utils/fileSystem/parsedPath.js.map +1 -0
- package/dist/src/utils/pseudoRandom.d.ts +2 -1
- package/dist/src/utils/pseudoRandom.js +4 -1
- package/dist/src/utils/pseudoRandom.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"downloadEvent.js","sourceRoot":"","sources":["../../../../src/downloader/dtos/downloadEvent.ts"],"names":[],"mappings":"AAAA,IAAK,
|
|
1
|
+
{"version":3,"file":"downloadEvent.js","sourceRoot":"","sources":["../../../../src/downloader/dtos/downloadEvent.ts"],"names":[],"mappings":"AAAA,IAAK,qBA4BJ;AA5BD,WAAK,qBAAqB;IACtB,4DAAmC,CAAA;IACnC,kEAAyC,CAAA;IACzC,gEAAuC,CAAA;IACvC,wFAA+D,CAAA;IAC/D,sDAA6B,CAAA;IAC7B,oDAA2B,CAAA;IAC3B,sEAA6C,CAAA;IAC7C,oEAA2C,CAAA;IAC3C,0EAAiD,CAAA;IACjD,wEAA+C,CAAA;IAC/C,0EAAiD,CAAA;IACjD,kEAAyC,CAAA;IACzC,sEAA6C,CAAA;IAC7C,4EAAmD,CAAA;IACnD,0EAAiD,CAAA;IACjD,oEAA2C,CAAA;IAC3C,oEAA2C,CAAA;IAC3C,8CAAqB,CAAA;IACrB,4CAAmB,CAAA;IACnB,4CAAmB,CAAA;IACnB,4CAAmB,CAAA;IACnB,0CAAiB,CAAA;IACjB,0DAAiC,CAAA;IACjC,gDAAuB,CAAA;IACvB,0EAAiD,CAAA;IACjD,sFAA6D,CAAA;IAC7D,0EAAiD,CAAA;AACrD,CAAC,EA5BI,qBAAqB,KAArB,qBAAqB,QA4BzB;AAED,eAAe,qBAAqB,CAAC"}
|
|
@@ -3,9 +3,22 @@ import type DownloadFileInfo from "./downloadFileInfo";
|
|
|
3
3
|
export default class DownloadFileChunkInfo {
|
|
4
4
|
readonly id: string;
|
|
5
5
|
readonly file: DownloadFileInfo;
|
|
6
|
+
/**
|
|
7
|
+
* Zero-based index of first byte of this chunk within a file.
|
|
8
|
+
*/
|
|
6
9
|
readonly start: number | null;
|
|
10
|
+
/**
|
|
11
|
+
* Zero-based index of last byte of this chunk within a file.
|
|
12
|
+
*/
|
|
7
13
|
readonly end: number | null;
|
|
14
|
+
/**
|
|
15
|
+
* Zero-based index of the chunk within a file.
|
|
16
|
+
*/
|
|
8
17
|
readonly chunkNumber: number;
|
|
18
|
+
/**
|
|
19
|
+
* The real chunk size in bytes (no matter of downloader chunkSize setting). For unspecified downloader chunkSize
|
|
20
|
+
* this will equal to file size. Otherwise it is calculated as end-start+1
|
|
21
|
+
*/
|
|
9
22
|
readonly chunkSize: number;
|
|
10
23
|
isCompleted: boolean;
|
|
11
24
|
isFailed: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"downloadFileChunkInfo.js","sourceRoot":"","sources":["../../../../src/downloader/dtos/downloadFileChunkInfo.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,OAAO,OAAO,qBAAqB;
|
|
1
|
+
{"version":3,"file":"downloadFileChunkInfo.js","sourceRoot":"","sources":["../../../../src/downloader/dtos/downloadFileChunkInfo.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,OAAO,OAAO,qBAAqB;IA4BtC,YAAY,IAAsB,EAAE,WAAmB,EAAE,YAA2B;QANpF,gBAAW,GAAG,KAAK,CAAC;QACpB,aAAQ,GAAG,KAAK,CAAC;QACjB,YAAO,GAAyB,IAAI,CAAC;QACrC,oBAAe,GAAG,CAAC,CAAC;QACpB,YAAO,GAAG,CAAC,CAAC;QAGR,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,UAAU,IAAI,WAAW,EAAE,CAAC;QAC9C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,YAAY,KAAK,IAAI,EAAE;YACvB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;YAClB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;YAChB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC;SACrC;aACI;YACD,IAAI,CAAC,KAAK,GAAG,WAAW,GAAG,YAAa,CAAC;YACzC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,GAAG,YAAa,GAAG,CAAC,CAAC,CAAC;YAC1E,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;SAC9C;IACL,CAAC;IAED,IAAI,CAAC,MAAqB;QACtB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IAC1B,CAAC;IAED,QAAQ;QACJ,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;IAC1B,CAAC;IAED,WAAW,CAAC,eAAuB;QAC/B,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,IAAI,CAAC,SAAS,KAAK,CAAC;YACpB,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC;;YAEnB,IAAI,CAAC,OAAO,GAAG,CAAC,GAAG,GAAG,eAAe,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;IAChE,CAAC;CACJ"}
|
|
@@ -11,6 +11,7 @@ export default class DownloadFileInfo {
|
|
|
11
11
|
isCompleted: boolean;
|
|
12
12
|
isFailed: boolean;
|
|
13
13
|
lastSuccessfulChunkNumber: number | null;
|
|
14
|
+
temporaryDownloadPath: string | null;
|
|
14
15
|
/**
|
|
15
16
|
* How many bytes have been downloaded counting only completed chunks.
|
|
16
17
|
*/
|
|
@@ -24,25 +25,28 @@ export default class DownloadFileInfo {
|
|
|
24
25
|
chunkCount: number;
|
|
25
26
|
chunks: DownloadFileChunkInfo[];
|
|
26
27
|
failures: DownloadError[];
|
|
27
|
-
downloadName: string | null;
|
|
28
28
|
/**
|
|
29
29
|
* @param externalId ID of the file - returned in Filemail web API transfer response.
|
|
30
30
|
* @param url Absolute url to the file on Fileserver.
|
|
31
31
|
* @param name File name as it is returned from Filemail web API (relative to transfer folder, / is the path separator - api convention).
|
|
32
32
|
* @param sizeInBytes Size of the file - obtained from Filemail web API transfer response.
|
|
33
|
-
* @param downloadPath Optional:
|
|
34
|
-
* based on download folder
|
|
35
|
-
* @param
|
|
36
|
-
*
|
|
33
|
+
* @param downloadPath Optional: absolute download path where the file should be saved. This param is also used when restoring interrupted download.
|
|
34
|
+
* When this parameter is null it will be set automatically by the downloader based on download folder (configured in the downloader) + {@link name}.
|
|
35
|
+
* @param chunkCount How many chunks this file contains. Note: zero-byte (empty) files have 1 chunk.
|
|
36
|
+
* @param temporaryDownloadPath Temporary download path - where the file is physically download until it is complete (and then renamed to {@link downloadPath}).
|
|
37
37
|
*/
|
|
38
|
-
constructor(externalId: string, url: string, name: string, sizeInBytes: number, downloadPath?: string | null,
|
|
38
|
+
constructor(externalId: string, url: string, name: string, sizeInBytes: number, downloadPath?: string | null, chunkCount?: number | null, temporaryDownloadPath?: string | null);
|
|
39
39
|
start(): void;
|
|
40
40
|
starting(): void;
|
|
41
41
|
fail(reason: DownloadError): void;
|
|
42
|
-
complete(): void;
|
|
42
|
+
complete(finalDownloadPath: string): void;
|
|
43
43
|
chunkStarted(chunk: DownloadFileChunkInfo): void;
|
|
44
44
|
chunkCompleted(chunk: DownloadFileChunkInfo): void;
|
|
45
45
|
chunkFailed(chunk: DownloadFileChunkInfo): void;
|
|
46
|
+
/**
|
|
47
|
+
* Updates file's {@link downloadedBytes} by adding number of downloaded bytes of every pending chunk to {@link downloadedBytes_bank}.
|
|
48
|
+
* Once {@link downloadedBytes} is updated - progress in percent is updated too ({@link percent}).
|
|
49
|
+
*/
|
|
46
50
|
updateProgress(): void;
|
|
47
51
|
get lastProgressTick(): number | null;
|
|
48
52
|
get hasDownloadPath(): boolean;
|
|
@@ -16,12 +16,12 @@ class DownloadFileInfo {
|
|
|
16
16
|
* @param url Absolute url to the file on Fileserver.
|
|
17
17
|
* @param name File name as it is returned from Filemail web API (relative to transfer folder, / is the path separator - api convention).
|
|
18
18
|
* @param sizeInBytes Size of the file - obtained from Filemail web API transfer response.
|
|
19
|
-
* @param downloadPath Optional:
|
|
20
|
-
* based on download folder
|
|
21
|
-
* @param
|
|
22
|
-
*
|
|
19
|
+
* @param downloadPath Optional: absolute download path where the file should be saved. This param is also used when restoring interrupted download.
|
|
20
|
+
* When this parameter is null it will be set automatically by the downloader based on download folder (configured in the downloader) + {@link name}.
|
|
21
|
+
* @param chunkCount How many chunks this file contains. Note: zero-byte (empty) files have 1 chunk.
|
|
22
|
+
* @param temporaryDownloadPath Temporary download path - where the file is physically download until it is complete (and then renamed to {@link downloadPath}).
|
|
23
23
|
*/
|
|
24
|
-
constructor(externalId, url, name, sizeInBytes, downloadPath = null,
|
|
24
|
+
constructor(externalId, url, name, sizeInBytes, downloadPath = null, chunkCount = null, temporaryDownloadPath = null) {
|
|
25
25
|
_DownloadFileInfo_lastProgressTick.set(this, null);
|
|
26
26
|
_DownloadFileInfo_downloadPath.set(this, null);
|
|
27
27
|
_DownloadFileInfo_pendingChunks.set(this, []);
|
|
@@ -31,6 +31,7 @@ class DownloadFileInfo {
|
|
|
31
31
|
this.isCompleted = false;
|
|
32
32
|
this.isFailed = false;
|
|
33
33
|
this.lastSuccessfulChunkNumber = null;
|
|
34
|
+
this.temporaryDownloadPath = null;
|
|
34
35
|
/**
|
|
35
36
|
* How many bytes have been downloaded counting only completed chunks.
|
|
36
37
|
*/
|
|
@@ -48,9 +49,8 @@ class DownloadFileInfo {
|
|
|
48
49
|
this.url = url;
|
|
49
50
|
this.name = name;
|
|
50
51
|
this.sizeInBytes = sizeInBytes;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
this.downloadName = downloadName;
|
|
52
|
+
__classPrivateFieldSet(this, _DownloadFileInfo_downloadPath, downloadPath, "f");
|
|
53
|
+
this.temporaryDownloadPath = temporaryDownloadPath;
|
|
54
54
|
if (chunkCount !== null)
|
|
55
55
|
this.chunkCount = chunkCount;
|
|
56
56
|
}
|
|
@@ -64,7 +64,8 @@ class DownloadFileInfo {
|
|
|
64
64
|
this.isFailed = true;
|
|
65
65
|
this.failures.push(reason);
|
|
66
66
|
}
|
|
67
|
-
complete() {
|
|
67
|
+
complete(finalDownloadPath) {
|
|
68
|
+
this.downloadPath = finalDownloadPath;
|
|
68
69
|
this.isFailed = false;
|
|
69
70
|
this.isCompleted = true;
|
|
70
71
|
}
|
|
@@ -92,6 +93,10 @@ class DownloadFileInfo {
|
|
|
92
93
|
if (idx > -1)
|
|
93
94
|
__classPrivateFieldGet(this, _DownloadFileInfo_pendingChunks, "f").splice(idx, 1);
|
|
94
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Updates file's {@link downloadedBytes} by adding number of downloaded bytes of every pending chunk to {@link downloadedBytes_bank}.
|
|
98
|
+
* Once {@link downloadedBytes} is updated - progress in percent is updated too ({@link percent}).
|
|
99
|
+
*/
|
|
95
100
|
updateProgress() {
|
|
96
101
|
__classPrivateFieldSet(this, _DownloadFileInfo_lastProgressTick, new Date().getTime(), "f");
|
|
97
102
|
let downloaded = this.downloadedBytes_bank;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"downloadFileInfo.js","sourceRoot":"","sources":["../../../../src/downloader/dtos/downloadFileInfo.ts"],"names":[],"mappings":";;;;;;;;;;;;AAGA,MAAqB,gBAAgB;IAiCjC;;;;;;;;;OASG;IACH,
|
|
1
|
+
{"version":3,"file":"downloadFileInfo.js","sourceRoot":"","sources":["../../../../src/downloader/dtos/downloadFileInfo.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,26 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Note: this is a JSON DTO interface - short property names are to minimize state size on disk in case there are downloads with lots of files.
|
|
3
|
+
*/
|
|
1
4
|
interface DownloadTrackerFileInfo {
|
|
2
5
|
/**
|
|
3
|
-
*
|
|
4
|
-
*/
|
|
5
|
-
id: string;
|
|
6
|
-
/**
|
|
7
|
-
* Download url
|
|
6
|
+
* Download url.
|
|
8
7
|
*/
|
|
9
8
|
u: string;
|
|
10
9
|
/**
|
|
11
|
-
* Size in bytes
|
|
10
|
+
* Size in bytes.
|
|
12
11
|
*/
|
|
13
12
|
s: number;
|
|
14
13
|
/**
|
|
15
|
-
* File name (as
|
|
14
|
+
* File name (as it came from api, so potentially including folders, separator is always a forward slash). E.g. /some/folder/file.txt
|
|
16
15
|
*/
|
|
17
16
|
n: string;
|
|
18
17
|
/**
|
|
19
|
-
* Absolute download path
|
|
18
|
+
* Absolute download path - final file download download path. E.g. C:\downloads\file.txt
|
|
20
19
|
*/
|
|
21
20
|
dp: string;
|
|
22
21
|
/**
|
|
23
|
-
*
|
|
22
|
+
* Temporary download path - physical file download download path until it is complete. Ee.g. C:\downloads\unconfiormed_123456.fmdownload
|
|
23
|
+
* Allows avoiding naming conflicts and indicating to end users that file is in progress.
|
|
24
|
+
*/
|
|
25
|
+
tdp: string | null;
|
|
26
|
+
/**
|
|
27
|
+
* Number of chunks.
|
|
24
28
|
*/
|
|
25
29
|
cc: number;
|
|
26
30
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Note: this is a JSON DTO interface - short property names are to minimize state size on disk in case there are downloads with lots of files.
|
|
3
|
+
*/
|
|
4
|
+
interface DownloadTrackerFileProgressInfo {
|
|
5
|
+
/**
|
|
6
|
+
* Number of last successful chunk (only consecutive chunks count).
|
|
7
|
+
*/
|
|
8
|
+
ok: number | null;
|
|
9
|
+
/**
|
|
10
|
+
* Is this file in "failed" state?
|
|
11
|
+
*/
|
|
12
|
+
er: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Is this file in "completed" state?
|
|
15
|
+
*/
|
|
16
|
+
c: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Was this file ever written?
|
|
19
|
+
*/
|
|
20
|
+
wr: boolean;
|
|
21
|
+
}
|
|
22
|
+
export default DownloadTrackerFileProgressInfo;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"downloadTrackerFileProgressInfo.js","sourceRoot":"","sources":["../../../../src/downloader/dtos/downloadTrackerFileProgressInfo.ts"],"names":[],"mappings":""}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type DownloadTrackerFileProgressInfo from "./downloadTrackerFileProgressInfo";
|
|
2
2
|
interface DownloadTrackerProgressInfo {
|
|
3
|
-
|
|
3
|
+
trackedFiles: Record<string, DownloadTrackerFileProgressInfo>;
|
|
4
4
|
activeTime: number;
|
|
5
5
|
}
|
|
6
6
|
export default DownloadTrackerProgressInfo;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"downloadTrackingFailedEventArgs.js","sourceRoot":"","sources":["../../../../src/downloader/eventArgs/downloadTrackingFailedEventArgs.ts"],"names":[],"mappings":""}
|
|
@@ -9,12 +9,15 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _FilesDownloader_instances, _FilesDownloader_transferId, _FilesDownloader_trackId, _FilesDownloader_downloadId, _FilesDownloader_files, _FilesDownloader_downloadState, _FilesDownloader_options, _FilesDownloader_semaphore, _FilesDownloader_fileSystem, _FilesDownloader_apiClient, _FilesDownloader_fileserverClientFactory, _FilesDownloader_chunkStreamProviderFactory, _FilesDownloader_eventsEngine,
|
|
12
|
+
var _FilesDownloader_instances, _FilesDownloader_transferId, _FilesDownloader_trackId, _FilesDownloader_downloadId, _FilesDownloader_files, _FilesDownloader_downloadState, _FilesDownloader_options, _FilesDownloader_semaphore, _FilesDownloader_fileSystem, _FilesDownloader_apiClient, _FilesDownloader_fileserverClientFactory, _FilesDownloader_chunkStreamProviderFactory, _FilesDownloader_eventsEngine, _FilesDownloader_ongoingChunkDownloads, _FilesDownloader_ongoingFileDownloads, _FilesDownloader_deleteAllTemporaryAndCompletedFiles, _FilesDownloader_registerTransferDownload, _FilesDownloader_addEventListeners, _FilesDownloader_removeEventListeners, _FilesDownloader_onFileCompleted, _FilesDownloader_onFileCompleting, _FilesDownloader_onFileSupersized, _FilesDownloader_onFileFailed, _FilesDownloader_createDownloadFile, _FilesDownloader_autoGenerateUniqueDownloadFile, _FilesDownloader_downloadAllChunksForFile, _FilesDownloader_downloadSingleChunk, _FilesDownloader_cleanupDownloaderStateAfterFilesLoop, _FilesDownloader_isDownloaderRunning, _FilesDownloader_cleanupEmptyDownloadFolderIfConfigured, _FilesDownloader_doTheFinalFileRenameAfterFilesIsDownloaded;
|
|
13
13
|
import DownloadState from "./downloadStatus/downloadState.js";
|
|
14
14
|
import DownloadError from "./dtos/downloadError.js";
|
|
15
15
|
import TransferDownloadEvent from "./dtos/downloadEvent.js";
|
|
16
16
|
import ChunkDownloader from "./chunkDownloader.js";
|
|
17
17
|
import TransferStatus from "../utils/types/transferStatus.js";
|
|
18
|
+
import DownloadErrorCode from "./dtos/downloadErrorCode.js";
|
|
19
|
+
import PseudoRandom from "../utils/pseudoRandom.js";
|
|
20
|
+
import DownloadFilePromise from "./downloadStatus/downloadFilePromise.js";
|
|
18
21
|
class FilesDownloader {
|
|
19
22
|
constructor(transferId, trackId, downloadId, files, oldState, fileSystem, semaphore, eventsEngine, options, apiClient, fileserverClientFactory, chunkStreamProviderFactory) {
|
|
20
23
|
_FilesDownloader_instances.add(this);
|
|
@@ -30,13 +33,28 @@ class FilesDownloader {
|
|
|
30
33
|
_FilesDownloader_fileserverClientFactory.set(this, void 0);
|
|
31
34
|
_FilesDownloader_chunkStreamProviderFactory.set(this, void 0);
|
|
32
35
|
_FilesDownloader_eventsEngine.set(this, void 0);
|
|
36
|
+
_FilesDownloader_ongoingChunkDownloads.set(this, void 0);
|
|
37
|
+
_FilesDownloader_ongoingFileDownloads.set(this, void 0);
|
|
38
|
+
_FilesDownloader_onFileCompleted.set(this, async (args) => {
|
|
39
|
+
__classPrivateFieldGet(this, _FilesDownloader_ongoingFileDownloads, "f")[args.file.id]?.complete();
|
|
40
|
+
});
|
|
41
|
+
_FilesDownloader_onFileCompleting.set(this, async (args) => {
|
|
42
|
+
// note the args.file.downloadPath may not be final - if a file with this name eixsts the following method will generate new name e.g. "file.txt" --> "file (1).txt"
|
|
43
|
+
const finalDownloadPath = await __classPrivateFieldGet(this, _FilesDownloader_instances, "m", _FilesDownloader_doTheFinalFileRenameAfterFilesIsDownloaded).call(this, args.file);
|
|
44
|
+
__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").fileCompleted(args.file.id, finalDownloadPath);
|
|
45
|
+
});
|
|
33
46
|
_FilesDownloader_onFileSupersized.set(this, async (fileArgs) => {
|
|
34
|
-
if (await __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").getFileSize(fileArgs.file.
|
|
35
|
-
await __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").truncateFile(fileArgs.file.
|
|
47
|
+
if (fileArgs.file.temporaryDownloadPath && await __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").getFileSize(fileArgs.file.temporaryDownloadPath) > fileArgs.file.size)
|
|
48
|
+
await __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").truncateFile(fileArgs.file.temporaryDownloadPath, fileArgs.file.size);
|
|
36
49
|
});
|
|
37
50
|
_FilesDownloader_onFileFailed.set(this, async (args) => {
|
|
38
|
-
|
|
39
|
-
|
|
51
|
+
__classPrivateFieldGet(this, _FilesDownloader_ongoingFileDownloads, "f")[args.file.id]?.complete();
|
|
52
|
+
if (__classPrivateFieldGet(this, _FilesDownloader_options, "f").deleteFailedFilesFromDisk) {
|
|
53
|
+
if (args.file.downloadPath && args.file.downloaded > 0)
|
|
54
|
+
await __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").deleteFile(args.file.downloadPath);
|
|
55
|
+
if (args.file.temporaryDownloadPath)
|
|
56
|
+
await __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").deleteFile(args.file.temporaryDownloadPath);
|
|
57
|
+
}
|
|
40
58
|
});
|
|
41
59
|
if (!transferId)
|
|
42
60
|
throw new DownloadError(`No transfer specified`);
|
|
@@ -58,99 +76,68 @@ class FilesDownloader {
|
|
|
58
76
|
__classPrivateFieldSet(this, _FilesDownloader_apiClient, apiClient, "f");
|
|
59
77
|
__classPrivateFieldSet(this, _FilesDownloader_fileserverClientFactory, fileserverClientFactory, "f");
|
|
60
78
|
__classPrivateFieldSet(this, _FilesDownloader_chunkStreamProviderFactory, chunkStreamProviderFactory, "f");
|
|
79
|
+
__classPrivateFieldSet(this, _FilesDownloader_ongoingChunkDownloads, {}, "f");
|
|
80
|
+
__classPrivateFieldSet(this, _FilesDownloader_ongoingFileDownloads, {}, "f");
|
|
61
81
|
}
|
|
62
82
|
async start() {
|
|
63
83
|
try {
|
|
64
|
-
let fileDownloaderIsFinished = false;
|
|
65
84
|
__classPrivateFieldGet(this, _FilesDownloader_instances, "m", _FilesDownloader_addEventListeners).call(this);
|
|
66
|
-
|
|
85
|
+
let isDownloaderRunning = true;
|
|
86
|
+
while (isDownloaderRunning) {
|
|
67
87
|
__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").start();
|
|
68
|
-
const ongoingChunkDownloads = {};
|
|
69
88
|
// MAIN FILE LOOP
|
|
70
89
|
for (const file of __classPrivateFieldGet(this, _FilesDownloader_files, "f")) {
|
|
71
90
|
if (file.isCompleted || file.isFailed)
|
|
72
91
|
continue;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if
|
|
76
|
-
|
|
77
|
-
//
|
|
78
|
-
file.
|
|
79
|
-
|
|
80
|
-
if (__classPrivateFieldGet(this, _FilesDownloader_options, "f").failFileWhenPreventingOverwrite)
|
|
81
|
-
__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").fileFailed(file, new DownloadError(`File ${file.downloadPath} already exists and download option "preventOverwrites" is set to true`));
|
|
82
|
-
else
|
|
83
|
-
__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").fileCompleted(file);
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").fileStarting(file);
|
|
87
|
-
if (fileExistsAndHasCorrectSize === false) {
|
|
88
|
-
try {
|
|
89
|
-
__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").fileCreating(file);
|
|
90
|
-
await __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").createFile(file.downloadPath, file.sizeInBytes);
|
|
91
|
-
__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").fileCreated(file);
|
|
92
|
-
}
|
|
93
|
-
catch (fileWriteErr) {
|
|
94
|
-
const errorCode = __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").fileErrorToDownloadErrorCode(fileWriteErr);
|
|
95
|
-
__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").fileFailed(file, new DownloadError(`File ${file.downloadPath} could not be created with specific size. See 'cause' for more details.`, { cause: fileWriteErr }, errorCode));
|
|
92
|
+
if (__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").isRunning === false)
|
|
93
|
+
break;
|
|
94
|
+
// figure out if we are downloading a new file or resuming a file that was interrupted
|
|
95
|
+
if (file.wasEverWritten) {
|
|
96
|
+
// this a resumed file (recreated from progress.json) - it must already exist under its temporary path
|
|
97
|
+
if (!file.temporaryDownloadPath) {
|
|
98
|
+
__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").fileFailed(file, new DownloadError(`File ${file.downloadPath} was supposed to be resumed but its temporary path is not known.`, undefined, DownloadErrorCode.ResumedFilePathNotSpecified));
|
|
96
99
|
continue;
|
|
97
100
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
for (const chunk of file.chunks) {
|
|
102
|
-
if (chunk.isCompleted || chunk.isFailed)
|
|
103
|
-
continue;
|
|
104
|
-
const releaseSemaphore = await __classPrivateFieldGet(this, _FilesDownloader_semaphore, "f").acquire();
|
|
105
|
-
if (__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").isRunning === false) {
|
|
106
|
-
// downloader is not running - stop trying more chunks
|
|
107
|
-
releaseSemaphore();
|
|
108
|
-
break;
|
|
109
|
-
}
|
|
110
|
-
if (file.isFailed) {
|
|
111
|
-
// do not try to download more chunks if the file has failed
|
|
112
|
-
releaseSemaphore();
|
|
113
|
-
break;
|
|
114
|
-
}
|
|
115
|
-
const chunkDownloader = new ChunkDownloader(__classPrivateFieldGet(this, _FilesDownloader_transferId, "f"), file, chunk, __classPrivateFieldGet(this, _FilesDownloader_downloadState, "f"), __classPrivateFieldGet(this, _FilesDownloader_options, "f"), __classPrivateFieldGet(this, _FilesDownloader_fileserverClientFactory, "f"), __classPrivateFieldGet(this, _FilesDownloader_chunkStreamProviderFactory, "f"), __classPrivateFieldGet(this, _FilesDownloader_eventsEngine, "f"));
|
|
116
|
-
const chunkPromise = chunkDownloader.download();
|
|
117
|
-
ongoingChunkDownloads[chunk.id] = chunkPromise;
|
|
118
|
-
chunkPromise.finally(() => {
|
|
119
|
-
releaseSemaphore();
|
|
120
|
-
delete ongoingChunkDownloads[chunk.id];
|
|
121
|
-
});
|
|
101
|
+
if ((await __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").pathExists(file.temporaryDownloadPath)) === false) {
|
|
102
|
+
__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").fileFailed(file, new DownloadError(`File ${file.downloadPath} was supposed to be resumed at ${file.temporaryDownloadPath}, but it does not exist on disk anymore.`, undefined, DownloadErrorCode.ResumedFileNotFound));
|
|
103
|
+
continue;
|
|
122
104
|
}
|
|
123
|
-
if (__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").isRunning === false)
|
|
124
|
-
break;
|
|
125
105
|
}
|
|
126
106
|
else {
|
|
127
|
-
//
|
|
128
|
-
file
|
|
129
|
-
|
|
107
|
+
// in some edge cases the temporary file may exist nad its name be persisted in the tracker file
|
|
108
|
+
// but the wasEverWrittenFlag was not yet set - just abandon such temporary file (it will be 'empty' - null bytes only)
|
|
109
|
+
if (file.temporaryDownloadPath)
|
|
110
|
+
__classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").deleteFile(file.temporaryDownloadPath);
|
|
111
|
+
// this is a new file - create it
|
|
112
|
+
await __classPrivateFieldGet(this, _FilesDownloader_instances, "m", _FilesDownloader_createDownloadFile).call(this, file);
|
|
130
113
|
}
|
|
114
|
+
__classPrivateFieldGet(this, _FilesDownloader_ongoingFileDownloads, "f")[file.externalId] = new DownloadFilePromise(file.externalId);
|
|
115
|
+
__classPrivateFieldGet(this, _FilesDownloader_ongoingFileDownloads, "f")[file.externalId].awaiter.then(id => {
|
|
116
|
+
delete __classPrivateFieldGet(this, _FilesDownloader_ongoingFileDownloads, "f")[id];
|
|
117
|
+
});
|
|
118
|
+
__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").fileStarting(file);
|
|
119
|
+
// note: this call does not really wait for all chunks to be downloaded, but until all chunks of a file have been **scheduled**
|
|
120
|
+
await __classPrivateFieldGet(this, _FilesDownloader_instances, "m", _FilesDownloader_downloadAllChunksForFile).call(this, file);
|
|
121
|
+
// so when we are here, the file is not complete
|
|
122
|
+
// to track completeness of a file we look at events emitted by this.#downloadState
|
|
131
123
|
}
|
|
132
|
-
// wait for remaining pending chunks
|
|
133
|
-
await Promise.allSettled(Object.values(ongoingChunkDownloads));
|
|
134
124
|
// when we got here it's either pause request, stop request (which is just like pause but without waiting for pending chunks), abort request (cancel the download entirely) or everything is complete;
|
|
125
|
+
// wait for any remaining pending chunks
|
|
126
|
+
await Promise.allSettled(Object.values(__classPrivateFieldGet(this, _FilesDownloader_ongoingChunkDownloads, "f")));
|
|
127
|
+
// wait for any remaining pending files
|
|
128
|
+
// note: we cannot rely just on chunk downloads being completed, because downloading chunks
|
|
129
|
+
// doesn't a file is complete; last phase of file completion is actually renaming the file
|
|
130
|
+
// from a temporary name (unconfirmed_123.fmdownload) to its real name (which may need adjustments if a file with same already exists
|
|
131
|
+
// in such case a rename will be executed automatically e.g. file.txt --> file (1).txt).
|
|
132
|
+
await Promise.allSettled(Object.values(__classPrivateFieldGet(this, _FilesDownloader_ongoingFileDownloads, "f")).map(x => x.awaiter));
|
|
135
133
|
if (__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").status === TransferStatus.Pausing) {
|
|
136
|
-
// set status to paused and await until resume/abort
|
|
134
|
+
// set status to paused and await until resume/abort
|
|
137
135
|
await __classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").paused();
|
|
138
136
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (__classPrivateFieldGet(this, _FilesDownloader_options, "f").deleteAbortedDownloadsFromDisk)
|
|
142
|
-
await __classPrivateFieldGet(this, _FilesDownloader_instances, "m", _FilesDownloader_deleteEntireDownload).call(this);
|
|
143
|
-
}
|
|
144
|
-
else if (__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").allFilesCompletedOrFailed) {
|
|
145
|
-
await __classPrivateFieldGet(this, _FilesDownloader_instances, "m", _FilesDownloader_registerTransferDownload).call(this);
|
|
146
|
-
__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").completed();
|
|
147
|
-
}
|
|
148
|
-
if (__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").status === TransferStatus.Completed || __classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").status === TransferStatus.Aborted) {
|
|
149
|
-
fileDownloaderIsFinished = true;
|
|
150
|
-
if (__classPrivateFieldGet(this, _FilesDownloader_options, "f").deleteEmptyDownloadFoldersAfterDownload && await __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").folderIsEmpty(__classPrivateFieldGet(this, _FilesDownloader_options, "f").downloadFolder))
|
|
151
|
-
await __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").deleteFolder(__classPrivateFieldGet(this, _FilesDownloader_options, "f").downloadFolder);
|
|
152
|
-
}
|
|
137
|
+
await __classPrivateFieldGet(this, _FilesDownloader_instances, "m", _FilesDownloader_cleanupDownloaderStateAfterFilesLoop).call(this);
|
|
138
|
+
isDownloaderRunning = __classPrivateFieldGet(this, _FilesDownloader_instances, "m", _FilesDownloader_isDownloaderRunning).call(this);
|
|
153
139
|
}
|
|
140
|
+
await __classPrivateFieldGet(this, _FilesDownloader_instances, "m", _FilesDownloader_cleanupEmptyDownloadFolderIfConfigured).call(this);
|
|
154
141
|
return __classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").getCurrentState(true);
|
|
155
142
|
}
|
|
156
143
|
catch (error) {
|
|
@@ -165,15 +152,18 @@ class FilesDownloader {
|
|
|
165
152
|
}
|
|
166
153
|
}
|
|
167
154
|
requestPause() {
|
|
155
|
+
Object.values(__classPrivateFieldGet(this, _FilesDownloader_ongoingFileDownloads, "f")).forEach(filePromise => filePromise.complete());
|
|
168
156
|
return __classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").requestPause({ interruptPendingChunks: false });
|
|
169
157
|
}
|
|
170
158
|
requestStop() {
|
|
159
|
+
Object.values(__classPrivateFieldGet(this, _FilesDownloader_ongoingFileDownloads, "f")).forEach(filePromise => filePromise.complete());
|
|
171
160
|
return __classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").requestPause({ interruptPendingChunks: true });
|
|
172
161
|
}
|
|
173
162
|
resume() {
|
|
174
163
|
return __classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").resume();
|
|
175
164
|
}
|
|
176
165
|
requestAbort() {
|
|
166
|
+
Object.values(__classPrivateFieldGet(this, _FilesDownloader_ongoingFileDownloads, "f")).forEach(filePromise => filePromise.complete());
|
|
177
167
|
return __classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").requestAbort();
|
|
178
168
|
}
|
|
179
169
|
get currentState() {
|
|
@@ -183,9 +173,13 @@ class FilesDownloader {
|
|
|
183
173
|
return __classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").status;
|
|
184
174
|
}
|
|
185
175
|
}
|
|
186
|
-
_FilesDownloader_transferId = new WeakMap(), _FilesDownloader_trackId = new WeakMap(), _FilesDownloader_downloadId = new WeakMap(), _FilesDownloader_files = new WeakMap(), _FilesDownloader_downloadState = new WeakMap(), _FilesDownloader_options = new WeakMap(), _FilesDownloader_semaphore = new WeakMap(), _FilesDownloader_fileSystem = new WeakMap(), _FilesDownloader_apiClient = new WeakMap(), _FilesDownloader_fileserverClientFactory = new WeakMap(), _FilesDownloader_chunkStreamProviderFactory = new WeakMap(), _FilesDownloader_eventsEngine = new WeakMap(), _FilesDownloader_onFileSupersized = new WeakMap(), _FilesDownloader_onFileFailed = new WeakMap(), _FilesDownloader_instances = new WeakSet(),
|
|
187
|
-
for (const file of __classPrivateFieldGet(this, _FilesDownloader_files, "f"))
|
|
188
|
-
|
|
176
|
+
_FilesDownloader_transferId = new WeakMap(), _FilesDownloader_trackId = new WeakMap(), _FilesDownloader_downloadId = new WeakMap(), _FilesDownloader_files = new WeakMap(), _FilesDownloader_downloadState = new WeakMap(), _FilesDownloader_options = new WeakMap(), _FilesDownloader_semaphore = new WeakMap(), _FilesDownloader_fileSystem = new WeakMap(), _FilesDownloader_apiClient = new WeakMap(), _FilesDownloader_fileserverClientFactory = new WeakMap(), _FilesDownloader_chunkStreamProviderFactory = new WeakMap(), _FilesDownloader_eventsEngine = new WeakMap(), _FilesDownloader_ongoingChunkDownloads = new WeakMap(), _FilesDownloader_ongoingFileDownloads = new WeakMap(), _FilesDownloader_onFileCompleted = new WeakMap(), _FilesDownloader_onFileCompleting = new WeakMap(), _FilesDownloader_onFileSupersized = new WeakMap(), _FilesDownloader_onFileFailed = new WeakMap(), _FilesDownloader_instances = new WeakSet(), _FilesDownloader_deleteAllTemporaryAndCompletedFiles = async function _FilesDownloader_deleteAllTemporaryAndCompletedFiles() {
|
|
177
|
+
for (const file of __classPrivateFieldGet(this, _FilesDownloader_files, "f")) {
|
|
178
|
+
if (file.temporaryDownloadPath)
|
|
179
|
+
await __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").deleteFile(file.temporaryDownloadPath);
|
|
180
|
+
if (file.isCompleted)
|
|
181
|
+
await __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").deleteFile(file.downloadPath);
|
|
182
|
+
}
|
|
189
183
|
}, _FilesDownloader_registerTransferDownload = async function _FilesDownloader_registerTransferDownload() {
|
|
190
184
|
__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").registeringTransferDownload();
|
|
191
185
|
await __classPrivateFieldGet(this, _FilesDownloader_apiClient, "f").registerTransferDownload({
|
|
@@ -195,11 +189,106 @@ _FilesDownloader_transferId = new WeakMap(), _FilesDownloader_trackId = new Weak
|
|
|
195
189
|
browser: __classPrivateFieldGet(this, _FilesDownloader_options, "f").userAgent,
|
|
196
190
|
});
|
|
197
191
|
}, _FilesDownloader_addEventListeners = function _FilesDownloader_addEventListeners() {
|
|
192
|
+
__classPrivateFieldGet(this, _FilesDownloader_eventsEngine, "f").addEventListener(TransferDownloadEvent.FileDownloadCompleted, __classPrivateFieldGet(this, _FilesDownloader_onFileCompleted, "f"));
|
|
193
|
+
__classPrivateFieldGet(this, _FilesDownloader_eventsEngine, "f").addEventListener(TransferDownloadEvent.FileDownloadCompleting, __classPrivateFieldGet(this, _FilesDownloader_onFileCompleting, "f"));
|
|
198
194
|
__classPrivateFieldGet(this, _FilesDownloader_eventsEngine, "f").addEventListener(TransferDownloadEvent.FileDownloadFailed, __classPrivateFieldGet(this, _FilesDownloader_onFileFailed, "f"));
|
|
199
195
|
__classPrivateFieldGet(this, _FilesDownloader_eventsEngine, "f").addEventListener(TransferDownloadEvent.PossibleSupersizedFile, __classPrivateFieldGet(this, _FilesDownloader_onFileSupersized, "f"));
|
|
200
196
|
}, _FilesDownloader_removeEventListeners = function _FilesDownloader_removeEventListeners() {
|
|
197
|
+
__classPrivateFieldGet(this, _FilesDownloader_eventsEngine, "f").removeEventListener(TransferDownloadEvent.FileDownloadCompleted, __classPrivateFieldGet(this, _FilesDownloader_onFileCompleted, "f"));
|
|
198
|
+
__classPrivateFieldGet(this, _FilesDownloader_eventsEngine, "f").removeEventListener(TransferDownloadEvent.FileDownloadCompleting, __classPrivateFieldGet(this, _FilesDownloader_onFileCompleting, "f"));
|
|
201
199
|
__classPrivateFieldGet(this, _FilesDownloader_eventsEngine, "f").removeEventListener(TransferDownloadEvent.FileDownloadFailed, __classPrivateFieldGet(this, _FilesDownloader_onFileFailed, "f"));
|
|
202
200
|
__classPrivateFieldGet(this, _FilesDownloader_eventsEngine, "f").removeEventListener(TransferDownloadEvent.PossibleSupersizedFile, __classPrivateFieldGet(this, _FilesDownloader_onFileSupersized, "f"));
|
|
201
|
+
}, _FilesDownloader_createDownloadFile = async function _FilesDownloader_createDownloadFile(file) {
|
|
202
|
+
__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").fileCreating(file);
|
|
203
|
+
await __classPrivateFieldGet(this, _FilesDownloader_instances, "m", _FilesDownloader_autoGenerateUniqueDownloadFile).call(this, file);
|
|
204
|
+
__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").fileCreated(file);
|
|
205
|
+
}, _FilesDownloader_autoGenerateUniqueDownloadFile = async function _FilesDownloader_autoGenerateUniqueDownloadFile(file) {
|
|
206
|
+
let counter = 0;
|
|
207
|
+
do {
|
|
208
|
+
const newFileName = `unconfirmed_${PseudoRandom.generateString(10)}.fmdownload`;
|
|
209
|
+
const newPath = __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").replaceFilenameInPath(file.downloadPath, newFileName);
|
|
210
|
+
if (await __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").createFile(newPath, false, file.sizeInBytes)) {
|
|
211
|
+
// eslint-disable-next-line no-param-reassign
|
|
212
|
+
file.temporaryDownloadPath = newPath;
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
counter += 1;
|
|
216
|
+
} while (counter < 10000);
|
|
217
|
+
throw new DownloadError(`Downloader could not generate unique download path for ${file.downloadPath}. It tried until counter=${counter}`, undefined, DownloadErrorCode.TooManyFileRenameAttempts);
|
|
218
|
+
}, _FilesDownloader_downloadAllChunksForFile = async function _FilesDownloader_downloadAllChunksForFile(file) {
|
|
219
|
+
if (file.chunks.length) {
|
|
220
|
+
// MAIN CHUNK LOOP
|
|
221
|
+
for (const chunk of file.chunks) {
|
|
222
|
+
if (chunk.isCompleted || chunk.isFailed)
|
|
223
|
+
continue;
|
|
224
|
+
const downloadScheduled = await __classPrivateFieldGet(this, _FilesDownloader_instances, "m", _FilesDownloader_downloadSingleChunk).call(this, file, chunk);
|
|
225
|
+
if (downloadScheduled === false) {
|
|
226
|
+
// downloader is not running or file is in failed state - stop the chunk loop
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
// zerobyte file
|
|
233
|
+
file.updateProgress();
|
|
234
|
+
__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").fileCompleting(file);
|
|
235
|
+
}
|
|
236
|
+
}, _FilesDownloader_downloadSingleChunk = async function _FilesDownloader_downloadSingleChunk(file, chunk) {
|
|
237
|
+
const releaseSemaphore = await __classPrivateFieldGet(this, _FilesDownloader_semaphore, "f").acquire();
|
|
238
|
+
if (__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").isRunning === false) {
|
|
239
|
+
// downloader is not running - stop trying more chunks
|
|
240
|
+
releaseSemaphore();
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
if (file.isFailed) {
|
|
244
|
+
// do not try to download more chunks if the file has failed
|
|
245
|
+
releaseSemaphore();
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
const chunkDownloader = new ChunkDownloader(__classPrivateFieldGet(this, _FilesDownloader_transferId, "f"), file, chunk, __classPrivateFieldGet(this, _FilesDownloader_downloadState, "f"), __classPrivateFieldGet(this, _FilesDownloader_options, "f"), __classPrivateFieldGet(this, _FilesDownloader_fileserverClientFactory, "f"), __classPrivateFieldGet(this, _FilesDownloader_chunkStreamProviderFactory, "f"), __classPrivateFieldGet(this, _FilesDownloader_eventsEngine, "f"));
|
|
249
|
+
const chunkPromise = chunkDownloader.download();
|
|
250
|
+
__classPrivateFieldGet(this, _FilesDownloader_ongoingChunkDownloads, "f")[chunk.id] = chunkPromise;
|
|
251
|
+
chunkPromise.finally(() => {
|
|
252
|
+
releaseSemaphore();
|
|
253
|
+
delete __classPrivateFieldGet(this, _FilesDownloader_ongoingChunkDownloads, "f")[chunk.id];
|
|
254
|
+
});
|
|
255
|
+
return true;
|
|
256
|
+
}, _FilesDownloader_cleanupDownloaderStateAfterFilesLoop = async function _FilesDownloader_cleanupDownloaderStateAfterFilesLoop() {
|
|
257
|
+
if (__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").status === TransferStatus.Aborting) {
|
|
258
|
+
__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").aborted();
|
|
259
|
+
if (__classPrivateFieldGet(this, _FilesDownloader_options, "f").deleteAbortedDownloadsFromDisk)
|
|
260
|
+
await __classPrivateFieldGet(this, _FilesDownloader_instances, "m", _FilesDownloader_deleteAllTemporaryAndCompletedFiles).call(this);
|
|
261
|
+
}
|
|
262
|
+
else if (__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").allFilesCompletedOrFailed) {
|
|
263
|
+
await __classPrivateFieldGet(this, _FilesDownloader_instances, "m", _FilesDownloader_registerTransferDownload).call(this);
|
|
264
|
+
__classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").completed();
|
|
265
|
+
}
|
|
266
|
+
}, _FilesDownloader_isDownloaderRunning = function _FilesDownloader_isDownloaderRunning() {
|
|
267
|
+
return __classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").status !== TransferStatus.Completed && __classPrivateFieldGet(this, _FilesDownloader_downloadState, "f").status !== TransferStatus.Aborted;
|
|
268
|
+
}, _FilesDownloader_cleanupEmptyDownloadFolderIfConfigured = async function _FilesDownloader_cleanupEmptyDownloadFolderIfConfigured() {
|
|
269
|
+
if (__classPrivateFieldGet(this, _FilesDownloader_options, "f").deleteEmptyDownloadFoldersAfterDownload && await __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").folderIsEmpty(__classPrivateFieldGet(this, _FilesDownloader_options, "f").downloadFolder))
|
|
270
|
+
await __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").deleteFolder(__classPrivateFieldGet(this, _FilesDownloader_options, "f").downloadFolder);
|
|
271
|
+
}, _FilesDownloader_doTheFinalFileRenameAfterFilesIsDownloaded = async function _FilesDownloader_doTheFinalFileRenameAfterFilesIsDownloaded(file) {
|
|
272
|
+
let created = false;
|
|
273
|
+
let counter = 0;
|
|
274
|
+
const original = __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").parseFilePath(file.downloadPath);
|
|
275
|
+
let newPathFormatted = file.downloadPath;
|
|
276
|
+
do {
|
|
277
|
+
created = await __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").createFile(newPathFormatted, false, file.size);
|
|
278
|
+
if (!created) {
|
|
279
|
+
counter += 1;
|
|
280
|
+
const newPath = {
|
|
281
|
+
dir: original.dir,
|
|
282
|
+
name: `${original.name} (${counter})`,
|
|
283
|
+
ext: original.ext,
|
|
284
|
+
};
|
|
285
|
+
newPathFormatted = __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").formatFilePath(newPath);
|
|
286
|
+
}
|
|
287
|
+
} while (created === false && counter < 10000);
|
|
288
|
+
if (!created)
|
|
289
|
+
throw new DownloadError(`Downloader could not rename temp file ${file.temporaryDownloadPath} to ${file.downloadPath}. It tried until counter=${counter}`, undefined, DownloadErrorCode.TooManyFileRenameAttempts);
|
|
290
|
+
await __classPrivateFieldGet(this, _FilesDownloader_fileSystem, "f").renameFile(file.temporaryDownloadPath, newPathFormatted);
|
|
291
|
+
return newPathFormatted;
|
|
203
292
|
};
|
|
204
293
|
export default FilesDownloader;
|
|
205
294
|
//# sourceMappingURL=filesDownloader.js.map
|