use crate::protocol::common::{ReceivingStream, SendReceivePair, SendingStream};
use crate::protocol::control::Compatibility;
use crate::protocol::session::{
Command, CommandParam, Get2Args, GetArgs, ListArgs, Put2Args, PutArgs,
};
use crate::Parameters;
use crate::client::CopyJobSpec;
use crate::session::handler::UI;
use super::SessionCommandImpl;
use super::handler::{
CreateDirectoryHandler, GetHandler, ListingHandler, PutHandler, SessionCommand,
SetMetadataHandler,
};
pub(crate) struct SpanInfo {
pub name: &'static str,
pub primary_arg: String,
}
#[derive(Debug, Copy, Clone)]
pub(crate) enum TransferPhase {
Pre,
Transfer,
Post,
}
pub(crate) fn client_sender<'a, S: SendingStream + 'static, R: ReceivingStream + 'static>(
stream: SendReceivePair<S, R>,
copy_spec: &CopyJobSpec,
phase: TransferPhase,
compat: Compatibility,
params: &Parameters,
ui: Option<UI>,
config: &'a crate::config::Configuration,
) -> (Box<dyn SessionCommandImpl + 'a>, SpanInfo) {
macro_rules! xreturn {
($cmd:expr, $name:expr, $args:expr, $primary_arg:expr) => {
(
SessionCommand::boxed(stream, $cmd, $args, compat, config, ui),
SpanInfo {
name: $name,
primary_arg: $primary_arg,
},
)
};
}
let src = ©_spec.source.filename;
let dest = ©_spec.destination.filename;
match phase {
TransferPhase::Pre => {
let path = copy_spec.source.filename.clone();
let mut options = vec![];
if params.recurse {
options.push(CommandParam::Recurse.into());
}
let args = Some(ListArgs {
path: path.clone(),
options,
});
xreturn!(ListingHandler, "LIST", args, path)
}
TransferPhase::Transfer => {
if copy_spec.source.user_at_host.is_some() {
let mut args = Get2Args::default();
args.filename.clone_from(©_spec.source.filename);
if copy_spec.preserve {
args.options.push(CommandParam::PreserveMetadata.into());
}
xreturn!(GetHandler, "GETx", Some(args), src.clone())
} else if copy_spec.directory {
xreturn!(CreateDirectoryHandler, "MKDIR", None, dest.clone())
} else {
xreturn!(PutHandler, "PUT", None, src.clone())
}
}
TransferPhase::Post => {
xreturn!(SetMetadataHandler, "SETMETA", None, dest.clone())
}
}
}
pub(crate) fn command_handler<'a, S: SendingStream + 'static, R: ReceivingStream + 'static>(
stream: SendReceivePair<S, R>,
command: Command,
compat: Compatibility,
config: &'a crate::config::Configuration,
) -> (Box<dyn SessionCommandImpl + 'a>, SpanInfo) {
macro_rules! xreturn {
($cmd:expr, $name:expr, $args:expr, $primary_arg:expr) => {
(
SessionCommand::boxed(stream, $cmd, $args, compat, config, None),
SpanInfo {
name: $name,
primary_arg: $primary_arg,
},
)
};
}
let (handler, span_info): (Box<dyn SessionCommandImpl>, SpanInfo) = match command {
Command::Get(GetArgs { filename }) => xreturn!(
GetHandler,
"GET",
Some(Get2Args {
filename: filename.clone(),
options: vec![],
}),
filename.clone()
),
Command::Get2(args) => {
let filename = args.filename.clone();
xreturn!(GetHandler, "GET2", Some(args), filename)
}
Command::Put(PutArgs { filename }) => xreturn!(
PutHandler,
"PUT",
Some(Put2Args {
filename: filename.clone(),
options: vec![],
}),
filename.clone()
),
Command::Put2(args) => {
let filename = args.filename.clone();
xreturn!(PutHandler, "PUT2", Some(args), filename)
}
Command::CreateDirectory(args) => {
let dir_name = args.dir_name.clone();
xreturn!(CreateDirectoryHandler, "MKDIR", Some(args), dir_name)
}
Command::SetMetadata(args) => {
let path = args.path.clone();
xreturn!(SetMetadataHandler, "SETMETA", Some(args), path)
}
Command::List(args) => {
let path = args.path.clone();
xreturn!(ListingHandler, "LS", Some(args), path)
}
};
(handler, span_info)
}