use bstr::{BStr, BString};
use crate::{
driver,
driver::{apply::handle_io_err, Operation, State},
};
pub mod list {
use crate::driver;
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error("Could not get process named '{}' which should be running and tracked", wanted.0)]
ProcessMissing { wanted: driver::Key },
#[error("Failed to run 'list_available_blobs' command")]
ProcessInvoke(#[from] driver::process::client::invoke::without_content::Error),
#[error("The invoked command 'list_available_blobs' in process indicated an error: {status:?}")]
ProcessStatus { status: driver::process::Status },
}
}
pub mod fetch {
use crate::driver;
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error("Could not get process named '{}' which should be running and tracked", wanted.0)]
ProcessMissing { wanted: driver::Key },
#[error("Failed to run '{command}' command")]
ProcessInvoke {
command: String,
source: driver::process::client::invoke::Error,
},
#[error("The invoked command '{command}' in process indicated an error: {status:?}")]
ProcessStatus {
status: driver::process::Status,
command: String,
},
}
}
impl State {
pub fn list_delayed_paths(&mut self, process: &driver::Key) -> Result<Vec<BString>, list::Error> {
let client = self
.running
.get_mut(&process.0)
.ok_or_else(|| list::Error::ProcessMissing {
wanted: process.clone(),
})?;
let mut out = Vec::new();
let result = client.invoke_without_content("list_available_blobs", &mut None.into_iter(), &mut |line| {
if let Some(path) = line.strip_prefix(b"pathname=") {
out.push(path.into())
}
});
let status = match result {
Ok(res) => res,
Err(err) => {
if let driver::process::client::invoke::without_content::Error::Io(err) = &err {
handle_io_err(err, &mut self.running, process.0.as_ref());
}
return Err(err.into());
}
};
if status.is_success() {
Ok(out)
} else {
let message = status.message().unwrap_or_default();
match message {
"error" | "abort" => {}
_strange => {
let client = self.running.remove(&process.0).expect("we definitely have it");
client.into_child().kill().ok();
}
}
Err(list::Error::ProcessStatus { status })
}
}
pub fn fetch_delayed(
&mut self,
process: &driver::Key,
path: &BStr,
operation: Operation,
) -> Result<impl std::io::Read + '_, fetch::Error> {
let client = self
.running
.get_mut(&process.0)
.ok_or_else(|| fetch::Error::ProcessMissing {
wanted: process.clone(),
})?;
let result = client.invoke(
operation.as_str(),
&mut [("pathname", path.to_owned())].into_iter(),
&mut &b""[..],
);
let status = match result {
Ok(status) => status,
Err(err) => {
let driver::process::client::invoke::Error::Io(io_err) = &err;
handle_io_err(io_err, &mut self.running, process.0.as_ref());
return Err(fetch::Error::ProcessInvoke {
command: operation.as_str().into(),
source: err,
});
}
};
if status.is_success() {
let client = self.running.remove(&process.0).expect("present for borrowcheck dance");
self.running.insert(process.0.clone(), client);
let client = self.running.get_mut(&process.0).expect("just inserted");
Ok(client.as_read())
} else {
let message = status.message().unwrap_or_default();
match message {
"abort" => {
client.capabilities_mut().remove(operation.as_str());
}
"error" => {}
_strange => {
let client = self.running.remove(&process.0).expect("we definitely have it");
client.into_child().kill().ok();
}
}
Err(fetch::Error::ProcessStatus {
command: operation.as_str().into(),
status,
})
}
}
}