use crate::backup::get_time_from_file_name; use crate::config::RemoteBackupConfig; use crate::error::{AlbatrossError, Result}; use ssh2::Session; use std::net::TcpStream; use std::path::PathBuf; /// Open an SSH session fn open_ssh_session(remote_config: &RemoteBackupConfig) -> Result { let tcp = TcpStream::connect(&remote_config.sftp_server_addr)?; let mut sess = Session::new()?; sess.set_tcp_stream(tcp); sess.handshake().unwrap(); if let Some(password) = &remote_config.password { sess.userauth_password(&remote_config.username, password)?; } else if let Some(key) = &remote_config.private_key { let public_key = remote_config.public_key.as_deref(); sess.userauth_pubkey_file(&remote_config.username, public_key, key, None)?; } else { return Err(AlbatrossError::NoSSHAuth); } Ok(sess) } /// Handle remote backup of a file pub fn remote_backup(file: PathBuf, remote_config: &RemoteBackupConfig) -> Result<()> { let sess = open_ssh_session(remote_config)?; let remote_path = remote_config.remote_dir.join(file.file_name().unwrap()); let mut local_file = std::fs::File::open(&file)?; let sftp = sess.sftp()?; let mut remote_file = sftp.create(&remote_path)?; std::io::copy(&mut local_file, &mut remote_file)?; let files = sftp.readdir(&remote_config.remote_dir)?; let mut backups: Vec = files .into_iter() .map(|(file, _)| file) .filter(|file| { if let Some(ext) = file.extension() { ext == "gz" } else { false } }) .collect(); backups.sort_by(|file_a, file_b| { let time_a = get_time_from_file_name(file_a.file_name().unwrap().to_str().unwrap()).unwrap(); let time_b = get_time_from_file_name(file_b.file_name().unwrap().to_str().unwrap()).unwrap(); time_b.cmp(&time_a) }); if backups.len() > remote_config.backups_to_keep as usize { for _ in 0..(backups.len() - remote_config.backups_to_keep as usize) { if let Some(backup_path) = backups.pop() { sftp.unlink(&*backup_path)?; } } } Ok(()) }