diff options
-rw-r--r-- | editors/code/src/installation/download_file.ts | 36 |
1 files changed, 17 insertions, 19 deletions
diff --git a/editors/code/src/installation/download_file.ts b/editors/code/src/installation/download_file.ts index 71700ec8a..b31d2a736 100644 --- a/editors/code/src/installation/download_file.ts +++ b/editors/code/src/installation/download_file.ts | |||
@@ -1,8 +1,12 @@ | |||
1 | import fetch from "node-fetch"; | 1 | import fetch from "node-fetch"; |
2 | import * as fs from "fs"; | 2 | import * as fs from "fs"; |
3 | import * as stream from "stream"; | ||
4 | import * as util from "util"; | ||
3 | import { strict as assert } from "assert"; | 5 | import { strict as assert } from "assert"; |
4 | import { NestedError } from "ts-nested-error"; | 6 | import { NestedError } from "ts-nested-error"; |
5 | 7 | ||
8 | const pipeline = util.promisify(stream.pipeline); | ||
9 | |||
6 | class DownloadFileError extends NestedError {} | 10 | class DownloadFileError extends NestedError {} |
7 | 11 | ||
8 | /** | 12 | /** |
@@ -29,25 +33,19 @@ export async function downloadFile( | |||
29 | const totalBytes = Number(res.headers.get('content-length')); | 33 | const totalBytes = Number(res.headers.get('content-length')); |
30 | assert(!Number.isNaN(totalBytes), "Sanity check of content-length protocol"); | 34 | assert(!Number.isNaN(totalBytes), "Sanity check of content-length protocol"); |
31 | 35 | ||
32 | let readBytes = 0; | ||
33 | |||
34 | console.log("Downloading file of", totalBytes, "bytes size from", url, "to", destFilePath); | 36 | console.log("Downloading file of", totalBytes, "bytes size from", url, "to", destFilePath); |
35 | 37 | ||
36 | // Here reject() may be called 2 times. As per ECMAScript standard, 2-d call is ignored | 38 | let readBytes = 0; |
37 | // https://tc39.es/ecma262/#sec-promise-reject-functions | 39 | res.body.on("data", (chunk: Buffer) => { |
38 | 40 | readBytes += chunk.length; | |
39 | return new Promise<void>((resolve, reject) => res.body | 41 | onProgress(readBytes, totalBytes); |
40 | .on("data", (chunk: Buffer) => { | 42 | }); |
41 | readBytes += chunk.length; | 43 | |
42 | onProgress(readBytes, totalBytes); | 44 | const destFileStream = fs.createWriteStream(destFilePath, { mode: destFilePermissions }); |
43 | }) | 45 | |
44 | .on("error", err => reject( | 46 | await pipeline(res.body, destFileStream).catch(DownloadFileError.rethrow("Piping file error")); |
45 | new DownloadFileError(`Read-stream error, read bytes: ${readBytes}`, err) | 47 | return new Promise<void>(resolve => { |
46 | )) | 48 | destFileStream.on("close", resolve); // details on workaround: https://github.com/rust-analyzer/rust-analyzer/pull/3092#discussion_r378191131 |
47 | .pipe(fs.createWriteStream(destFilePath, { mode: destFilePermissions })) | 49 | destFileStream.destroy(); |
48 | .on("error", err => reject( | 50 | }); |
49 | new DownloadFileError(`Write-stream error, read bytes: ${readBytes}`, err) | ||
50 | )) | ||
51 | .on("close", resolve) | ||
52 | ); | ||
53 | } | 51 | } |