Skip to content

Commit 7231e70

Browse files
committed
feat(runtime): add CLI streaming process handle
1 parent 5b32ff9 commit 7231e70

1 file changed

Lines changed: 73 additions & 0 deletions

File tree

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package io.github.easy4j.opencode.cli;
2+
3+
import java.util.concurrent.CompletableFuture;
4+
import java.util.concurrent.atomic.AtomicBoolean;
5+
6+
/**
7+
* Handle for an asynchronously streaming OpenCode CLI child process.
8+
*
9+
* @author <a href="https://github.com/loong10k">Loong Wan</a>
10+
* @since 3.0.0
11+
*/
12+
public final class OpenCodeCliStreamHandle {
13+
14+
private final Process process;
15+
private final CompletableFuture<OpenCodeCliResult> completion;
16+
private final AtomicBoolean cancellationRequested = new AtomicBoolean();
17+
18+
OpenCodeCliStreamHandle(Process process, CompletableFuture<OpenCodeCliResult> completion) {
19+
this.process = process;
20+
this.completion = completion;
21+
}
22+
23+
public CompletableFuture<OpenCodeCliResult> getCompletion() {
24+
return completion;
25+
}
26+
27+
public boolean isRunning() {
28+
return process != null && process.isAlive() && !completion.isDone();
29+
}
30+
31+
/**
32+
* Cancel the local child process tree. This does not call the OpenCode HTTP
33+
* session abort endpoint.
34+
*
35+
* @return true when cancellation was requested before completion
36+
*/
37+
public boolean cancel() {
38+
if (completion.isDone()) {
39+
return false;
40+
}
41+
cancellationRequested.set(true);
42+
terminateProcessTree();
43+
return true;
44+
}
45+
46+
public boolean isCancellationRequested() {
47+
return cancellationRequested.get();
48+
}
49+
50+
private void terminateProcessTree() {
51+
if (process == null) {
52+
return;
53+
}
54+
ProcessHandle handle = process.toHandle();
55+
handle.descendants().forEach(child -> {
56+
try {
57+
child.destroy();
58+
} catch (RuntimeException ignored) {
59+
}
60+
});
61+
process.destroy();
62+
63+
if (process.isAlive()) {
64+
handle.descendants().forEach(child -> {
65+
try {
66+
child.destroyForcibly();
67+
} catch (RuntimeException ignored) {
68+
}
69+
});
70+
process.destroyForcibly();
71+
}
72+
}
73+
}

0 commit comments

Comments
 (0)