More work to clean up api client bridge

feat/RusshSupport
Chip Senkbeil 7 months ago
parent 608a4c0161
commit b17d5dfdb4
No known key found for this signature in database
GPG Key ID: 35EF1F8EC72A4131

@ -14,7 +14,7 @@ pub use unsupported::*;
/// Full API that represents a distant-compatible server.
#[async_trait]
pub trait Api {
pub trait Api: Send + Sync {
/// Specific implementation of [`FileSystemApi`] associated with this [`Api`].
type FileSystem: FileSystemApi;
@ -54,7 +54,7 @@ pub trait Api {
/// API supporting filesystem operations.
#[async_trait]
pub trait FileSystemApi {
pub trait FileSystemApi: Send + Sync {
/// Reads bytes from a file.
///
/// * `path` - the path to the file
@ -164,7 +164,7 @@ pub trait FileSystemApi {
/// API supporting process creation and manipulation.
#[async_trait]
pub trait ProcessApi {
pub trait ProcessApi: Send + Sync {
/// Spawns a new process, returning its id.
///
/// * `cmd` - the full command to run as a new process (including arguments)
@ -200,7 +200,7 @@ pub trait ProcessApi {
/// API supporting searching through the remote system.
#[async_trait]
pub trait SearchApi {
pub trait SearchApi: Send + Sync {
/// Searches files for matches based on a query.
///
/// * `query` - the specific query to perform
@ -214,21 +214,21 @@ pub trait SearchApi {
/// API supporting retrieval of information about the remote system.
#[async_trait]
pub trait SystemInfoApi {
pub trait SystemInfoApi: Send + Sync {
/// Retrieves information about the system.
async fn system_info(&self, ctx: BoxedCtx) -> io::Result<SystemInfo>;
}
/// API supporting retrieval of the server's version.
#[async_trait]
pub trait VersionApi {
pub trait VersionApi: Send + Sync {
/// Retrieves information about the server's capabilities.
async fn version(&self, ctx: BoxedCtx) -> io::Result<Version>;
}
/// API supporting watching of changes to the remote filesystem.
#[async_trait]
pub trait WatchApi {
pub trait WatchApi: Send + Sync {
/// Watches a file or directory for changes.
///
/// * `path` - the path to the file or directory

@ -5,7 +5,7 @@ use async_trait::async_trait;
use distant_core_protocol::{Error, Request, Response};
use crate::api::{
Api, BoxedCtx, Ctx, FileSystemApi, ProcessApi, SearchApi, SystemInfoApi, VersionApi, WatchApi,
Api, Ctx, FileSystemApi, ProcessApi, SearchApi, SystemInfoApi, VersionApi, WatchApi,
};
pub type BoxedClient = Box<dyn Client>;
@ -33,17 +33,19 @@ pub trait Client {
/// This can be used to run an Api implementation locally, such as when you want to translate some
/// other platform (e.g. ssh, docker) into a distant-compatible form.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ClientBridge<T: Api>(Arc<T>);
pub struct ClientBridge<T: Api> {
api: Arc<T>,
}
impl<T: Api> ClientBridge<T> {
/// Creates a new bridge wrapping around the provided api.
pub fn new(api: T) -> Self {
Self(Arc::new(api))
Self { api: Arc::new(api) }
}
}
#[async_trait]
impl<T: Api + Send + Sync> Client for ClientBridge<T> {
impl<T: Api> Client for ClientBridge<T> {
async fn fire(&mut self, request: Request) -> io::Result<()> {
let _ = self.send(request).await?;
Ok(())
@ -58,7 +60,7 @@ impl<T: Api + Send + Sync> Client for ClientBridge<T> {
self.0
}
fn clone_ctx(&self) -> BoxedCtx {
fn clone_ctx(&self) -> Box<dyn Ctx> {
Box::new(__Ctx(self.0, self.1.clone()))
}
@ -69,13 +71,20 @@ impl<T: Api + Send + Sync> Client for ClientBridge<T> {
}
}
// TODO: Do we give this some unique id? We could randomize it, but would need the
// random crate to do so. Is that even necessary given this represents a "connection"
// and the likelihood that someone creates multiple bridges to the same api is minimal?
let (tx, rx) = mpsc::channel();
let ctx = Box::new(__Ctx(0, tx));
// TODO: This is blocking! How can we make this async? Do we REALLY need to import tokio?
//
// We would need to import tokio to spawn a task to run this...
let _response = handle_request(Arc::clone(&self.0), ctx, request).await;
//
// Alternatively, we could make some sort of trait that is a task queuer that is
// also passed to the bridge and is used to abstract the tokio spawn. Tokio itself
// can implement that trait by creating some newtype that just uses tokio spawn underneath
let _response = handle_request(Arc::clone(&self.api), ctx, request).await;
Ok(rx)
}
@ -84,15 +93,19 @@ impl<T: Api + Send + Sync> Client for ClientBridge<T> {
let rx = self.mail(request).await?;
// TODO: This is blocking! How can we make this async? Do we REALLY need to import tokio?
//
// If we abstract the mpsc::Receiver to be async, we can make this async without using
// tokio runtime directly. The mail function would return a boxed version of this trait
// and we can await on it like usual
rx.recv()
.map_err(|_| io::Error::new(io::ErrorKind::Other, "Bridge has closed"))
}
}
/// Processes an incoming request.
async fn handle_request<T>(api: Arc<T>, ctx: BoxedCtx, request: Request) -> Response
async fn handle_request<T>(api: Arc<T>, ctx: Box<dyn Ctx>, request: Request) -> Response
where
T: Api + Send,
T: Api,
{
match request {
Request::Version {} => {

Loading…
Cancel
Save