use std::{ffi::OsString, net::Ipv4Addr, path::PathBuf};
use crate::{
RunAs, SandboxConfig, SandboxError, SandboxId,
cli::{self, ExecResponse, IpResponse, ListResponse, StartResponse},
};
#[derive(Debug, Clone, Default)]
pub struct SandboxEnvironmentBuilder {
id: Option<SandboxId>,
config: Option<OsString>,
}
impl SandboxEnvironmentBuilder {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn id<I>(mut self, id: I) -> Self
where
I: Into<SandboxId>,
{
self.id = Some(id.into());
self
}
#[must_use]
pub fn config<C>(mut self, config: C) -> Self
where
C: Into<SandboxConfig>,
{
self.config = Some(config.into().to_os_string());
self
}
#[must_use]
pub fn raw_config<S>(mut self, config: S) -> Self
where
S: Into<OsString>,
{
self.config = Some(config.into());
self
}
pub fn start(self) -> Result<SandboxEnvironment, SandboxError> {
let Self { id, config } = self;
let StartResponse { id } = cli::start(id, config)?;
Ok(SandboxEnvironment { id })
}
}
#[derive(Debug, Clone)]
pub struct SandboxEnvironment {
id: SandboxId,
}
impl SandboxEnvironment {
#[must_use]
pub fn builder() -> SandboxEnvironmentBuilder {
SandboxEnvironmentBuilder::new()
}
pub fn list() -> Result<Vec<SandboxEnvironment>, SandboxError> {
let ListResponse {
windows_sandbox_environments: environments,
} = cli::list()?;
Ok(environments
.into_iter()
.map(|env| SandboxEnvironment { id: env.id })
.collect())
}
#[must_use]
pub fn from_id(id: SandboxId) -> Self {
Self { id }
}
#[must_use]
pub fn id(&self) -> SandboxId {
self.id
}
pub fn exec<C, R>(&self, command: C, run_as: R) -> Result<ExecResult, SandboxError>
where
C: Into<OsString>,
R: Into<RunAs>,
{
self.exec_impl(command.into(), run_as.into(), None)
}
pub fn exec_in<C, R, P>(
&self,
command: C,
run_as: R,
working_directory: P,
) -> Result<ExecResult, SandboxError>
where
C: Into<OsString>,
R: Into<RunAs>,
P: Into<PathBuf>,
{
self.exec_impl(
command.into(),
run_as.into(),
Some(working_directory.into()),
)
}
fn exec_impl(
&self,
command: OsString,
run_as: RunAs,
working_directory: Option<PathBuf>,
) -> Result<ExecResult, SandboxError> {
let ExecResponse { exit_code } = cli::exec(self.id, command, run_as, working_directory)?;
Ok(ExecResult { exit_code })
}
pub fn share<P, Q>(
&self,
host_path: P,
sandbox_path: Q,
allow_write: bool,
) -> Result<(), SandboxError>
where
P: Into<PathBuf>,
Q: Into<PathBuf>,
{
cli::share(self.id, host_path.into(), sandbox_path.into(), allow_write)
}
pub fn stop(&self) -> Result<(), SandboxError> {
cli::stop(self.id)
}
pub fn connect(&self) -> Result<(), SandboxError> {
cli::connect(self.id)
}
pub fn ip(&self) -> Result<IpResult, SandboxError> {
let IpResponse { networks } = cli::ip(self.id)?;
Ok(IpResult {
networks: networks
.into_iter()
.map(|network| IpNetwork {
ipv4_address: network.ipv4_address,
})
.collect(),
})
}
}
#[derive(Debug)]
pub struct ExecResult {
exit_code: i32,
}
impl ExecResult {
#[must_use]
pub fn exit_code(&self) -> i32 {
self.exit_code
}
}
#[derive(Debug)]
pub struct IpResult {
networks: Vec<IpNetwork>,
}
impl IpResult {
#[must_use]
pub fn networks(&self) -> &[IpNetwork] {
&self.networks
}
}
#[derive(Debug)]
pub struct IpNetwork {
ipv4_address: Ipv4Addr,
}
impl IpNetwork {
#[must_use]
pub fn ipv4_address(&self) -> Ipv4Addr {
self.ipv4_address
}
}