Skip to content

Commit 06168b2

Browse files
committed
wip
1 parent a57a5c5 commit 06168b2

File tree

3 files changed

+44
-54
lines changed

3 files changed

+44
-54
lines changed

src/test/jsonl-stream.test.ts

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,16 @@ import * as assert from "node:assert";
33
import { LogLevel } from "vscode";
44
import type { LogOutputChannel, Event } from "vscode";
55

6-
import { createJsonlStream } from "../utils/jsonl-stream.js";
6+
import { JsonlStream } from "../utils/jsonl-stream.js";
77

88
const setup = () => {
9-
const mockOutputChannel: LogOutputChannel = {
10-
name: "test",
11-
logLevel: LogLevel.Info,
12-
onDidChangeLogLevel: {} as Event<LogLevel>,
13-
append: () => {},
14-
appendLine: () => {},
15-
replace: () => {},
16-
clear: () => {},
17-
show: () => {},
18-
hide: () => {},
19-
dispose: () => {},
20-
trace: () => {},
21-
debug: () => {},
22-
info: () => {},
23-
warn: () => {},
24-
error: () => {},
25-
};
26-
27-
const jsonlStream = createJsonlStream(mockOutputChannel);
9+
const jsonlStream = new JsonlStream();
2810

2911
const callbackCalls: unknown[] = [];
3012
const callback = (data: unknown) => {
3113
callbackCalls.push(data);
3214
};
33-
jsonlStream.on(callback);
15+
jsonlStream.onJson(callback);
3416

3517
return {
3618
jsonlStream,

src/utils/container-status.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { Disposable, LogOutputChannel } from "vscode";
44
import * as z from "zod/v4-mini";
55

66
import { createEmitter } from "./emitter.ts";
7-
import { createJsonlStream } from "./jsonl-stream.ts";
7+
import { JsonlStream } from "./jsonl-stream.ts";
88

99
export type ContainerStatus = "running" | "stopping" | "stopped";
1010

@@ -123,8 +123,8 @@ function listenToContainerStatus(
123123
throw new Error("Failed to get stdout from docker events process");
124124
}
125125

126-
const jsonlStream = createJsonlStream(outputChannel);
127-
jsonlStream.on((json) => {
126+
const jsonlStream = new JsonlStream();
127+
jsonlStream.onJson((json) => {
128128
const parsed = DockerEventsSchema.safeParse(json);
129129
if (!parsed.success) {
130130
return;
@@ -134,6 +134,8 @@ function listenToContainerStatus(
134134
return;
135135
}
136136

137+
outputChannel.debug(`[container.status]: ${parsed.data.Action}`);
138+
137139
switch (parsed.data.Action) {
138140
case "start":
139141
onStatusChange("running");
@@ -147,9 +149,7 @@ function listenToContainerStatus(
147149
}
148150
});
149151

150-
dockerEvents.stdout.on("data", (data: Buffer) => {
151-
jsonlStream.write(data);
152-
});
152+
dockerEvents.stdout.pipe(jsonlStream);
153153
} catch (error) {
154154
// If we can't spawn the process, try again after a delay
155155
scheduleRestart();

src/utils/jsonl-stream.ts

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,52 @@
1-
import type { LogOutputChannel } from "vscode";
1+
import { Writable } from "node:stream";
22

3-
import type { Callback } from "./emitter.ts";
4-
import { createEmitter } from "./emitter.ts";
5-
6-
interface JsonlStream {
7-
write(data: Buffer): void;
8-
on(callback: Callback<unknown>): void;
9-
}
10-
11-
function safeJsonParse(text: string): unknown {
3+
/**
4+
* Safely parses a JSON string, returning null if parsing fails.
5+
* @param str - The JSON string to parse.
6+
* @returns The parsed object or null if invalid.
7+
*/
8+
export function safeJsonParse(str: string): unknown {
129
try {
13-
return JSON.parse(text);
10+
return JSON.parse(str);
1411
} catch {
1512
return undefined;
1613
}
1714
}
1815

19-
export const createJsonlStream = (outputChannel: LogOutputChannel): JsonlStream => {
20-
const emitter = createEmitter(outputChannel)
21-
let buffer = "";
22-
return {
23-
write(data) {
24-
buffer += data.toString();
16+
/**
17+
* Writable stream that buffers data until a newline,
18+
* parses each line as JSON, and emits the parsed object.
19+
*/
20+
export class JsonlStream extends Writable {
21+
constructor() {
22+
let buffer = "";
23+
super({
24+
write: (chunk, _encoding, callback) => {
25+
buffer += String(chunk);
2526

26-
// Process all complete lines
2727
let newlineIndex = buffer.indexOf("\n");
2828
while (newlineIndex !== -1) {
2929
const line = buffer.substring(0, newlineIndex).trim();
3030
buffer = buffer.substring(newlineIndex + 1);
3131

3232
const json = safeJsonParse(line);
33-
if (json) {
34-
void emitter.emit(json)
35-
}
33+
if (json !== null) {
34+
this.emit("json", json);
35+
}
3636

3737
newlineIndex = buffer.indexOf("\n");
3838
}
39-
},
40-
on(callback) {
41-
emitter.on(callback)
42-
},
43-
}
44-
};
39+
40+
callback();
41+
},
42+
});
43+
}
44+
45+
/**
46+
* Registers a listener for parsed JSON objects.
47+
* @param listener - Function called with each parsed object.
48+
*/
49+
onJson(callback: (json: unknown) => void) {
50+
this.on("json", callback);
51+
}
52+
}

0 commit comments

Comments
 (0)