use std::path::{Path, PathBuf};
use tokio::{fs::File, io::{AsyncReadExt, AsyncWriteExt}};
use crate::sftp::{sftp, sftp_authentication::SftpAuthentication, sftp_auth_basic::SftpAuthBasic, sftp_auth_key::SftpAuthKey};
pub struct SftpSender {
host: String,
remote_dir: PathBuf,
authentication: SftpAuthentication,
}
impl SftpSender {
pub fn new<T: AsRef<str>>(host: T) -> Self {
SftpSender {
host: host.as_ref().to_string(),
remote_dir: PathBuf::from("/"),
authentication: SftpAuthentication::new(),
}
}
pub fn auth_basic<T: AsRef<str>>(mut self, user: T, password: T) -> Self {
self.authentication.basic = Some(SftpAuthBasic {
user: user.as_ref().to_string(),
password: password.as_ref().to_string()
});
self
}
pub fn auth_key<T: AsRef<str>>(mut self, user: T, key_path: T, passphrase: Option<String>) -> Self {
self.authentication.key = Some(SftpAuthKey {
user: user.as_ref().to_string(),
key_path: PathBuf::from(key_path.as_ref()),
passphrase
});
self
}
pub fn remote_dir<T: AsRef<Path>>(mut self, remote_dir: T) -> Self {
self.remote_dir = remote_dir.as_ref().to_path_buf();
self
}
pub async fn send_file<T: AsRef<Path>>(self, file_path: T, file_name: Option<String>) -> anyhow::Result<()> {
let sftp = sftp::connect_and_authenticate(&self.host, &self.authentication).await?;
let file_name = match file_name {
Some(name) => name,
None => file_path.as_ref().file_name().unwrap().to_string_lossy().to_string(),
};
let remote_file_path = self.remote_dir.join(file_name);
let mut remote_file = sftp.create(remote_file_path.to_str().unwrap()).await?;
let mut source_file = File::open(file_path.as_ref()).await?;
tracing::debug!("uploading {:?} to {:?}", file_path.as_ref(), &remote_file_path);
let mut buffer = vec![0u8; 1024];
loop {
let bytes = source_file.read(&mut buffer).await?;
if bytes == 0 {
break;
}
remote_file.write_all(&buffer[..bytes]).await?;
}
tracing::debug!("upload complete");
Ok(())
}
pub async fn send_bytes<S: AsRef<str>>(self, bytes: &[u8], file_name: S) -> anyhow::Result<()> {
let sftp = sftp::connect_and_authenticate(&self.host, &self.authentication).await?;
let remote_file_path = self.remote_dir.join(file_name.as_ref());
let mut remote_file = sftp.create(remote_file_path.to_str().unwrap()).await?;
tracing::debug!("uploading bytes to {:?}", &remote_file_path);
remote_file.write_all(&bytes).await?;
tracing::debug!("upload complete");
Ok(())
}
}