Get distant-plugin to compile

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

4
Cargo.lock generated

@ -958,7 +958,11 @@ dependencies = [
"async-trait",
"distant-core-auth",
"distant-core-protocol",
"env_logger",
"rand 0.8.5",
"serde",
"test-log",
"tokio",
]
[[package]]

@ -15,4 +15,11 @@ license = "MIT OR Apache-2.0"
async-trait = "0.1.68"
distant-core-auth = { version = "=0.21.0", path = "../distant-core-auth" }
distant-core-protocol = { version = "=0.21.0", path = "../distant-core-protocol" }
rand = "0.8.5"
serde = { version = "1.0.163", features = ["derive"] }
tokio = { version = "1", default-features = false, features = ["sync"] }
[dev-dependencies]
env_logger = "0.10.0"
test-log = "0.2.11"
tokio = { version = "1.28.2", default-features = false, features = ["rt", "macros"] }

@ -58,36 +58,46 @@ pub trait FileSystemApi: Send + Sync {
/// Reads bytes from a file.
///
/// * `path` - the path to the file
async fn read_file(&self, ctx: BoxedCtx, path: PathBuf) -> io::Result<Vec<u8>>;
async fn read_file(&self, ctx: Box<dyn Ctx>, path: PathBuf) -> io::Result<Vec<u8>>;
/// Reads bytes from a file as text.
///
/// * `path` - the path to the file
async fn read_file_text(&self, ctx: BoxedCtx, path: PathBuf) -> io::Result<String>;
async fn read_file_text(&self, ctx: Box<dyn Ctx>, path: PathBuf) -> io::Result<String>;
/// Writes bytes to a file, overwriting the file if it exists.
///
/// * `path` - the path to the file
/// * `data` - the data to write
async fn write_file(&self, ctx: BoxedCtx, path: PathBuf, data: Vec<u8>) -> io::Result<()>;
async fn write_file(&self, ctx: Box<dyn Ctx>, path: PathBuf, data: Vec<u8>) -> io::Result<()>;
/// Writes text to a file, overwriting the file if it exists.
///
/// * `path` - the path to the file
/// * `data` - the data to write
async fn write_file_text(&self, ctx: BoxedCtx, path: PathBuf, data: String) -> io::Result<()>;
async fn write_file_text(
&self,
ctx: Box<dyn Ctx>,
path: PathBuf,
data: String,
) -> io::Result<()>;
/// Writes bytes to the end of a file, creating it if it is missing.
///
/// * `path` - the path to the file
/// * `data` - the data to append
async fn append_file(&self, ctx: BoxedCtx, path: PathBuf, data: Vec<u8>) -> io::Result<()>;
async fn append_file(&self, ctx: Box<dyn Ctx>, path: PathBuf, data: Vec<u8>) -> io::Result<()>;
/// Writes bytes to the end of a file, creating it if it is missing.
///
/// * `path` - the path to the file
/// * `data` - the data to append
async fn append_file_text(&self, ctx: BoxedCtx, path: PathBuf, data: String) -> io::Result<()>;
async fn append_file_text(
&self,
ctx: Box<dyn Ctx>,
path: PathBuf,
data: String,
) -> io::Result<()>;
/// Reads entries from a directory.
///
@ -98,7 +108,7 @@ pub trait FileSystemApi: Send + Sync {
/// * `include_root` - if true, will include the directory specified in the entries
async fn read_dir(
&self,
ctx: BoxedCtx,
ctx: Box<dyn Ctx>,
path: PathBuf,
depth: usize,
absolute: bool,
@ -110,30 +120,30 @@ pub trait FileSystemApi: Send + Sync {
///
/// * `path` - the path to the directory
/// * `all` - if true, will create all missing parent components
async fn create_dir(&self, ctx: BoxedCtx, path: PathBuf, all: bool) -> io::Result<()>;
async fn create_dir(&self, ctx: Box<dyn Ctx>, path: PathBuf, all: bool) -> io::Result<()>;
/// Copies some file or directory.
///
/// * `src` - the path to the file or directory to copy
/// * `dst` - the path where the copy will be placed
async fn copy(&self, ctx: BoxedCtx, src: PathBuf, dst: PathBuf) -> io::Result<()>;
async fn copy(&self, ctx: Box<dyn Ctx>, src: PathBuf, dst: PathBuf) -> io::Result<()>;
/// Removes some file or directory.
///
/// * `path` - the path to a file or directory
/// * `force` - if true, will remove non-empty directories
async fn remove(&self, ctx: BoxedCtx, path: PathBuf, force: bool) -> io::Result<()>;
async fn remove(&self, ctx: Box<dyn Ctx>, path: PathBuf, force: bool) -> io::Result<()>;
/// Renames some file or directory.
///
/// * `src` - the path to the file or directory to rename
/// * `dst` - the new name for the file or directory
async fn rename(&self, ctx: BoxedCtx, src: PathBuf, dst: PathBuf) -> io::Result<()>;
async fn rename(&self, ctx: Box<dyn Ctx>, src: PathBuf, dst: PathBuf) -> io::Result<()>;
/// Checks if the specified path exists.
///
/// * `path` - the path to the file or directory
async fn exists(&self, ctx: BoxedCtx, path: PathBuf) -> io::Result<bool>;
async fn exists(&self, ctx: Box<dyn Ctx>, path: PathBuf) -> io::Result<bool>;
/// Reads metadata for a file or directory.
///
@ -142,7 +152,7 @@ pub trait FileSystemApi: Send + Sync {
/// * `resolve_file_type` - if true, will resolve symlinks to underlying type (file or dir)
async fn metadata(
&self,
ctx: BoxedCtx,
ctx: Box<dyn Ctx>,
path: PathBuf,
canonicalize: bool,
resolve_file_type: bool,
@ -155,7 +165,7 @@ pub trait FileSystemApi: Send + Sync {
/// * `permissions` - the new permissions to apply
async fn set_permissions(
&self,
ctx: BoxedCtx,
ctx: Box<dyn Ctx>,
path: PathBuf,
permissions: Permissions,
options: SetPermissionsOptions,
@ -173,7 +183,7 @@ pub trait ProcessApi: Send + Sync {
/// * `pty` - if provided, will run the process within a PTY of the given size
async fn proc_spawn(
&self,
ctx: BoxedCtx,
ctx: Box<dyn Ctx>,
cmd: String,
environment: Environment,
current_dir: Option<PathBuf>,
@ -183,19 +193,24 @@ pub trait ProcessApi: Send + Sync {
/// Kills a running process by its id.
///
/// * `id` - the unique id of the process
async fn proc_kill(&self, ctx: BoxedCtx, id: ProcessId) -> io::Result<()>;
async fn proc_kill(&self, ctx: Box<dyn Ctx>, id: ProcessId) -> io::Result<()>;
/// Sends data to the stdin of the process with the specified id.
///
/// * `id` - the unique id of the process
/// * `data` - the bytes to send to stdin
async fn proc_stdin(&self, ctx: BoxedCtx, id: ProcessId, data: Vec<u8>) -> io::Result<()>;
async fn proc_stdin(&self, ctx: Box<dyn Ctx>, id: ProcessId, data: Vec<u8>) -> io::Result<()>;
/// Resizes the PTY of the process with the specified id.
///
/// * `id` - the unique id of the process
/// * `size` - the new size of the pty
async fn proc_resize_pty(&self, ctx: BoxedCtx, id: ProcessId, size: PtySize) -> io::Result<()>;
async fn proc_resize_pty(
&self,
ctx: Box<dyn Ctx>,
id: ProcessId,
size: PtySize,
) -> io::Result<()>;
}
/// API supporting searching through the remote system.
@ -204,26 +219,26 @@ pub trait SearchApi: Send + Sync {
/// Searches files for matches based on a query.
///
/// * `query` - the specific query to perform
async fn search(&self, ctx: BoxedCtx, query: SearchQuery) -> io::Result<SearchId>;
async fn search(&self, ctx: Box<dyn Ctx>, query: SearchQuery) -> io::Result<SearchId>;
/// Cancels an actively-ongoing search.
///
/// * `id` - the id of the search to cancel
async fn cancel_search(&self, ctx: BoxedCtx, id: SearchId) -> io::Result<()>;
async fn cancel_search(&self, ctx: Box<dyn Ctx>, id: SearchId) -> io::Result<()>;
}
/// API supporting retrieval of information about the remote system.
#[async_trait]
pub trait SystemInfoApi: Send + Sync {
/// Retrieves information about the system.
async fn system_info(&self, ctx: BoxedCtx) -> io::Result<SystemInfo>;
async fn system_info(&self, ctx: Box<dyn Ctx>) -> io::Result<SystemInfo>;
}
/// API supporting retrieval of the server's version.
#[async_trait]
pub trait VersionApi: Send + Sync {
/// Retrieves information about the server's capabilities.
async fn version(&self, ctx: BoxedCtx) -> io::Result<Version>;
async fn version(&self, ctx: Box<dyn Ctx>) -> io::Result<Version>;
}
/// API supporting watching of changes to the remote filesystem.
@ -237,7 +252,7 @@ pub trait WatchApi: Send + Sync {
/// * `except` - if non-empty, will limit reported changes to those not included in this list
async fn watch(
&self,
ctx: BoxedCtx,
ctx: Box<dyn Ctx>,
path: PathBuf,
recursive: bool,
only: Vec<ChangeKind>,
@ -247,5 +262,5 @@ pub trait WatchApi: Send + Sync {
/// Removes a file or directory from being watched.
///
/// * `path` - the path to the file or directory
async fn unwatch(&self, ctx: BoxedCtx, path: PathBuf) -> io::Result<()>;
async fn unwatch(&self, ctx: Box<dyn Ctx>, path: PathBuf) -> io::Result<()>;
}

@ -3,9 +3,6 @@ use std::io;
use async_trait::async_trait;
use distant_core_protocol::Response;
/// Type abstraction of a boxed [`Ctx`].
pub type BoxedCtx = Box<dyn Ctx>;
/// Represents a context associated when an API request is being executed, supporting the ability
/// to send responses back asynchronously.
#[async_trait]
@ -14,7 +11,7 @@ pub trait Ctx: Send {
fn connection(&self) -> u32;
/// Clones context, returning a new boxed instance.
fn clone_ctx(&self) -> BoxedCtx;
fn clone_ctx(&self) -> Box<dyn Ctx>;
/// Sends some response back.
fn send(&self, response: Response) -> io::Result<()>;

@ -50,34 +50,44 @@ impl Api for Unsupported {
#[async_trait]
impl FileSystemApi for Unsupported {
async fn read_file(&self, _ctx: BoxedCtx, _path: PathBuf) -> io::Result<Vec<u8>> {
async fn read_file(&self, _ctx: Box<dyn Ctx>, _path: PathBuf) -> io::Result<Vec<u8>> {
unsupported("read_file")
}
async fn read_file_text(&self, _ctx: BoxedCtx, _path: PathBuf) -> io::Result<String> {
async fn read_file_text(&self, _ctx: Box<dyn Ctx>, _path: PathBuf) -> io::Result<String> {
unsupported("read_file_text")
}
async fn write_file(&self, _ctx: BoxedCtx, _path: PathBuf, _data: Vec<u8>) -> io::Result<()> {
async fn write_file(
&self,
_ctx: Box<dyn Ctx>,
_path: PathBuf,
_data: Vec<u8>,
) -> io::Result<()> {
unsupported("write_file")
}
async fn write_file_text(
&self,
_ctx: BoxedCtx,
_ctx: Box<dyn Ctx>,
_path: PathBuf,
_data: String,
) -> io::Result<()> {
unsupported("write_file_text")
}
async fn append_file(&self, _ctx: BoxedCtx, _path: PathBuf, _data: Vec<u8>) -> io::Result<()> {
async fn append_file(
&self,
_ctx: Box<dyn Ctx>,
_path: PathBuf,
_data: Vec<u8>,
) -> io::Result<()> {
unsupported("append_file")
}
async fn append_file_text(
&self,
_ctx: BoxedCtx,
_ctx: Box<dyn Ctx>,
_path: PathBuf,
_data: String,
) -> io::Result<()> {
@ -86,7 +96,7 @@ impl FileSystemApi for Unsupported {
async fn read_dir(
&self,
_ctx: BoxedCtx,
_ctx: Box<dyn Ctx>,
_path: PathBuf,
_depth: usize,
_absolute: bool,
@ -96,29 +106,29 @@ impl FileSystemApi for Unsupported {
unsupported("read_dir")
}
async fn create_dir(&self, _ctx: BoxedCtx, _path: PathBuf, _all: bool) -> io::Result<()> {
async fn create_dir(&self, _ctx: Box<dyn Ctx>, _path: PathBuf, _all: bool) -> io::Result<()> {
unsupported("create_dir")
}
async fn copy(&self, _ctx: BoxedCtx, _src: PathBuf, _dst: PathBuf) -> io::Result<()> {
async fn copy(&self, _ctx: Box<dyn Ctx>, _src: PathBuf, _dst: PathBuf) -> io::Result<()> {
unsupported("copy")
}
async fn remove(&self, _ctx: BoxedCtx, _path: PathBuf, _force: bool) -> io::Result<()> {
async fn remove(&self, _ctx: Box<dyn Ctx>, _path: PathBuf, _force: bool) -> io::Result<()> {
unsupported("remove")
}
async fn rename(&self, _ctx: BoxedCtx, _src: PathBuf, _dst: PathBuf) -> io::Result<()> {
async fn rename(&self, _ctx: Box<dyn Ctx>, _src: PathBuf, _dst: PathBuf) -> io::Result<()> {
unsupported("rename")
}
async fn exists(&self, _ctx: BoxedCtx, _path: PathBuf) -> io::Result<bool> {
async fn exists(&self, _ctx: Box<dyn Ctx>, _path: PathBuf) -> io::Result<bool> {
unsupported("exists")
}
async fn metadata(
&self,
_ctx: BoxedCtx,
_ctx: Box<dyn Ctx>,
_path: PathBuf,
_canonicalize: bool,
_resolve_file_type: bool,
@ -128,7 +138,7 @@ impl FileSystemApi for Unsupported {
async fn set_permissions(
&self,
_ctx: BoxedCtx,
_ctx: Box<dyn Ctx>,
_path: PathBuf,
_permissions: Permissions,
_options: SetPermissionsOptions,
@ -141,7 +151,7 @@ impl FileSystemApi for Unsupported {
impl ProcessApi for Unsupported {
async fn proc_spawn(
&self,
_ctx: BoxedCtx,
_ctx: Box<dyn Ctx>,
_cmd: String,
_environment: Environment,
_current_dir: Option<PathBuf>,
@ -150,17 +160,22 @@ impl ProcessApi for Unsupported {
unsupported("proc_spawn")
}
async fn proc_kill(&self, _ctx: BoxedCtx, _id: ProcessId) -> io::Result<()> {
async fn proc_kill(&self, _ctx: Box<dyn Ctx>, _id: ProcessId) -> io::Result<()> {
unsupported("proc_kill")
}
async fn proc_stdin(&self, _ctx: BoxedCtx, _id: ProcessId, _data: Vec<u8>) -> io::Result<()> {
async fn proc_stdin(
&self,
_ctx: Box<dyn Ctx>,
_id: ProcessId,
_data: Vec<u8>,
) -> io::Result<()> {
unsupported("proc_stdin")
}
async fn proc_resize_pty(
&self,
_ctx: BoxedCtx,
_ctx: Box<dyn Ctx>,
_id: ProcessId,
_size: PtySize,
) -> io::Result<()> {
@ -170,25 +185,25 @@ impl ProcessApi for Unsupported {
#[async_trait]
impl SearchApi for Unsupported {
async fn search(&self, _ctx: BoxedCtx, _query: SearchQuery) -> io::Result<SearchId> {
async fn search(&self, _ctx: Box<dyn Ctx>, _query: SearchQuery) -> io::Result<SearchId> {
unsupported("search")
}
async fn cancel_search(&self, _ctx: BoxedCtx, _id: SearchId) -> io::Result<()> {
async fn cancel_search(&self, _ctx: Box<dyn Ctx>, _id: SearchId) -> io::Result<()> {
unsupported("cancel_search")
}
}
#[async_trait]
impl SystemInfoApi for Unsupported {
async fn system_info(&self, _ctx: BoxedCtx) -> io::Result<SystemInfo> {
async fn system_info(&self, _ctx: Box<dyn Ctx>) -> io::Result<SystemInfo> {
unsupported("system_info")
}
}
#[async_trait]
impl VersionApi for Unsupported {
async fn version(&self, _ctx: BoxedCtx) -> io::Result<Version> {
async fn version(&self, _ctx: Box<dyn Ctx>) -> io::Result<Version> {
unsupported("version")
}
}
@ -197,7 +212,7 @@ impl VersionApi for Unsupported {
impl WatchApi for Unsupported {
async fn watch(
&self,
_ctx: BoxedCtx,
_ctx: Box<dyn Ctx>,
_path: PathBuf,
_recursive: bool,
_only: Vec<ChangeKind>,
@ -206,7 +221,7 @@ impl WatchApi for Unsupported {
unsupported("watch")
}
async fn unwatch(&self, _ctx: BoxedCtx, _path: PathBuf) -> io::Result<()> {
async fn unwatch(&self, _ctx: Box<dyn Ctx>, _path: PathBuf) -> io::Result<()> {
unsupported("unwatch")
}
}

@ -1,8 +1,9 @@
use std::io;
use std::sync::{mpsc, Arc};
use std::sync::Arc;
use async_trait::async_trait;
use distant_core_protocol::{Error, Request, Response};
use tokio::sync::mpsc;
use crate::api::{
Api, Ctx, FileSystemApi, ProcessApi, SearchApi, SystemInfoApi, VersionApi, WatchApi,
@ -13,18 +14,25 @@ pub type BoxedClient = Box<dyn Client>;
/// Full API for a distant-compatible client.
#[async_trait]
pub trait Client {
/// Sends a request without waiting for a response; this method is able to be used even
/// if the session's receiving line to the remote server has been severed.
async fn fire(&mut self, request: Request) -> io::Result<()>;
/// Sends a request and returns a mailbox that can receive one or more responses, failing if
/// unable to send a request or if the session's receiving line to the remote server has
/// already been severed.
async fn mail(&mut self, request: Request) -> io::Result<mpsc::Receiver<Response>>;
/// Sends a request and returns a stream of responses, failing if unable to send a request or
/// if the session's receiving line to the remote server has already been severed.
async fn mail(&mut self, request: Request) -> io::Result<mpsc::UnboundedReceiver<Response>>;
/// Sends a request and waits for a response, failing if unable to send a request or if
/// the session's receiving line to the remote server has already been severed
async fn send(&mut self, request: Request) -> io::Result<Response>;
/// the session's receiving line to the remote server has already been severed.
async fn send(&mut self, request: Request) -> io::Result<Response> {
let mut rx = self.mail(request).await?;
rx.recv()
.await
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Channel has closed"))
}
/// Sends a request without waiting for a response; this method is able to be used even
/// if the session's receiving line to the remote server has been severed.
async fn fire(&mut self, request: Request) -> io::Result<()> {
let _ = self.send(request).await?;
Ok(())
}
}
/// Represents a bridge between a [`Client`] and an [`Api`] implementation that maps requests to
@ -45,15 +53,10 @@ impl<T: Api> ClientBridge<T> {
}
#[async_trait]
impl<T: Api> Client for ClientBridge<T> {
async fn fire(&mut self, request: Request) -> io::Result<()> {
let _ = self.send(request).await?;
Ok(())
}
async fn mail(&mut self, request: Request) -> io::Result<mpsc::Receiver<Response>> {
impl<T: Api + 'static> Client for ClientBridge<T> {
async fn mail(&mut self, request: Request) -> io::Result<mpsc::UnboundedReceiver<Response>> {
#[derive(Clone, Debug)]
struct __Ctx(u32, mpsc::Sender<Response>);
struct __Ctx(u32, mpsc::UnboundedSender<Response>);
impl Ctx for __Ctx {
fn connection(&self) -> u32 {
@ -71,34 +74,22 @@ impl<T: Api> 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...
//
// 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;
let (tx, rx) = mpsc::unbounded_channel();
let ctx = Box::new(__Ctx(rand::random(), tx));
Ok(rx)
}
tokio::task::spawn({
let api = Arc::clone(&self.api);
async move {
let response = {
let ctx = ctx.clone_ctx();
handle_request(api, ctx, request).await
};
async fn send(&mut self, request: Request) -> io::Result<Response> {
let rx = self.mail(request).await?;
let _ = ctx.send(response);
}
});
// 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"))
Ok(rx)
}
}

@ -146,7 +146,7 @@ impl FromStr for Host {
/// ### Examples
///
/// ```
/// # use distant_core_net::common::Host;
/// # use distant_plugin::common::Host;
/// # use std::net::{Ipv4Addr, Ipv6Addr};
/// // IPv4 address
/// assert_eq!("127.0.0.1".parse(), Ok(Host::Ipv4(Ipv4Addr::new(127, 0, 0, 1))));

@ -33,7 +33,7 @@ impl Map {
/// Keeping the value will result in `x` retaining the `a` key's original value:
///
/// ```rust
/// use distant_core_net::map;
/// use distant_plugin::map;
///
/// let mut x = map!("a" -> "hello", "b" -> "world");
/// let y = map!("a" -> "foo", "c" -> "bar");
@ -46,7 +46,7 @@ impl Map {
/// Not keeping the value will result in `x` replacing the `a` key's value:
///
/// ```rust
/// use distant_core_net::map;
/// use distant_plugin::map;
///
/// let mut x = map!("a" -> "hello", "b" -> "world");
/// let y = map!("a" -> "foo", "c" -> "bar");
@ -292,7 +292,7 @@ impl<'de> Deserialize<'de> for Map {
/// Generates a new [`Map`] of key/value pairs based on literals.
///
/// ```
/// use distant_core_net::map;
/// use distant_plugin::map;
///
/// let _map = map!("key" -> "value", "key2" -> "value2");
/// ```

@ -50,7 +50,7 @@ where
/// ### Examples
///
/// ```
/// use distant_core_plugin::boxed_launch_handler;
/// use distant_plugin::boxed_launch_handler;
///
/// let _handler = boxed_launch_handler!(|destination, options, authenticator| {
/// todo!("Implement handler logic.");
@ -121,7 +121,7 @@ where
/// ### Examples
///
/// ```
/// use distant_core_plugin::boxed_connect_handler;
/// use distant_plugin::boxed_connect_handler;
///
/// let _handler = boxed_connect_handler!(|destination, options, authenticator| {
/// todo!("Implement handler logic.");
@ -157,7 +157,7 @@ macro_rules! boxed_connect_handler {
#[cfg(test)]
mod tests {
use distant_core_auth::*;
use distant_core_auth::msg::*;
use test_log::test;
use super::*;
@ -177,34 +177,35 @@ mod tests {
fn test_authenticator() -> impl Authenticator {
struct __TestAuthenticator;
#[async_trait]
impl Authenticator for __TestAuthenticator {
async fn initialize(
&mut self,
initialization: Initialization,
_initialization: Initialization,
) -> io::Result<InitializationResponse> {
unimplemented!()
}
async fn challenge(&mut self, challenge: Challenge) -> io::Result<ChallengeResponse> {
async fn challenge(&mut self, _challenge: Challenge) -> io::Result<ChallengeResponse> {
unimplemented!()
}
async fn verify(
&mut self,
verification: Verification,
_verification: Verification,
) -> io::Result<VerificationResponse> {
unimplemented!()
}
async fn info(&mut self, info: Info) -> io::Result<()> {
async fn info(&mut self, _info: Info) -> io::Result<()> {
unimplemented!()
}
async fn error(&mut self, error: Error) -> io::Result<()> {
async fn error(&mut self, _error: Error) -> io::Result<()> {
unimplemented!()
}
async fn start_method(&mut self, start_method: StartMethod) -> io::Result<()> {
async fn start_method(&mut self, _start_method: StartMethod) -> io::Result<()> {
unimplemented!()
}
@ -221,66 +222,66 @@ mod tests {
let handler = boxed_launch_handler!(|_destination, _options, _authenticator| {
Err(io::Error::from(io::ErrorKind::Other))
});
assert_eq!(
handler
.launch(
&test_destination(),
&test_options(),
&mut test_authenticator()
)
.await
.unwrap_err()
.kind(),
io::ErrorKind::Other
);
let Err(err) = handler
.launch(
&test_destination(),
&test_options(),
&mut test_authenticator(),
)
.await
else {
panic!("Launch succeeded unexpectedly");
};
assert_eq!(err.kind(), io::ErrorKind::Other);
let handler = boxed_launch_handler!(|_destination, _options, _authenticator| async {
Err(io::Error::from(io::ErrorKind::Other))
});
assert_eq!(
handler
.launch(
&test_destination(),
&test_options(),
&mut test_authenticator()
)
.await
.unwrap_err()
.kind(),
io::ErrorKind::Other
);
let Err(err) = handler
.launch(
&test_destination(),
&test_options(),
&mut test_authenticator(),
)
.await
else {
panic!("Launch succeeded unexpectedly");
};
assert_eq!(err.kind(), io::ErrorKind::Other);
let handler = boxed_launch_handler!(move |_destination, _options, _authenticator| {
Err(io::Error::from(io::ErrorKind::Other))
});
assert_eq!(
handler
.launch(
&test_destination(),
&test_options(),
&mut test_authenticator()
)
.await
.unwrap_err()
.kind(),
io::ErrorKind::Other
);
let Err(err) = handler
.launch(
&test_destination(),
&test_options(),
&mut test_authenticator(),
)
.await
else {
panic!("Launch succeeded unexpectedly");
};
assert_eq!(err.kind(), io::ErrorKind::Other);
let handler = boxed_launch_handler!(move |_destination, _options, _authenticator| async {
Err(io::Error::from(io::ErrorKind::Other))
});
assert_eq!(
handler
.launch(
&test_destination(),
&test_options(),
&mut test_authenticator()
)
.await
.unwrap_err()
.kind(),
io::ErrorKind::Other
);
let Err(err) = handler
.launch(
&test_destination(),
&test_options(),
&mut test_authenticator(),
)
.await
else {
panic!("Launch succeeded unexpectedly");
};
assert_eq!(err.kind(), io::ErrorKind::Other);
}
#[test(tokio::test)]
@ -288,65 +289,65 @@ mod tests {
let handler = boxed_connect_handler!(|_destination, _options, _authenticator| {
Err(io::Error::from(io::ErrorKind::Other))
});
assert_eq!(
handler
.connect(
&test_destination(),
&test_options(),
&mut test_authenticator()
)
.await
.unwrap_err()
.kind(),
io::ErrorKind::Other
);
let Err(err) = handler
.connect(
&test_destination(),
&test_options(),
&mut test_authenticator(),
)
.await
else {
panic!("Connect succeeded unexpectedly");
};
assert_eq!(err.kind(), io::ErrorKind::Other);
let handler = boxed_connect_handler!(|_destination, _options, _authenticator| async {
Err(io::Error::from(io::ErrorKind::Other))
});
assert_eq!(
handler
.connect(
&test_destination(),
&test_options(),
&mut test_authenticator()
)
.await
.unwrap_err()
.kind(),
io::ErrorKind::Other
);
let Err(err) = handler
.connect(
&test_destination(),
&test_options(),
&mut test_authenticator(),
)
.await
else {
panic!("Connect succeeded unexpectedly");
};
assert_eq!(err.kind(), io::ErrorKind::Other);
let handler = boxed_connect_handler!(move |_destination, _options, _authenticator| {
Err(io::Error::from(io::ErrorKind::Other))
});
assert_eq!(
handler
.connect(
&test_destination(),
&test_options(),
&mut test_authenticator()
)
.await
.unwrap_err()
.kind(),
io::ErrorKind::Other
);
let Err(err) = handler
.connect(
&test_destination(),
&test_options(),
&mut test_authenticator(),
)
.await
else {
panic!("Connect succeeded unexpectedly");
};
assert_eq!(err.kind(), io::ErrorKind::Other);
let handler = boxed_connect_handler!(move |_destination, _options, _authenticator| async {
Err(io::Error::from(io::ErrorKind::Other))
});
assert_eq!(
handler
.connect(
&test_destination(),
&test_options(),
&mut test_authenticator()
)
.await
.unwrap_err()
.kind(),
io::ErrorKind::Other
);
let Err(err) = handler
.connect(
&test_destination(),
&test_options(),
&mut test_authenticator(),
)
.await
else {
panic!("Connect succeeded unexpectedly");
};
assert_eq!(err.kind(), io::ErrorKind::Other);
}
}

Loading…
Cancel
Save