Albatross/src/remote/sftp.rs

79 lines
2.2 KiB
Rust

use std::net::TcpStream;
use std::path::PathBuf;
use ssh2::Session;
use crate::error;
use crate::error::AlbatrossError;
use crate::remote::{PathLocation, RemoteBackupSite};
use crate::config::remote::SFTPConfig;
/// SFTP Remote Site
pub struct SFTPBackup {
/// SSH Session
session: Session,
/// Remote target directory
target_dir: PathBuf,
/// Number of backups to keep
backups_to_keep: usize,
}
impl SFTPBackup {
/// New SFTPBackup
pub fn new(config: &SFTPConfig, backups_to_keep: usize) -> error::Result<Self> {
let tcp = TcpStream::connect(&config.server_addr)?;
let mut sess = Session::new()?;
sess.set_tcp_stream(tcp);
sess.handshake().unwrap();
if let Some(password) = &config.password {
sess.userauth_password(&config.username, password)?;
} else if let Some(key) = &config.private_key {
let public_key = config.public_key.as_deref();
sess.userauth_pubkey_file(&config.username, public_key, key, None)?;
} else {
return Err(AlbatrossError::NoSSHAuth);
}
Ok(Self {
session: sess,
target_dir: config.remote_dir.clone(),
backups_to_keep,
})
}
}
impl RemoteBackupSite for SFTPBackup {
type FileType = PathLocation;
fn backup_to_remote(&mut self, file: PathBuf) -> error::Result<()> {
let remote_path = self.target_dir.join(file.file_name().unwrap());
let mut local_file = std::fs::File::open(&file)?;
let sftp = self.session.sftp()?;
let mut remote_file = sftp.create(&remote_path)?;
std::io::copy(&mut local_file, &mut remote_file)?;
Ok(())
}
fn get_backups(&mut self) -> error::Result<Vec<Self::FileType>> {
let files = self.session.sftp()?.readdir(&self.target_dir)?;
Ok(files
.into_iter()
.filter_map(|(file, _)| Self::FileType::new(file))
.collect())
}
fn remove_backup(&mut self, backup: Self::FileType) -> error::Result<()> {
Ok(self.session.sftp()?.unlink(&*backup.location)?)
}
fn backups_to_keep(&self) -> usize {
self.backups_to_keep
}
}