use anyhow::{Result, anyhow};
use crate::sftp::wire::{Attrs, STATUS_NO_SUCH_FILE};
pub mod sftp;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Refused {
pub status: u32,
}
impl std::fmt::Display for Refused {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = match self.status {
1 => "end of file",
2 => "no such file",
3 => "permission denied",
4 => "failure",
5 => "bad message",
6 => "no connection",
7 => "connection lost",
8 => "operation unsupported",
_ => "unrecognised status",
};
write!(f, "the remote refused: {name} ({})", self.status)
}
}
impl std::error::Error for Refused {}
pub fn is_absent(e: &anyhow::Error) -> bool {
e.chain()
.filter_map(|c| c.downcast_ref::<Refused>())
.any(|r| r.status == STATUS_NO_SUCH_FILE)
}
#[derive(Debug, Clone)]
pub struct Entry {
pub name: String,
pub attrs: Attrs,
}
#[derive(Debug, Clone)]
pub struct RangeReq {
pub path: String,
pub offset: u64,
pub len: u64,
}
#[allow(async_fn_in_trait)]
pub trait RemoteFs {
async fn read_batch(&self, paths: &[String]) -> Vec<Result<Vec<u8>>>;
async fn read_ranges(&self, reqs: &[RangeReq]) -> Vec<Result<Vec<u8>>>;
async fn list_dirs(&self, paths: &[String]) -> Vec<Result<Vec<Entry>>>;
async fn list_dir(&self, path: &str) -> Result<Vec<Entry>> {
let one = [path.to_string()];
self.list_dirs(&one)
.await
.into_iter()
.next()
.unwrap_or_else(|| Err(anyhow!("list_dirs returned no result for {path}")))
}
async fn home(&self) -> Result<String>;
fn round_trips(&self) -> u64;
}