mod host;
pub use async_trait::async_trait;
pub use host::HostSandbox;
use std::{fmt, sync::Arc};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OutStream {
Stdout,
Stderr,
}
pub type OutputCallback = Arc<dyn Fn(OutStream, &str) + Send + Sync>;
#[derive(Debug, Clone)]
pub struct ExecOutput {
pub stdout: String,
pub stderr: String,
pub exit_code: Option<i32>,
}
impl ExecOutput {
pub fn is_success(&self) -> bool {
self.exit_code == Some(0)
}
}
#[derive(Debug)]
pub enum SandboxError {
Io(String),
Unsupported,
Other(String),
}
impl fmt::Display for SandboxError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SandboxError::Io(e) => write!(f, "sandbox io error: {e}"),
SandboxError::Unsupported => {
write!(f, "operation not supported by this sandbox")
}
SandboxError::Other(e) => write!(f, "sandbox error: {e}"),
}
}
}
impl std::error::Error for SandboxError {}
impl From<std::io::Error> for SandboxError {
fn from(e: std::io::Error) -> Self {
SandboxError::Io(e.to_string())
}
}
#[async_trait]
pub trait Sandbox: Send + Sync {
async fn open(self: Arc<Self>, session_id: &str) -> Result<Arc<dyn Sandbox>, SandboxError>;
async fn execute(
&self,
command: &str,
on_output: Option<OutputCallback>,
) -> Result<ExecOutput, SandboxError>;
async fn save(&self) -> Result<(), SandboxError> {
Ok(())
}
async fn fork(&self, _to_session: &str) -> Result<(), SandboxError> {
Err(SandboxError::Unsupported)
}
}