From 36dc3edb7a73e0d60ba2a3e589d1ae76c27f9d9d Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 11 Feb 2020 23:58:20 +0200 Subject: vscode: added error handling to download file streams --- editors/code/src/installation/download_file.ts | 23 ++++++++++++++++------- editors/code/src/installation/language_server.ts | 2 ++ 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'editors/code/src') diff --git a/editors/code/src/installation/download_file.ts b/editors/code/src/installation/download_file.ts index f1f9f4a25..71700ec8a 100644 --- a/editors/code/src/installation/download_file.ts +++ b/editors/code/src/installation/download_file.ts @@ -1,6 +1,9 @@ import fetch from "node-fetch"; import * as fs from "fs"; import { strict as assert } from "assert"; +import { NestedError } from "ts-nested-error"; + +class DownloadFileError extends NestedError {} /** * Downloads file from `url` and stores it at `destFilePath` with `destFilePermissions`. @@ -14,13 +17,13 @@ export async function downloadFile( destFilePermissions: number, onProgress: (readBytes: number, totalBytes: number) => void ): Promise { - const res = await fetch(url); + const res = await fetch(url).catch(DownloadFileError.rethrow("Failed at initial fetch")); if (!res.ok) { console.log("Error", res.status, "while downloading file from", url); console.dir({ body: await res.text(), headers: res.headers }, { depth: 3 }); - throw new Error(`Got response ${res.status} when trying to download a file`); + throw new DownloadFileError(`Got response ${res.status}`); } const totalBytes = Number(res.headers.get('content-length')); @@ -30,15 +33,21 @@ export async function downloadFile( console.log("Downloading file of", totalBytes, "bytes size from", url, "to", destFilePath); + // Here reject() may be called 2 times. As per ECMAScript standard, 2-d call is ignored + // https://tc39.es/ecma262/#sec-promise-reject-functions + return new Promise((resolve, reject) => res.body .on("data", (chunk: Buffer) => { readBytes += chunk.length; onProgress(readBytes, totalBytes); }) - .on("error", reject) - .pipe(fs - .createWriteStream(destFilePath, { mode: destFilePermissions }) - .on("close", resolve) - ) + .on("error", err => reject( + new DownloadFileError(`Read-stream error, read bytes: ${readBytes}`, err) + )) + .pipe(fs.createWriteStream(destFilePath, { mode: destFilePermissions })) + .on("error", err => reject( + new DownloadFileError(`Write-stream error, read bytes: ${readBytes}`, err) + )) + .on("close", resolve) ); } diff --git a/editors/code/src/installation/language_server.ts b/editors/code/src/installation/language_server.ts index 52c5cbe7d..4797c3f01 100644 --- a/editors/code/src/installation/language_server.ts +++ b/editors/code/src/installation/language_server.ts @@ -104,6 +104,8 @@ export async function ensureLanguageServerBinary( `GitHub repository: ${err.message}` ); + console.error(err); + dns.resolve('example.com').then( addrs => console.log("DNS resolution for example.com was successful", addrs), err => { -- cgit v1.2.3 From a3febc1c574b9f99120b0e5bc860bf2458d0b919 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Wed, 12 Feb 2020 21:40:35 +0200 Subject: vscode: switched to stream.pipeline with .on(close) workaround --- editors/code/src/installation/download_file.ts | 36 ++++++++++++-------------- 1 file changed, 17 insertions(+), 19 deletions(-) (limited to 'editors/code/src') 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 @@ import fetch from "node-fetch"; import * as fs from "fs"; +import * as stream from "stream"; +import * as util from "util"; import { strict as assert } from "assert"; import { NestedError } from "ts-nested-error"; +const pipeline = util.promisify(stream.pipeline); + class DownloadFileError extends NestedError {} /** @@ -29,25 +33,19 @@ export async function downloadFile( const totalBytes = Number(res.headers.get('content-length')); assert(!Number.isNaN(totalBytes), "Sanity check of content-length protocol"); - let readBytes = 0; - console.log("Downloading file of", totalBytes, "bytes size from", url, "to", destFilePath); - // Here reject() may be called 2 times. As per ECMAScript standard, 2-d call is ignored - // https://tc39.es/ecma262/#sec-promise-reject-functions - - return new Promise((resolve, reject) => res.body - .on("data", (chunk: Buffer) => { - readBytes += chunk.length; - onProgress(readBytes, totalBytes); - }) - .on("error", err => reject( - new DownloadFileError(`Read-stream error, read bytes: ${readBytes}`, err) - )) - .pipe(fs.createWriteStream(destFilePath, { mode: destFilePermissions })) - .on("error", err => reject( - new DownloadFileError(`Write-stream error, read bytes: ${readBytes}`, err) - )) - .on("close", resolve) - ); + let readBytes = 0; + res.body.on("data", (chunk: Buffer) => { + readBytes += chunk.length; + onProgress(readBytes, totalBytes); + }); + + const destFileStream = fs.createWriteStream(destFilePath, { mode: destFilePermissions }); + + await pipeline(res.body, destFileStream).catch(DownloadFileError.rethrow("Piping file error")); + return new Promise(resolve => { + destFileStream.on("close", resolve); // details on workaround: https://github.com/rust-analyzer/rust-analyzer/pull/3092#discussion_r378191131 + destFileStream.destroy(); + }); } -- cgit v1.2.3 From da6ae3b6e0700acf80eeb27b513abdd381c50916 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Thu, 13 Feb 2020 22:21:19 +0200 Subject: vscode: replaced DownloadFileError with NestedError itself for simplicity --- editors/code/src/installation/download_file.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'editors/code/src') diff --git a/editors/code/src/installation/download_file.ts b/editors/code/src/installation/download_file.ts index b31d2a736..591de0d31 100644 --- a/editors/code/src/installation/download_file.ts +++ b/editors/code/src/installation/download_file.ts @@ -7,8 +7,6 @@ import { NestedError } from "ts-nested-error"; const pipeline = util.promisify(stream.pipeline); -class DownloadFileError extends NestedError {} - /** * Downloads file from `url` and stores it at `destFilePath` with `destFilePermissions`. * `onProgress` callback is called on recieveing each chunk of bytes @@ -21,13 +19,13 @@ export async function downloadFile( destFilePermissions: number, onProgress: (readBytes: number, totalBytes: number) => void ): Promise { - const res = await fetch(url).catch(DownloadFileError.rethrow("Failed at initial fetch")); + const res = await fetch(url).catch(NestedError.rethrow("Failed at initial fetch")); if (!res.ok) { console.log("Error", res.status, "while downloading file from", url); console.dir({ body: await res.text(), headers: res.headers }, { depth: 3 }); - throw new DownloadFileError(`Got response ${res.status}`); + throw new NestedError(`Got response ${res.status}`); } const totalBytes = Number(res.headers.get('content-length')); @@ -43,9 +41,12 @@ export async function downloadFile( const destFileStream = fs.createWriteStream(destFilePath, { mode: destFilePermissions }); - await pipeline(res.body, destFileStream).catch(DownloadFileError.rethrow("Piping file error")); + await pipeline(res.body, destFileStream).catch(NestedError.rethrow("Piping file error")); return new Promise(resolve => { - destFileStream.on("close", resolve); // details on workaround: https://github.com/rust-analyzer/rust-analyzer/pull/3092#discussion_r378191131 + destFileStream.on("close", resolve); destFileStream.destroy(); + + // Details on workaround: https://github.com/rust-analyzer/rust-analyzer/pull/3092#discussion_r378191131 + // Issue at nodejs repo: https://github.com/nodejs/node/issues/31776 }); } -- cgit v1.2.3 From 574dc11a2fed943bc40e338b22c5b12bef66e768 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Fri, 14 Feb 2020 00:31:23 +0200 Subject: vscode: removed nested errors as per matklad --- editors/code/src/installation/download_file.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'editors/code/src') diff --git a/editors/code/src/installation/download_file.ts b/editors/code/src/installation/download_file.ts index 591de0d31..d154f4816 100644 --- a/editors/code/src/installation/download_file.ts +++ b/editors/code/src/installation/download_file.ts @@ -3,7 +3,6 @@ import * as fs from "fs"; import * as stream from "stream"; import * as util from "util"; import { strict as assert } from "assert"; -import { NestedError } from "ts-nested-error"; const pipeline = util.promisify(stream.pipeline); @@ -19,13 +18,13 @@ export async function downloadFile( destFilePermissions: number, onProgress: (readBytes: number, totalBytes: number) => void ): Promise { - const res = await fetch(url).catch(NestedError.rethrow("Failed at initial fetch")); + const res = await fetch(url); if (!res.ok) { console.log("Error", res.status, "while downloading file from", url); console.dir({ body: await res.text(), headers: res.headers }, { depth: 3 }); - throw new NestedError(`Got response ${res.status}`); + throw new Error(`Got response ${res.status} when trying to download a file.`); } const totalBytes = Number(res.headers.get('content-length')); @@ -41,7 +40,7 @@ export async function downloadFile( const destFileStream = fs.createWriteStream(destFilePath, { mode: destFilePermissions }); - await pipeline(res.body, destFileStream).catch(NestedError.rethrow("Piping file error")); + await pipeline(res.body, destFileStream); return new Promise(resolve => { destFileStream.on("close", resolve); destFileStream.destroy(); -- cgit v1.2.3