Skip to content
This repository has been archived by the owner on Aug 31, 2023. It is now read-only.

Commit

Permalink
fix(vscode): add a timeout on the stream reading tasks (#3995)
Browse files Browse the repository at this point in the history
  • Loading branch information
leops authored Dec 6, 2022
1 parent 5cd4dfd commit c2705ff
Showing 1 changed file with 64 additions and 22 deletions.
86 changes: 64 additions & 22 deletions editors/vscode/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { spawn } from "child_process";
import type { Readable } from "stream";
import { type ChildProcess, spawn } from "child_process";
import { connect, type Socket } from "net";
import { promisify } from "util";
import {
Expand Down Expand Up @@ -248,45 +247,88 @@ async function fileExists(path: Uri) {
}
}

function collectStream(stream: Readable) {
return new Promise<string>((resolve, reject) => {
let buffer = "";
stream.on("data", (data) => {
buffer += data.toString("utf-8");
});
interface MutableBuffer {
content: string;
}

stream.on("error", reject);
function collectStream(
outputChannel: OutputChannel,
process: ChildProcess,
key: "stdout" | "stderr",
buffer: MutableBuffer,
) {
return new Promise<void>((resolve, reject) => {
const stream = process[key];
stream.setEncoding("utf-8");

stream.on("error", (err) => {
outputChannel.appendLine(`[cli-${key}] error`);
reject(err);
});
stream.on("close", () => {
outputChannel.appendLine(`[cli-${key}] close`);
resolve();
});
stream.on("finish", () => {
outputChannel.appendLine(`[cli-${key}] finish`);
resolve();
});
stream.on("end", () => {
resolve(buffer);
outputChannel.appendLine(`[cli-${key}] end`);
resolve();
});

stream.on("data", (data) => {
outputChannel.appendLine(`[cli-${key}] data ${data.length}`);
buffer.content += data;
});
});
}

function withTimeout(promise: Promise<void>, duration: number) {
return Promise.race([
promise,
new Promise<void>((resolve) => setTimeout(resolve, duration)),
]);
}

async function getSocket(
outputChannel: OutputChannel,
command: string,
): Promise<string> {
const process = spawn(command, ["__print_socket"], {
stdio: "pipe",
stdio: [null, "pipe", "pipe"],
});

const exitCode = new Promise<number>((resolve, reject) => {
const stdout = { content: "" };
const stderr = { content: "" };

const stdoutPromise = collectStream(outputChannel, process, "stdout", stdout);
const stderrPromise = collectStream(outputChannel, process, "stderr", stderr);

const exitCode = await new Promise<number>((resolve, reject) => {
process.on("error", reject);
process.on("exit", resolve);
process.on("exit", (code) => {
outputChannel.appendLine(`[cli] exit ${code}`);
resolve(code);
});
process.on("close", (code) => {
outputChannel.appendLine(`[cli] close ${code}`);
resolve(code);
});
});

const [stdout, stderr, code] = await Promise.all([
collectStream(process.stdout),
collectStream(process.stderr),
exitCode,
await Promise.all([
withTimeout(stdoutPromise, 1000),
withTimeout(stderrPromise, 1000),
]);

const pipeName = stdout.trimEnd();
const pipeName = stdout.content.trimEnd();

if (code !== 0 || pipeName.length === 0) {
let message = `Command "${command} __print_socket" exited with code ${code}`;
if (stderr.length > 0) {
message += `\nOutput:\n${stderr}`;
if (exitCode !== 0 || pipeName.length === 0) {
let message = `Command "${command} __print_socket" exited with code ${exitCode}`;
if (stderr.content.length > 0) {
message += `\nOutput:\n${stderr.content}`;
}

throw new Error(message);
Expand Down

0 comments on commit c2705ff

Please sign in to comment.