muster/domain/port/process_runner.rs
1use std::time::Duration;
2
3use crate::domain::{
4 process::StopSignal,
5 pty::{ProcessOutput, PtyError, PtySize, SpawnRequest},
6};
7
8/// Sink for a single process's output events, supplied by the runtime. The
9/// concrete implementation (e.g. a channel into the event loop) lives in an
10/// adapter, keeping the domain free of any transport type.
11pub trait OutputSink: Send + Sync + 'static {
12 /// Delivers one output event from the process to the runtime.
13 fn send(&self, output: ProcessOutput);
14}
15
16/// Handle to a spawned process: write input, resize, or terminate it.
17pub trait ProcessHandle: Send {
18 /// The OS process ID of the spawned child, when the platform exposes it.
19 /// Defaults to unknown so simple test doubles need not invent one.
20 fn process_id(&self) -> Option<u32> {
21 None
22 }
23
24 /// Writes raw input bytes to the process's PTY.
25 ///
26 /// # Errors
27 /// Returns a `PtyError` if the write fails.
28 fn write_input(&mut self, bytes: &[u8]) -> Result<(), PtyError>;
29
30 /// Resizes the process's PTY.
31 ///
32 /// # Errors
33 /// Returns a `PtyError` if the resize fails.
34 fn resize(&mut self, size: PtySize) -> Result<(), PtyError>;
35
36 /// Suspends the process (SIGSTOP-equivalent), leaving it alive.
37 ///
38 /// # Errors
39 /// Returns a `PtyError` if the signal cannot be sent.
40 fn pause(&mut self) -> Result<(), PtyError>;
41
42 /// Resumes a previously suspended process (SIGCONT-equivalent).
43 ///
44 /// # Errors
45 /// Returns a `PtyError` if the signal cannot be sent.
46 fn resume(&mut self) -> Result<(), PtyError>;
47
48 /// Requests graceful process termination with `signal` and `grace`, falling
49 /// back to [`Self::kill`] for adapters without a distinct mechanism.
50 ///
51 /// # Errors
52 /// Returns a `PtyError` if the termination signal cannot be sent.
53 fn terminate(&mut self, _signal: StopSignal, _grace: Duration) -> Result<(), PtyError> {
54 self.kill()
55 }
56
57 /// Forcibly terminates the process.
58 ///
59 /// # Errors
60 /// Returns a `PtyError` if the kill signal cannot be sent.
61 fn kill(&mut self) -> Result<(), PtyError>;
62}
63
64/// Driven port: spawns a process under a PTY and streams its output to a sink.
65pub trait ProcessRunner {
66 /// Spawns `request`'s command, delivering output to `sink`, and returns a
67 /// handle for interacting with the running process.
68 ///
69 /// # Errors
70 /// Returns a `PtyError` if the process cannot be spawned.
71 fn spawn(
72 &self,
73 request: SpawnRequest,
74 sink: Box<dyn OutputSink>,
75 ) -> Result<Box<dyn ProcessHandle>, PtyError>;
76}