diff --git a/distant-core/src/manager/client.rs b/distant-core/src/manager/client.rs index 1acdcc0..c260b2e 100644 --- a/distant-core/src/manager/client.rs +++ b/distant-core/src/manager/client.rs @@ -1,8 +1,9 @@ use super::data::{ - ConnectionId, ConnectionInfo, ConnectionList, Destination, Extra, ManagerRequest, - ManagerResponse, + ConnectionId, ConnectionInfo, ConnectionList, Destination, ManagerRequest, ManagerResponse, +}; +use crate::{ + DistantChannel, DistantClient, DistantMsg, DistantRequestData, DistantResponseData, Map, }; -use crate::{DistantChannel, DistantClient, DistantMsg, DistantRequestData, DistantResponseData}; use distant_net::{ router, Auth, AuthServer, Client, IntoSplit, MpscTransport, OneshotListener, Request, Response, ServerExt, ServerRef, UntypedTransportRead, UntypedTransportWrite, @@ -122,20 +123,23 @@ impl DistantManagerClient { } /// Request that the manager launches a new server at the given `destination` - /// with `extra` being passed for destination-specific details, returning the new + /// with `options` being passed for destination-specific details, returning the new /// `destination` of the spawned server to connect to pub async fn launch( &mut self, destination: impl Into, - extra: impl Into, + options: impl Into, ) -> io::Result { let destination = Box::new(destination.into()); - let extra = extra.into(); - trace!("launch({}, {})", destination, extra); + let options = options.into(); + trace!("launch({}, {})", destination, options); let res = self .client - .send(ManagerRequest::Launch { destination, extra }) + .send(ManagerRequest::Launch { + destination, + options, + }) .await?; match res.payload { ManagerResponse::Launched { destination } => Ok(destination), @@ -148,19 +152,22 @@ impl DistantManagerClient { } /// Request that the manager establishes a new connection at the given `destination` - /// with `extra` being passed for destination-specific details + /// with `options` being passed for destination-specific details pub async fn connect( &mut self, destination: impl Into, - extra: impl Into, + options: impl Into, ) -> io::Result { let destination = Box::new(destination.into()); - let extra = extra.into(); - trace!("connect({}, {})", destination, extra); + let options = options.into(); + trace!("connect({}, {})", destination, options); let res = self .client - .send(ManagerRequest::Connect { destination, extra }) + .send(ManagerRequest::Connect { + destination, + options, + }) .await?; match res.payload { ManagerResponse::Connected { id } => Ok(id), @@ -406,7 +413,7 @@ mod tests { let err = client .connect( "scheme://host".parse::().unwrap(), - "key=value".parse::().unwrap(), + "key=value".parse::().unwrap(), ) .await .unwrap_err(); @@ -434,7 +441,7 @@ mod tests { let err = client .connect( "scheme://host".parse::().unwrap(), - "key=value".parse::().unwrap(), + "key=value".parse::().unwrap(), ) .await .unwrap_err(); @@ -465,7 +472,7 @@ mod tests { let id = client .connect( "scheme://host".parse::().unwrap(), - "key=value".parse::().unwrap(), + "key=value".parse::().unwrap(), ) .await .unwrap(); @@ -532,7 +539,7 @@ mod tests { let info = ConnectionInfo { id: 123, destination: "scheme://host".parse::().unwrap(), - extra: "key=value".parse::().unwrap(), + options: "key=value".parse::().unwrap(), }; transport @@ -547,7 +554,7 @@ mod tests { info.destination, "scheme://host".parse::().unwrap() ); - assert_eq!(info.extra, "key=value".parse::().unwrap()); + assert_eq!(info.options, "key=value".parse::().unwrap()); } #[tokio::test] diff --git a/distant-core/src/manager/data.rs b/distant-core/src/manager/data.rs index 0be4b2a..b23d742 100644 --- a/distant-core/src/manager/data.rs +++ b/distant-core/src/manager/data.rs @@ -1,9 +1,6 @@ mod destination; pub use destination::*; -mod extra; -pub use extra::*; - mod id; pub use id::*; diff --git a/distant-core/src/manager/data/extra.rs b/distant-core/src/manager/data/extra.rs deleted file mode 100644 index 1e3e89a..0000000 --- a/distant-core/src/manager/data/extra.rs +++ /dev/null @@ -1,2 +0,0 @@ -/// Represents extra data included for connections -pub type Extra = crate::data::Map; diff --git a/distant-core/src/manager/data/info.rs b/distant-core/src/manager/data/info.rs index 517b0cc..b20c9b7 100644 --- a/distant-core/src/manager/data/info.rs +++ b/distant-core/src/manager/data/info.rs @@ -1,4 +1,5 @@ -use super::{ConnectionId, Destination, Extra}; +use super::{ConnectionId, Destination}; +use crate::data::Map; use serde::{Deserialize, Serialize}; /// Information about a specific connection @@ -10,6 +11,6 @@ pub struct ConnectionInfo { /// Destination with which this connection is associated pub destination: Destination, - /// Extra information associated with this connection - pub extra: Extra, + /// Additional options associated with this connection + pub options: Map, } diff --git a/distant-core/src/manager/data/request.rs b/distant-core/src/manager/data/request.rs index 2d29c35..b049920 100644 --- a/distant-core/src/manager/data/request.rs +++ b/distant-core/src/manager/data/request.rs @@ -1,5 +1,5 @@ -use super::{ChannelId, ConnectionId, Destination, Extra}; -use crate::{DistantMsg, DistantRequestData}; +use super::{ChannelId, ConnectionId, Destination}; +use crate::{DistantMsg, DistantRequestData, Map}; use distant_net::Request; use serde::{Deserialize, Serialize}; @@ -12,9 +12,9 @@ pub enum ManagerRequest { // NOTE: Boxed per clippy's large_enum_variant warning destination: Box, - /// Extra details specific to the connection + /// Additional options specific to the connection #[cfg_attr(feature = "clap", clap(short, long, action = clap::ArgAction::Append))] - extra: Extra, + options: Map, }, /// Initiate a connection through the manager @@ -22,9 +22,9 @@ pub enum ManagerRequest { // NOTE: Boxed per clippy's large_enum_variant warning destination: Box, - /// Extra details specific to the connection + /// Additional options specific to the connection #[cfg_attr(feature = "clap", clap(short, long, action = clap::ArgAction::Append))] - extra: Extra, + options: Map, }, /// Opens a channel for communication with a server diff --git a/distant-core/src/manager/server.rs b/distant-core/src/manager/server.rs index 81587b6..3f15a4c 100644 --- a/distant-core/src/manager/server.rs +++ b/distant-core/src/manager/server.rs @@ -1,6 +1,6 @@ use crate::{ - ChannelId, ConnectionId, ConnectionInfo, ConnectionList, Destination, Extra, ManagerRequest, - ManagerResponse, + ChannelId, ConnectionId, ConnectionInfo, ConnectionList, Destination, ManagerRequest, + ManagerResponse, Map, }; use async_trait::async_trait; use distant_net::{ @@ -123,14 +123,14 @@ impl DistantManager { }) } - /// Launches a new server at the specified `destination` using the given `extra` information + /// Launches a new server at the specified `destination` using the given `options` information /// and authentication client (if needed) to retrieve additional information needed to /// enter the destination prior to starting the server, returning the destination of the /// launched server async fn launch( &self, destination: Destination, - extra: Extra, + options: Map, auth: Option<&mut AuthClient>, ) -> io::Result { let auth = auth.ok_or_else(|| { @@ -163,19 +163,19 @@ impl DistantManager { format!("No launch handler registered for {}", scheme), ) })?; - handler.launch(&destination, &extra, auth).await? + handler.launch(&destination, &options, auth).await? }; Ok(credentials) } - /// Connects to a new server at the specified `destination` using the given `extra` information + /// Connects to a new server at the specified `destination` using the given `options` information /// and authentication client (if needed) to retrieve additional information needed to /// establish the connection to the server async fn connect( &self, destination: Destination, - extra: Extra, + options: Map, auth: Option<&mut AuthClient>, ) -> io::Result { let auth = auth.ok_or_else(|| { @@ -208,10 +208,10 @@ impl DistantManager { format!("No connect handler registered for {}", scheme), ) })?; - handler.connect(&destination, &extra, auth).await? + handler.connect(&destination, &options, auth).await? }; - let connection = DistantManagerConnection::new(destination, extra, writer, reader); + let connection = DistantManagerConnection::new(destination, options, writer, reader); let id = connection.id; self.connections.write().await.insert(id, connection); Ok(id) @@ -223,7 +223,7 @@ impl DistantManager { Some(connection) => Ok(ConnectionInfo { id: connection.id, destination: connection.destination.clone(), - extra: connection.extra.clone(), + options: connection.options.clone(), }), None => Err(io::Error::new( io::ErrorKind::NotConnected, @@ -297,24 +297,36 @@ impl Server for DistantManager { } = ctx; let response = match request.payload { - ManagerRequest::Launch { destination, extra } => { + ManagerRequest::Launch { + destination, + options, + } => { let mut auth = match local_data.auth_client.as_ref() { Some(client) => Some(client.lock().await), None => None, }; - match self.launch(*destination, extra, auth.as_deref_mut()).await { + match self + .launch(*destination, options, auth.as_deref_mut()) + .await + { Ok(destination) => ManagerResponse::Launched { destination }, Err(x) => ManagerResponse::Error(x.into()), } } - ManagerRequest::Connect { destination, extra } => { + ManagerRequest::Connect { + destination, + options, + } => { let mut auth = match local_data.auth_client.as_ref() { Some(client) => Some(client.lock().await), None => None, }; - match self.connect(*destination, extra, auth.as_deref_mut()).await { + match self + .connect(*destination, options, auth.as_deref_mut()) + .await + { Ok(id) => ManagerResponse::Connected { id }, Err(x) => ManagerResponse::Error(x.into()), } @@ -461,10 +473,10 @@ mod tests { let server = setup(); let destination = "scheme://host".parse::().unwrap(); - let extra = "".parse::().unwrap(); + let options = "".parse::().unwrap(); let (mut auth, _auth_server) = auth_client_server(); let err = server - .launch(destination, extra, Some(&mut auth)) + .launch(destination, options, Some(&mut auth)) .await .unwrap_err(); assert_eq!(err.kind(), io::ErrorKind::InvalidInput, "{:?}", err); @@ -485,10 +497,10 @@ mod tests { .insert("scheme".to_string(), handler); let destination = "scheme://host".parse::().unwrap(); - let extra = "".parse::().unwrap(); + let options = "".parse::().unwrap(); let (mut auth, _auth_server) = auth_client_server(); let err = server - .launch(destination, extra, Some(&mut auth)) + .launch(destination, options, Some(&mut auth)) .await .unwrap_err(); assert_eq!(err.kind(), io::ErrorKind::Other); @@ -512,10 +524,10 @@ mod tests { .insert("scheme".to_string(), handler); let destination = "scheme://host".parse::().unwrap(); - let extra = "key=value".parse::().unwrap(); + let options = "key=value".parse::().unwrap(); let (mut auth, _auth_server) = auth_client_server(); let destination = server - .launch(destination, extra, Some(&mut auth)) + .launch(destination, options, Some(&mut auth)) .await .unwrap(); @@ -530,10 +542,10 @@ mod tests { let server = setup(); let destination = "scheme://host".parse::().unwrap(); - let extra = "".parse::().unwrap(); + let options = "".parse::().unwrap(); let (mut auth, _auth_server) = auth_client_server(); let err = server - .connect(destination, extra, Some(&mut auth)) + .connect(destination, options, Some(&mut auth)) .await .unwrap_err(); assert_eq!(err.kind(), io::ErrorKind::InvalidInput, "{:?}", err); @@ -554,10 +566,10 @@ mod tests { .insert("scheme".to_string(), handler); let destination = "scheme://host".parse::().unwrap(); - let extra = "".parse::().unwrap(); + let options = "".parse::().unwrap(); let (mut auth, _auth_server) = auth_client_server(); let err = server - .connect(destination, extra, Some(&mut auth)) + .connect(destination, options, Some(&mut auth)) .await .unwrap_err(); assert_eq!(err.kind(), io::ErrorKind::Other); @@ -578,10 +590,10 @@ mod tests { .insert("scheme".to_string(), handler); let destination = "scheme://host".parse::().unwrap(); - let extra = "key=value".parse::().unwrap(); + let options = "key=value".parse::().unwrap(); let (mut auth, _auth_server) = auth_client_server(); let id = server - .connect(destination, extra, Some(&mut auth)) + .connect(destination, options, Some(&mut auth)) .await .unwrap(); @@ -589,7 +601,7 @@ mod tests { let connection = lock.get(&id).unwrap(); assert_eq!(connection.id, id); assert_eq!(connection.destination, "scheme://host"); - assert_eq!(connection.extra, "key=value".parse().unwrap()); + assert_eq!(connection.options, "key=value".parse().unwrap()); } #[tokio::test] @@ -620,7 +632,7 @@ mod tests { ConnectionInfo { id, destination: "scheme://host".parse().unwrap(), - extra: "key=value".parse().unwrap(), + options: "key=value".parse().unwrap(), } ); } diff --git a/distant-core/src/manager/server/connection.rs b/distant-core/src/manager/server/connection.rs index 112f1cf..843597b 100644 --- a/distant-core/src/manager/server/connection.rs +++ b/distant-core/src/manager/server/connection.rs @@ -1,6 +1,7 @@ use crate::{ + data::Map, manager::{ - data::{ChannelId, ConnectionId, Destination, Extra}, + data::{ChannelId, ConnectionId, Destination}, BoxedDistantReader, BoxedDistantWriter, }, DistantMsg, DistantRequestData, DistantResponseData, ManagerResponse, @@ -14,7 +15,7 @@ use tokio::{sync::mpsc, task::JoinHandle}; pub struct DistantManagerConnection { pub id: ConnectionId, pub destination: Destination, - pub extra: Extra, + pub options: Map, tx: mpsc::Sender, reader_task: JoinHandle<()>, writer_task: JoinHandle<()>, @@ -84,7 +85,7 @@ enum StateMachine { impl DistantManagerConnection { pub fn new( destination: Destination, - extra: Extra, + options: Map, mut writer: BoxedDistantWriter, mut reader: BoxedDistantReader, ) -> Self { @@ -162,7 +163,7 @@ impl DistantManagerConnection { Self { id: connection_id, destination, - extra, + options, tx, reader_task, writer_task, diff --git a/distant-core/src/manager/server/handler.rs b/distant-core/src/manager/server/handler.rs index a396f2e..f0fa6be 100644 --- a/distant-core/src/manager/server/handler.rs +++ b/distant-core/src/manager/server/handler.rs @@ -1,6 +1,5 @@ use crate::{ - manager::data::{Destination, Extra}, - DistantMsg, DistantRequestData, DistantResponseData, + data::Map, manager::data::Destination, DistantMsg, DistantRequestData, DistantResponseData, }; use async_trait::async_trait; use distant_net::{AuthClient, Request, Response, TypedAsyncRead, TypedAsyncWrite}; @@ -20,7 +19,7 @@ pub trait LaunchHandler: Send + Sync { async fn launch( &self, destination: &Destination, - extra: &Extra, + options: &Map, auth_client: &mut AuthClient, ) -> io::Result; } @@ -28,16 +27,16 @@ pub trait LaunchHandler: Send + Sync { #[async_trait] impl LaunchHandler for F where - F: for<'a> Fn(&'a Destination, &'a Extra, &'a mut AuthClient) -> R + Send + Sync + 'static, + F: for<'a> Fn(&'a Destination, &'a Map, &'a mut AuthClient) -> R + Send + Sync + 'static, R: Future> + Send + 'static, { async fn launch( &self, destination: &Destination, - extra: &Extra, + options: &Map, auth_client: &mut AuthClient, ) -> io::Result { - self(destination, extra, auth_client).await + self(destination, options, auth_client).await } } @@ -47,7 +46,7 @@ pub trait ConnectHandler: Send + Sync { async fn connect( &self, destination: &Destination, - extra: &Extra, + options: &Map, auth_client: &mut AuthClient, ) -> io::Result; } @@ -55,15 +54,15 @@ pub trait ConnectHandler: Send + Sync { #[async_trait] impl ConnectHandler for F where - F: for<'a> Fn(&'a Destination, &'a Extra, &'a mut AuthClient) -> R + Send + Sync + 'static, + F: for<'a> Fn(&'a Destination, &'a Map, &'a mut AuthClient) -> R + Send + Sync + 'static, R: Future> + Send + 'static, { async fn connect( &self, destination: &Destination, - extra: &Extra, + options: &Map, auth_client: &mut AuthClient, ) -> io::Result { - self(destination, extra, auth_client).await + self(destination, options, auth_client).await } } diff --git a/distant-core/tests/manager_tests.rs b/distant-core/tests/manager_tests.rs index ab7fe30..40527b8 100644 --- a/distant-core/tests/manager_tests.rs +++ b/distant-core/tests/manager_tests.rs @@ -1,7 +1,7 @@ use distant_core::{ net::{FramedTransport, InmemoryTransport, IntoSplit, OneshotListener, PlainCodec}, BoxedDistantReader, BoxedDistantWriter, Destination, DistantApiServer, DistantChannelExt, - DistantManager, DistantManagerClient, DistantManagerClientConfig, DistantManagerConfig, Extra, + DistantManager, DistantManagerClient, DistantManagerClientConfig, DistantManagerConfig, Map, }; use std::io; @@ -54,7 +54,7 @@ async fn should_be_able_to_establish_a_single_connection_and_communicate() { let id = client .connect( "scheme://host".parse::().unwrap(), - "key=value".parse::().unwrap(), + "key=value".parse::().unwrap(), ) .await .expect("Failed to connect to a remote server"); @@ -74,7 +74,7 @@ async fn should_be_able_to_establish_a_single_connection_and_communicate() { .expect("Failed to get info about connection"); assert_eq!(info.id, id); assert_eq!(info.destination.to_string(), "scheme://host"); - assert_eq!(info.extra, "key=value".parse::().unwrap()); + assert_eq!(info.options, "key=value".parse::().unwrap()); // Create a new channel and request some data let mut channel = client diff --git a/distant-net/src/auth.rs b/distant-net/src/auth.rs index 89f9b40..1f7e103 100644 --- a/distant-net/src/auth.rs +++ b/distant-net/src/auth.rs @@ -50,7 +50,7 @@ pub enum AuthRequest { /// Represents a challenge comprising a series of questions to be presented Challenge { questions: Vec, - extra: HashMap, + options: HashMap, }, /// Represents an ask to verify some information @@ -91,17 +91,17 @@ pub struct AuthQuestion { /// The text of the question pub text: String, - /// Any extra information specific to a particular auth domain + /// Any options information specific to a particular auth domain /// such as including a username and instructions for SSH authentication - pub extra: HashMap, + pub options: HashMap, } impl AuthQuestion { - /// Creates a new question without any extra data + /// Creates a new question without any options data pub fn new(text: impl Into) -> Self { Self { text: text.into(), - extra: HashMap::new(), + options: HashMap::new(), } } } diff --git a/distant-net/src/auth/client.rs b/distant-net/src/auth/client.rs index 3761d7c..206fdb5 100644 --- a/distant-net/src/auth/client.rs +++ b/distant-net/src/auth/client.rs @@ -83,18 +83,18 @@ impl AuthClient { pub async fn challenge( &mut self, questions: Vec, - extra: HashMap, + options: HashMap, ) -> io::Result> { trace!( - "AuthClient::challenge(questions = {:?}, extra = {:?})", + "AuthClient::challenge(questions = {:?}, options = {:?})", questions, - extra + options ); // Perform JIT handshake if enabled self.jit_handshake().await?; - let payload = AuthRequest::Challenge { questions, extra }; + let payload = AuthRequest::Challenge { questions, options }; let encrypted_payload = self.serialize_and_encrypt(&payload)?; let response = self.inner.send(Auth::Msg { encrypted_payload }).await?; @@ -281,7 +281,7 @@ mod tests { AuthQuestion::new("question1".to_string()), AuthQuestion { text: "question2".to_string(), - extra: vec![("key2".to_string(), "value2".to_string())] + options: vec![("key2".to_string(), "value2".to_string())] .into_iter() .collect(), }, @@ -360,7 +360,7 @@ mod tests { AuthQuestion::new("question1".to_string()), AuthQuestion { text: "question2".to_string(), - extra: vec![("key2".to_string(), "value2".to_string())] + options: vec![("key2".to_string(), "value2".to_string())] .into_iter() .collect(), }, @@ -398,14 +398,14 @@ mod tests { match request.payload { Auth::Msg { encrypted_payload } => { match decrypt_and_deserialize(&mut codec, &encrypted_payload).unwrap() { - AuthRequest::Challenge { questions, extra } => { + AuthRequest::Challenge { questions, options } => { assert_eq!( questions, vec![ AuthQuestion::new("question1".to_string()), AuthQuestion { text: "question2".to_string(), - extra: vec![("key2".to_string(), "value2".to_string())] + options: vec![("key2".to_string(), "value2".to_string())] .into_iter() .collect(), }, @@ -413,7 +413,7 @@ mod tests { ); assert_eq!( - extra, + options, vec![("key".to_string(), "value".to_string())] .into_iter() .collect(), diff --git a/distant-net/src/auth/server.rs b/distant-net/src/auth/server.rs index 7e01e99..2c5f599 100644 --- a/distant-net/src/auth/server.rs +++ b/distant-net/src/auth/server.rs @@ -120,12 +120,12 @@ where let response = match request { Ok(request) => match request { - AuthRequest::Challenge { questions, extra } => { + AuthRequest::Challenge { questions, options } => { trace!("Received challenge request"); trace!("questions = {:?}", questions); - trace!("extra = {:?}", extra); + trace!("options = {:?}", options); - let answers = (self.on_challenge)(questions, extra); + let answers = (self.on_challenge)(questions, options); AuthResponse::Challenge { answers } } AuthRequest::Verify { kind, text } => { @@ -310,8 +310,8 @@ mod tests { let (tx, mut rx) = mpsc::channel(1); let (mut t, _) = spawn_auth_server( /* on_challenge */ - move |questions, extra| { - tx.try_send((questions, extra)).unwrap(); + move |questions, options| { + tx.try_send((questions, options)).unwrap(); vec!["answer1".to_string(), "answer2".to_string()] }, /* on_verify */ |_, _| false, @@ -346,12 +346,12 @@ mod tests { AuthQuestion::new("question1".to_string()), AuthQuestion { text: "question2".to_string(), - extra: vec![("key".to_string(), "value".to_string())] + options: vec![("key".to_string(), "value".to_string())] .into_iter() .collect(), }, ], - extra: vec![("hello".to_string(), "world".to_string())] + options: vec![("hello".to_string(), "world".to_string())] .into_iter() .collect(), }, @@ -362,21 +362,21 @@ mod tests { .unwrap(); // Verify that the handler was triggered - let (questions, extra) = rx.recv().await.expect("Channel closed unexpectedly"); + let (questions, options) = rx.recv().await.expect("Channel closed unexpectedly"); assert_eq!( questions, vec![ AuthQuestion::new("question1".to_string()), AuthQuestion { text: "question2".to_string(), - extra: vec![("key".to_string(), "value".to_string())] + options: vec![("key".to_string(), "value".to_string())] .into_iter() .collect(), } ] ); assert_eq!( - extra, + options, vec![("hello".to_string(), "world".to_string())] .into_iter() .collect() diff --git a/distant-net/tests/auth.rs b/distant-net/tests/auth.rs index b666a66..e798446 100644 --- a/distant-net/tests/auth.rs +++ b/distant-net/tests/auth.rs @@ -23,9 +23,9 @@ fn setup() -> (AuthClient, mpsc::Receiver) { // Make a server that echos questions back as answers and only verifies the text "yes" let server = AuthServer { - on_challenge: move |questions, extra| { + on_challenge: move |questions, options| { let questions_2 = questions.clone(); - tx.try_send(AuthRequest::Challenge { questions, extra }) + tx.try_send(AuthRequest::Challenge { questions, options }) .unwrap(); questions_2.into_iter().map(|x| x.text).collect() }, @@ -75,12 +75,12 @@ async fn client_should_be_able_to_challenge_against_server() { // Verify that the server received the request let request = rx.recv().await.unwrap(); match request { - AuthRequest::Challenge { questions, extra } => { + AuthRequest::Challenge { questions, options } => { assert_eq!(questions.len(), 1); assert_eq!(questions[0].text, "hello"); - assert_eq!(questions[0].extra, HashMap::new()); + assert_eq!(questions[0].options, HashMap::new()); - assert_eq!(extra, HashMap::new()); + assert_eq!(options, HashMap::new()); } x => panic!("Unexpected request received by server: {:?}", x), } diff --git a/src/cli/client.rs b/src/cli/client.rs index 7a93abf..6d12b19 100644 --- a/src/cli/client.rs +++ b/src/cli/client.rs @@ -42,10 +42,11 @@ impl Client { on_challenge: { let tx = tx.clone(); let rx = rx.clone(); - Box::new(move |questions, extra| { + Box::new(move |questions, options| { let question_cnt = questions.len(); - if let Err(x) = tx.send_blocking(&AuthRequest::Challenge { questions, extra }) { + if let Err(x) = tx.send_blocking(&AuthRequest::Challenge { questions, options }) + { error!("{}", x); return (0..question_cnt) .into_iter() diff --git a/src/cli/commands/client.rs b/src/cli/commands/client.rs index 65fc0fa..10fc8ad 100644 --- a/src/cli/commands/client.rs +++ b/src/cli/commands/client.rs @@ -3,7 +3,10 @@ use crate::{ client::{MsgReceiver, MsgSender}, Cache, Client, }, - config::{ClientConfig, ClientLaunchConfig, NetworkConfig}, + config::{ + ClientActionConfig, ClientConfig, ClientConnectConfig, ClientLaunchConfig, + ClientReplConfig, NetworkConfig, + }, paths::user::CACHE_FILE_PATH_STR, CliError, CliResult, }; @@ -14,7 +17,7 @@ use distant_core::{ data::{ChangeKindSet, Environment}, net::{IntoSplit, Request, Response, TypedAsyncRead, TypedAsyncWrite}, ConnectionId, Destination, DistantManagerClient, DistantMsg, DistantRequestData, - DistantResponseData, Extra, Host, RemoteCommand, Watcher, + DistantResponseData, Host, Map, RemoteCommand, Watcher, }; use log::*; use serde_json::{json, Value}; @@ -50,6 +53,9 @@ pub enum ClientSubcommand { )] cache: PathBuf, + #[clap(flatten)] + config: ClientActionConfig, + /// Specify a connection being managed #[clap(long)] connection: Option, @@ -57,10 +63,6 @@ pub enum ClientSubcommand { #[clap(flatten)] network: NetworkConfig, - /// Represents the maximum time (in seconds) to wait for a network request before timing out - #[clap(short, long)] - timeout: Option, - #[clap(subcommand)] request: DistantRequestData, }, @@ -76,6 +78,9 @@ pub enum ClientSubcommand { )] cache: PathBuf, + #[clap(flatten)] + config: ClientConnectConfig, + #[clap(flatten)] network: NetworkConfig, @@ -149,6 +154,9 @@ pub enum ClientSubcommand { )] cache: PathBuf, + #[clap(flatten)] + config: ClientReplConfig, + /// Specify a connection being managed #[clap(long)] connection: Option, @@ -159,10 +167,6 @@ pub enum ClientSubcommand { /// Format used for input into and output from the repl #[clap(short, long, default_value_t, value_enum)] format: Format, - - /// Represents the maximum time (in seconds) to wait for a network request before timing out - #[clap(short, long)] - timeout: Option, }, /// Select the active connection @@ -244,10 +248,10 @@ impl ClientSubcommand { match self { Self::Action { + config: action_config, connection, network, request, - timeout, .. } => { let network = network.merge(config.network); @@ -265,6 +269,8 @@ impl ClientSubcommand { format!("Failed to open channel to connection {connection_id}") })?; + let timeout = action_config.timeout.or(config.action.timeout); + debug!( "Timeout configured to be {}", match timeout { @@ -375,6 +381,7 @@ impl ClientSubcommand { } } Self::Connect { + config: connect_config, network, format, destination, @@ -393,10 +400,15 @@ impl ClientSubcommand { .context("Failed to connect to manager")? }; + // Merge our connect configs, overwriting anything in the config file with our cli + // arguments + let mut options = Map::from(config.connect); + options.extend(Map::from(connect_config).into_map()); + // Trigger our manager to connect to the launched server - debug!("Connecting to server at {}", destination); + debug!("Connecting to server at {} with {}", destination, options); let id = client - .connect(*destination, Extra::new()) + .connect(*destination, options) .await .context("Failed to connect to server")?; @@ -418,7 +430,7 @@ impl ClientSubcommand { } } Self::Launch { - config: launcher_config, + config: launch_config, network, format, mut destination, @@ -439,8 +451,8 @@ impl ClientSubcommand { // Merge our launch configs, overwriting anything in the config file // with our cli arguments - let mut extra = Extra::from(config.launch); - extra.extend(Extra::from(launcher_config).into_map()); + let mut options = Map::from(config.launch); + options.extend(Map::from(launch_config).into_map()); // Grab the host we are connecting to for later use let host = destination.host.to_string(); @@ -455,9 +467,9 @@ impl ClientSubcommand { } // Start the server using our manager - debug!("Launching server at {} with {}", destination, extra); + debug!("Launching server at {} with {}", destination, options); let mut new_destination = client - .launch(*destination, extra) + .launch(*destination, options) .await .context("Failed to launch server")?; @@ -480,7 +492,7 @@ impl ClientSubcommand { // Trigger our manager to connect to the launched server debug!("Connecting to server at {}", new_destination); let id = client - .connect(new_destination, Extra::new()) + .connect(new_destination, Map::new()) .await .context("Failed to connect to server")?; @@ -531,10 +543,10 @@ impl ClientSubcommand { Lsp::new(channel).spawn(cmd, persist, pty).await?; } Self::Repl { + config: repl_config, connection, network, format, - timeout, .. } => { let network = network.merge(config.network); @@ -548,6 +560,8 @@ impl ClientSubcommand { let connection_id = use_or_lookup_connection_id(&mut cache, connection, &mut client).await?; + let timeout = repl_config.timeout.or(config.repl.timeout); + debug!("Opening raw channel to connection {}", connection_id); let channel = client .open_raw_channel(connection_id) diff --git a/src/cli/commands/manager.rs b/src/cli/commands/manager.rs index d1e6175..ea9306f 100644 --- a/src/cli/commands/manager.rs +++ b/src/cli/commands/manager.rs @@ -343,7 +343,7 @@ impl ManagerSubcommand { scheme: String, host: String, port: String, - extra: String, + options: String, } println!( @@ -357,7 +357,7 @@ impl ManagerSubcommand { .port .map(|x| x.to_string()) .unwrap_or_default(), - extra: info.extra.to_string() + options: info.options.to_string() }]) ); diff --git a/src/cli/commands/manager/handlers.rs b/src/cli/commands/manager/handlers.rs index 10d0d62..ee89f0f 100644 --- a/src/cli/commands/manager/handlers.rs +++ b/src/cli/commands/manager/handlers.rs @@ -6,7 +6,7 @@ use distant_core::{ XChaCha20Poly1305Codec, }, BoxedDistantReader, BoxedDistantWriter, BoxedDistantWriterReader, ConnectHandler, Destination, - Extra, LaunchHandler, + LaunchHandler, Map, }; use log::*; use std::{ @@ -49,11 +49,11 @@ impl LaunchHandler for ManagerLaunchHandler { async fn launch( &self, destination: &Destination, - extra: &Extra, + options: &Map, _auth_client: &mut AuthClient, ) -> io::Result { - trace!("Handling launch of {destination} with extra '{extra}'"); - let config = ClientLaunchConfig::from(extra.clone()); + debug!("Handling launch of {destination} with options '{options}'"); + let config = ClientLaunchConfig::from(options.clone()); // Get the path to the distant binary, ensuring it exists and is executable let program = which::which(match config.distant.bin { @@ -86,13 +86,13 @@ impl LaunchHandler for ManagerLaunchHandler { args.push(port.to_string()); } - // Add any extra arguments to the command - if let Some(extra_args) = config.distant.args { + // Add any options arguments to the command + if let Some(options_args) = config.distant.args { // NOTE: Split arguments based on whether we are running on windows or unix args.extend(if cfg!(windows) { - winsplit::split(&extra_args) + winsplit::split(&options_args) } else { - shell_words::split(&extra_args) + shell_words::split(&options_args) .map_err(|x| io::Error::new(io::ErrorKind::InvalidInput, x))? }); } @@ -162,14 +162,14 @@ impl LaunchHandler for SshLaunchHandler { async fn launch( &self, destination: &Destination, - extra: &Extra, + options: &Map, auth_client: &mut AuthClient, ) -> io::Result { - trace!("Handling launch of {destination} with extra '{extra}'"); - let config = ClientLaunchConfig::from(extra.clone()); + debug!("Handling launch of {destination} with options '{options}'"); + let config = ClientLaunchConfig::from(options.clone()); use distant_ssh2::DistantLaunchOpts; - let mut ssh = load_ssh(destination, extra)?; + let mut ssh = load_ssh(destination, options)?; let handler = AuthClientSshAuthHandler::new(auth_client); let _ = ssh.authenticate(handler).await?; let opts = { @@ -178,7 +178,7 @@ impl LaunchHandler for SshLaunchHandler { binary: config.distant.bin.unwrap_or(opts.binary), args: config.distant.args.unwrap_or(opts.args), use_login_shell: !config.distant.no_shell, - timeout: match extra.get("timeout") { + timeout: match options.get("timeout") { Some(s) => std::time::Duration::from_millis( s.parse::().map_err(|_| invalid("timeout"))?, ), @@ -218,10 +218,10 @@ impl ConnectHandler for DistantConnectHandler { async fn connect( &self, destination: &Destination, - extra: &Extra, + options: &Map, auth_client: &mut AuthClient, ) -> io::Result { - trace!("Handling connect of {destination} with extra '{extra}'"); + debug!("Handling connect of {destination} with options '{options}'"); let host = destination.host.to_string(); let port = destination.port.ok_or_else(|| missing("port"))?; @@ -246,13 +246,13 @@ impl ConnectHandler for DistantConnectHandler { )); } - // Use provided password or extra key if available, otherwise ask for it, and produce a + // Use provided password or options key if available, otherwise ask for it, and produce a // codec using the key let codec = { let key = destination .password .as_deref() - .or_else(|| extra.get("key").map(|s| s.as_str())); + .or_else(|| options.get("key").map(|s| s.as_str())); let key = match key { Some(key) => key.parse::().map_err(|_| invalid("key"))?, @@ -290,11 +290,11 @@ impl ConnectHandler for SshConnectHandler { async fn connect( &self, destination: &Destination, - extra: &Extra, + options: &Map, auth_client: &mut AuthClient, ) -> io::Result { - trace!("Handling connect of {destination} with extra '{extra}'"); - let mut ssh = load_ssh(destination, extra)?; + debug!("Handling connect of {destination} with options '{options}'"); + let mut ssh = load_ssh(destination, options)?; let handler = AuthClientSshAuthHandler::new(auth_client); let _ = ssh.authenticate(handler).await?; ssh.into_distant_writer_reader().await @@ -316,22 +316,22 @@ impl<'a> AuthClientSshAuthHandler<'a> { impl<'a> distant_ssh2::SshAuthHandler for AuthClientSshAuthHandler<'a> { async fn on_authenticate(&self, event: distant_ssh2::SshAuthEvent) -> io::Result> { use std::collections::HashMap; - let mut extra = HashMap::new(); + let mut options = HashMap::new(); let mut questions = Vec::new(); for prompt in event.prompts { - let mut extra = HashMap::new(); - extra.insert("echo".to_string(), prompt.echo.to_string()); + let mut options = HashMap::new(); + options.insert("echo".to_string(), prompt.echo.to_string()); questions.push(AuthQuestion { text: prompt.prompt, - extra, + options, }); } - extra.insert("instructions".to_string(), event.instructions); - extra.insert("username".to_string(), event.username); + options.insert("instructions".to_string(), event.instructions); + options.insert("username".to_string(), event.username); - self.0.lock().await.challenge(questions, extra).await + self.0.lock().await.challenge(questions, options).await } async fn on_verify_host(&self, host: &str) -> io::Result { @@ -364,27 +364,30 @@ impl<'a> distant_ssh2::SshAuthHandler for AuthClientSshAuthHandler<'a> { } #[cfg(any(feature = "libssh", feature = "ssh2"))] -fn load_ssh(destination: &Destination, extra: &Extra) -> io::Result { - trace!("load_ssh({destination}, {extra}"); +fn load_ssh(destination: &Destination, options: &Map) -> io::Result { + trace!("load_ssh({destination}, {options})"); use distant_ssh2::{Ssh, SshOpts}; let host = destination.host.to_string(); let opts = SshOpts { - backend: match extra.get("backend").or_else(|| extra.get("ssh.backend")) { + backend: match options + .get("backend") + .or_else(|| options.get("ssh.backend")) + { Some(s) => s.parse().map_err(|_| invalid("backend"))?, None => Default::default(), }, - identity_files: extra + identity_files: options .get("identity_files") - .or_else(|| extra.get("ssh.identity_files")) + .or_else(|| options.get("ssh.identity_files")) .map(|s| s.split(',').map(|s| PathBuf::from(s.trim())).collect()) .unwrap_or_default(), - identities_only: match extra + identities_only: match options .get("identities_only") - .or_else(|| extra.get("ssh.identities_only")) + .or_else(|| options.get("ssh.identities_only")) { Some(s) => Some(s.parse().map_err(|_| invalid("identities_only"))?), None => None, @@ -392,20 +395,23 @@ fn load_ssh(destination: &Destination, extra: &Extra) -> io::Result s.parse().map_err(|_| invalid("verbose"))?, None => false, }, diff --git a/src/config/client/action.rs b/src/config/client/action.rs index f4f7831..82fda0e 100644 --- a/src/config/client/action.rs +++ b/src/config/client/action.rs @@ -1,6 +1,7 @@ +use clap::Args; use serde::{Deserialize, Serialize}; -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Args, Debug, Default, Serialize, Deserialize)] pub struct ClientActionConfig { /// Represents the maximum time (in seconds) to wait for a network request before timing out pub timeout: Option, diff --git a/src/config/client/connect.rs b/src/config/client/connect.rs index 4904add..defd4a1 100644 --- a/src/config/client/connect.rs +++ b/src/config/client/connect.rs @@ -1,62 +1,28 @@ use clap::Args; use distant_core::Map; use serde::{Deserialize, Serialize}; -use std::path::PathBuf; #[derive(Args, Debug, Default, Serialize, Deserialize)] pub struct ClientConnectConfig { - #[cfg(any(feature = "libssh", feature = "ssh2"))] - #[clap(flatten)] + /// Additional options to provide, typically forwarded to the handler within the manager + /// facilitating the connection. Options are key-value pairs separated by comma. + /// + /// E.g. `key="value",key2="value2"` + #[clap(long, default_value_t)] #[serde(flatten)] - pub ssh: ClientConnectSshConfig, + pub options: Map, } impl From for ClientConnectConfig { - fn from(mut map: Map) -> Self { - Self { - #[cfg(any(feature = "libssh", feature = "ssh2"))] - ssh: ClientConnectSshConfig { - backend: map - .remove("ssh.backend") - .and_then(|x| x.parse::().ok()), - identity_file: map - .remove("ssh.identity_file") - .and_then(|x| x.parse::().ok()), - }, - } + fn from(map: Map) -> Self { + Self { options: map } } } impl From for Map { fn from(config: ClientConnectConfig) -> Self { let mut this = Self::new(); - - #[cfg(any(feature = "libssh", feature = "ssh2"))] - { - if let Some(x) = config.ssh.backend { - this.insert("ssh.backend".to_string(), x.to_string()); - } - - if let Some(x) = config.ssh.identity_file { - this.insert( - "ssh.identity_file".to_string(), - x.to_string_lossy().to_string(), - ); - } - } - + this.extend(config.options); this } } - -#[cfg(any(feature = "libssh", feature = "ssh2"))] -#[derive(Args, Debug, Default, Serialize, Deserialize)] -pub struct ClientConnectSshConfig { - /// Represents the backend - #[clap(name = "ssh-backend", long)] - pub backend: Option, - - /// Explicit identity file to use with ssh - #[clap(name = "ssh-identity-file", short = 'i', long)] - pub identity_file: Option, -} diff --git a/src/config/client/launch.rs b/src/config/client/launch.rs index 21a8864..42f048a 100644 --- a/src/config/client/launch.rs +++ b/src/config/client/launch.rs @@ -2,7 +2,6 @@ use crate::config::BindAddress; use clap::Args; use distant_core::Map; use serde::{Deserialize, Serialize}; -use std::path::PathBuf; #[derive(Args, Debug, Default, Serialize, Deserialize)] pub struct ClientLaunchConfig { @@ -10,9 +9,14 @@ pub struct ClientLaunchConfig { #[serde(flatten)] pub distant: ClientLaunchDistantConfig, - #[clap(flatten)] + /// Additional options to provide, typically forwarded to the handler within the manager + /// facilitating the launch of a distant server. Options are key-value pairs separated by + /// comma. + /// + /// E.g. `key="value",key2="value2"` + #[clap(long, default_value_t)] #[serde(flatten)] - pub ssh: ClientLaunchSshConfig, + pub options: Map, } impl From for ClientLaunchConfig { @@ -29,20 +33,7 @@ impl From for ClientLaunchConfig { .and_then(|x| x.parse::().ok()) .unwrap_or_default(), }, - ssh: ClientLaunchSshConfig { - bin: map.remove("ssh.bin"), - #[cfg(any(feature = "libssh", feature = "ssh2"))] - backend: map - .remove("ssh.backend") - .and_then(|x| x.parse::().ok()), - external: map - .remove("ssh.external") - .and_then(|x| x.parse::().ok()) - .unwrap_or_default(), - identity_file: map - .remove("ssh.identity_file") - .and_then(|x| x.parse::().ok()), - }, + options: map, } } } @@ -68,23 +59,7 @@ impl From for Map { config.distant.no_shell.to_string(), ); - if let Some(x) = config.ssh.bin { - this.insert("ssh.bin".to_string(), x); - } - - #[cfg(any(feature = "libssh", feature = "ssh2"))] - if let Some(x) = config.ssh.backend { - this.insert("ssh.backend".to_string(), x.to_string()); - } - - this.insert("ssh.external".to_string(), config.ssh.external.to_string()); - - if let Some(x) = config.ssh.identity_file { - this.insert( - "ssh.identity_file".to_string(), - x.to_string_lossy().to_string(), - ); - } + this.extend(config.options); this } @@ -120,25 +95,3 @@ pub struct ClientLaunchDistantConfig { #[clap(long)] pub no_shell: bool, } - -#[derive(Args, Debug, Default, Serialize, Deserialize)] -pub struct ClientLaunchSshConfig { - /// Path to ssh program on local machine to execute when using external ssh - #[clap(name = "ssh", long)] - pub bin: Option, - - /// If using native ssh integration, represents the backend - #[cfg(any(feature = "libssh", feature = "ssh2"))] - #[clap(name = "ssh-backend", long)] - pub backend: Option, - - /// If specified, will use the external ssh program to launch the server - /// instead of the native integration; does nothing if the ssh2 feature is - /// not enabled as there is no other option than external ssh - #[clap(name = "ssh-external", long)] - pub external: bool, - - /// Explicit identity file to use with ssh - #[clap(name = "ssh-identity-file", short = 'i', long)] - pub identity_file: Option, -} diff --git a/src/config/client/repl.rs b/src/config/client/repl.rs index f2f0482..a29e7d6 100644 --- a/src/config/client/repl.rs +++ b/src/config/client/repl.rs @@ -1,6 +1,7 @@ +use clap::Args; use serde::{Deserialize, Serialize}; -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Args, Debug, Default, Serialize, Deserialize)] pub struct ClientReplConfig { /// Represents the maximum time (in seconds) to wait for a network request before timing out pub timeout: Option,