Skip to main content

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}