strop_remote/exec/
stream.rs1use super::{RemoteCommand, RemoteCommandError, RemoteExitStatus, StdinMode};
3use strop_core::process::{self, StreamError, StreamPolicy};
4use strop_core::worker::CancelToken;
5use strop_workspace::RemoteEndpoint;
6
7pub struct RemoteStreamOutput {
8 pub status: RemoteExitStatus,
9 pub stderr: Vec<u8>,
10 pub stderr_dropped: u64,
11}
12#[derive(Debug)]
13pub enum RemoteStreamError<E> {
14 Remote(RemoteCommandError),
15 Consumer(E),
16}
17impl<E> From<RemoteCommandError> for RemoteStreamError<E> {
18 fn from(error: RemoteCommandError) -> Self {
19 Self::Remote(error)
20 }
21}
22
23pub fn stream<E>(
24 endpoint: &RemoteEndpoint,
25 command: &RemoteCommand,
26 token: &CancelToken,
27 consume: impl FnMut(&[u8]) -> Result<(), E>,
28) -> Result<RemoteStreamOutput, RemoteStreamError<E>> {
29 let (mut process, key) = super::run::supervised(endpoint, command, StdinMode::Finite)?;
30 let output = process::stream_with(
31 &mut process,
32 token,
33 &StreamPolicy {
34 stderr_limit: super::run::STDERR_LIMIT,
35 stderr_tail: super::run::STDERR_TAIL,
36 deadline: command.deadline(),
37 hold_stdin: true,
38 },
39 consume,
40 )
41 .map_err(|error| match error {
42 StreamError::Consumer(error) => RemoteStreamError::Consumer(error),
43 StreamError::Spawn(message) => {
44 RemoteStreamError::Remote(RemoteCommandError::Spawn { message })
45 }
46 StreamError::Cancelled => RemoteStreamError::Remote(RemoteCommandError::Cancelled {
47 diagnostics: "stream cancellation observed".into(),
48 }),
49 StreamError::TimedOut(deadline) => RemoteStreamError::Remote(RemoteCommandError::Timeout {
50 seconds: deadline.as_secs(),
51 }),
52 StreamError::Failure(error) => RemoteStreamError::Remote(RemoteCommandError::Local {
53 message: error.message,
54 }),
55 })?;
56 let output = super::run::classify(
59 process::CommandOutput {
60 status: output.status,
61 stdout: Vec::new(),
62 stdout_dropped: 0,
63 stderr: output.stderr,
64 stderr_dropped: output.stderr_dropped,
65 stdin_error: None,
66 },
67 &key,
68 )?;
69 Ok(RemoteStreamOutput {
70 status: output.status,
71 stderr: output.stderr,
72 stderr_dropped: output.stderr_dropped,
73 })
74}