84 lines
2.4 KiB
Rust
84 lines
2.4 KiB
Rust
use std::net::TcpStream;
|
|
use std::path::PathBuf;
|
|
|
|
use ssh2::Session;
|
|
|
|
use crate::config::RemoteBackupConfig;
|
|
use crate::error;
|
|
use crate::error::AlbatrossError;
|
|
use crate::remote::{PathLocation, RemoteBackupSite};
|
|
|
|
/// 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: &RemoteBackupConfig) -> error::Result<Self> {
|
|
let sftp_config = config
|
|
.sftp
|
|
.as_ref()
|
|
.ok_or_else(|| AlbatrossError::RemoteConfigError("SFTP".to_string()))?;
|
|
|
|
let tcp = TcpStream::connect(&sftp_config.server_addr)?;
|
|
let mut sess = Session::new()?;
|
|
sess.set_tcp_stream(tcp);
|
|
sess.handshake().unwrap();
|
|
|
|
if let Some(password) = &sftp_config.password {
|
|
sess.userauth_password(&sftp_config.username, password)?;
|
|
} else if let Some(key) = &sftp_config.private_key {
|
|
let public_key = sftp_config.public_key.as_deref();
|
|
sess.userauth_pubkey_file(&sftp_config.username, public_key, key, None)?;
|
|
} else {
|
|
return Err(AlbatrossError::NoSSHAuth);
|
|
}
|
|
|
|
Ok(Self {
|
|
session: sess,
|
|
target_dir: sftp_config.remote_dir.clone(),
|
|
backups_to_keep: config.backups_to_keep as usize,
|
|
})
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|