Skip to content

Commit b3f566e

Browse files
Copilotna-trium-144
andcommitted
Refactor to use streaming API and unified output array
- Use response.body stream instead of response.text() for better flexibility - Change CompileResultWithOutput to use single output array instead of separate arrays - Store outputs in the order they are received from the ndjson stream - Update cpp.ts to work with the new unified output structure Co-authored-by: na-trium-144 <[email protected]>
1 parent 1fcdfc5 commit b3f566e

File tree

2 files changed

+77
-46
lines changed

2 files changed

+77
-46
lines changed

app/terminal/wandbox/api.ts

Lines changed: 64 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,7 @@ interface CompileProps {
101101
codes: Code[];
102102
}
103103
export interface CompileResultWithOutput extends CompileResult {
104-
compilerOutput: ReplOutput[];
105-
compilerError: ReplOutput[];
106-
programOutput: ReplOutput[];
107-
programError: ReplOutput[];
104+
output: ReplOutput[];
108105
}
109106

110107
export async function compileAndRun(
@@ -136,12 +133,41 @@ export async function compileAndRun(
136133
throw new Error(`HTTP error! status: ${response.status}`);
137134
}
138135

139-
// Read the ndjson response line by line
140-
const text = await response.text();
141-
const lines = text.trim().split("\n");
142-
const ndjsonResults: CompileNdjsonResult[] = lines
143-
.filter((line) => line.trim().length > 0)
144-
.map((line) => JSON.parse(line) as CompileNdjsonResult);
136+
// Read the ndjson response as a stream
137+
const reader = response.body?.getReader();
138+
if (!reader) {
139+
throw new Error("Response body is not readable");
140+
}
141+
142+
const decoder = new TextDecoder();
143+
let buffer = "";
144+
const ndjsonResults: CompileNdjsonResult[] = [];
145+
146+
try {
147+
while (true) {
148+
const { done, value } = await reader.read();
149+
if (done) break;
150+
151+
buffer += decoder.decode(value, { stream: true });
152+
const lines = buffer.split("\n");
153+
154+
// Keep the last incomplete line in the buffer
155+
buffer = lines.pop() || "";
156+
157+
for (const line of lines) {
158+
if (line.trim().length > 0) {
159+
ndjsonResults.push(JSON.parse(line) as CompileNdjsonResult);
160+
}
161+
}
162+
}
163+
164+
// Process any remaining data in the buffer
165+
if (buffer.trim().length > 0) {
166+
ndjsonResults.push(JSON.parse(buffer) as CompileNdjsonResult);
167+
}
168+
} finally {
169+
reader.releaseLock();
170+
}
145171

146172
// Merge ndjson results into a CompileResult (same logic as Rust merge_compile_result)
147173
const result: CompileResult = {
@@ -157,6 +183,9 @@ export async function compileAndRun(
157183
url: "",
158184
};
159185

186+
// Build output array in the order messages are received
187+
const output: ReplOutput[] = [];
188+
160189
for (const r of ndjsonResults) {
161190
switch (r.type) {
162191
case "Control":
@@ -165,18 +194,42 @@ export async function compileAndRun(
165194
case "CompilerMessageS":
166195
result.compiler_output += r.data;
167196
result.compiler_message += r.data;
197+
// Add to output in order
198+
if (r.data.trim()) {
199+
for (const line of r.data.trim().split("\n")) {
200+
output.push({ type: "stdout", message: line });
201+
}
202+
}
168203
break;
169204
case "CompilerMessageE":
170205
result.compiler_error += r.data;
171206
result.compiler_message += r.data;
207+
// Add to output in order
208+
if (r.data.trim()) {
209+
for (const line of r.data.trim().split("\n")) {
210+
output.push({ type: "error", message: line });
211+
}
212+
}
172213
break;
173214
case "StdOut":
174215
result.program_output += r.data;
175216
result.program_message += r.data;
217+
// Add to output in order
218+
if (r.data.trim()) {
219+
for (const line of r.data.trim().split("\n")) {
220+
output.push({ type: "stdout", message: line });
221+
}
222+
}
176223
break;
177224
case "StdErr":
178225
result.program_error += r.data;
179226
result.program_message += r.data;
227+
// Add to output in order
228+
if (r.data.trim()) {
229+
for (const line of r.data.trim().split("\n")) {
230+
output.push({ type: "stderr", message: line });
231+
}
232+
}
180233
break;
181234
case "ExitCode":
182235
result.status += r.data;
@@ -192,29 +245,6 @@ export async function compileAndRun(
192245

193246
return {
194247
...result,
195-
compilerOutput: result.compiler_output.trim()
196-
? result.compiler_output
197-
.trim()
198-
.split("\n")
199-
.map((line) => ({ type: "stdout" as const, message: line }))
200-
: [],
201-
compilerError: result.compiler_error.trim()
202-
? result.compiler_error
203-
.trim()
204-
.split("\n")
205-
.map((line) => ({ type: "error" as const, message: line }))
206-
: [],
207-
programOutput: result.program_output.trim()
208-
? result.program_output
209-
.trim()
210-
.split("\n")
211-
.map((line) => ({ type: "stdout" as const, message: line }))
212-
: [],
213-
programError: result.program_error.trim()
214-
? result.program_error
215-
.trim()
216-
.split("\n")
217-
.map((line) => ({ type: "error" as const, message: line }))
218-
: [],
248+
output,
219249
};
220250
}

app/terminal/wandbox/cpp.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -101,33 +101,34 @@ export async function cppRunFiles(
101101
],
102102
});
103103

104-
const traceIndex = result.programError.findIndex(
105-
(line) => line.message === "Stack trace:"
104+
// Find stack trace in the output
105+
const traceIndex = result.output.findIndex(
106+
(line) => line.type === "stderr" && line.message === "Stack trace:"
106107
);
107-
const outputs: ReplOutput[] = [
108-
...result.compilerOutput,
109-
...result.compilerError,
110-
...result.programOutput,
111-
...(traceIndex >= 0
112-
? result.programError.slice(0, traceIndex)
113-
: result.programError),
114-
];
108+
109+
let outputs: ReplOutput[];
110+
115111
if (traceIndex >= 0) {
116112
// CPP_STACKTRACE_HANDLER のコードで出力されるスタックトレースを、js側でパースしていい感じに表示する
113+
outputs = result.output.slice(0, traceIndex);
117114
outputs.push({
118115
type: "trace" as const,
119116
message: "Stack trace (filtered):",
120117
});
121-
for (const line of result.programError.slice(traceIndex + 1)) {
118+
119+
for (const line of result.output.slice(traceIndex + 1)) {
122120
// ユーザーのソースコードだけを対象にする
123-
if (line.message.includes("/home/wandbox")) {
121+
if (line.type === "stderr" && line.message.includes("/home/wandbox")) {
124122
outputs.push({
125123
type: "trace" as const,
126124
message: line.message.replace("/home/wandbox/", ""),
127125
});
128126
}
129127
}
128+
} else {
129+
outputs = [...result.output];
130130
}
131+
131132
if (result.status !== "0") {
132133
outputs.push({
133134
type: "system" as const,

0 commit comments

Comments
 (0)