use std::{
future::Future,
io,
sync::Arc,
time::{Duration, SystemTime},
};
use sciparse::{identifier::isd_asn::IsdAsn, path::ScionPath};
use thiserror::Error;
use crate::path::fetcher::traits::PathFetchError;
pub trait PathManager: SyncPathManager {
fn path_wait(
&self,
src: IsdAsn,
dst: IsdAsn,
now: SystemTime,
) -> impl Future<Output = Result<ScionPath, PathWaitError>> + Send + '_;
fn path_timeout(
&self,
src: IsdAsn,
dst: IsdAsn,
now: SystemTime,
timeout: Duration,
) -> impl Future<Output = Result<ScionPath, PathWaitTimeoutError>> + Send + '_ {
let fut = self.path_wait(src, dst, now);
async move {
match tokio::time::timeout(timeout, fut).await {
Ok(result) => {
result.map_err(|e| {
match e {
PathWaitError::FetchFailed(source) => {
PathWaitTimeoutError::FetchFailed(source)
}
PathWaitError::NoPathFound => PathWaitTimeoutError::NoPathFound,
}
})
}
Err(_) => Err(PathWaitTimeoutError::Timeout),
}
}
}
}
#[derive(Debug, Clone, Error)]
#[non_exhaustive]
pub enum PathWaitError {
#[error("path fetch failed: {0}")]
FetchFailed(#[source] Arc<PathFetchError>),
#[error("no path found")]
NoPathFound,
}
#[derive(Debug, Clone, Error)]
#[non_exhaustive]
pub enum PathWaitTimeoutError {
#[error("path fetch failed: {0}")]
FetchFailed(#[source] Arc<PathFetchError>),
#[error("no path found")]
NoPathFound,
#[error("waiting for path timed out")]
Timeout,
}
pub trait SyncPathManager {
fn register_path(&self, src: IsdAsn, dst: IsdAsn, now: SystemTime, path: ScionPath);
fn try_cached_path(
&self,
src: IsdAsn,
dst: IsdAsn,
now: SystemTime,
) -> io::Result<Option<ScionPath>>;
}
pub trait PathPrefetcher {
fn prefetch_path(&self, src: IsdAsn, dst: IsdAsn);
}