use ftp::native_tls::TlsConnector; use ftp::FtpStream; use std::path::PathBuf; use crate::config::RemoteBackupConfig; use crate::error; use crate::error::AlbatrossError; use crate::remote::{PathLocation, RemoteBackupSite}; /// FTPS Remote Site pub struct FTPSBackup { /// FTP command stream stream: FtpStream, /// Remote target directory target_dir: PathBuf, /// Number of backups to keep backups_to_keep: usize, } impl FTPSBackup { /// New FTPSBackup pub fn new(config: &RemoteBackupConfig) -> error::Result { let ftps_config = config .ftps .as_ref() .ok_or_else(|| AlbatrossError::RemoteConfigError("FTPS".to_string()))?; let ctx = TlsConnector::new().unwrap(); let (ftp_stream, _) = FtpStream::connect(&ftps_config.server_addr)?; let domain = ftps_config .domain .as_ref() .map_or_else(|| "".to_string(), |s| s.clone()); let mut ftp_stream = ftp_stream.into_secure(ctx, domain.as_str())?; ftp_stream.login(&ftps_config.username, &ftps_config.password)?; Ok(Self { stream: ftp_stream, target_dir: ftps_config.remote_dir.clone(), backups_to_keep: config.backups_to_keep as usize, }) } } impl Drop for FTPSBackup { fn drop(&mut self) { self.stream.quit().ok(); } } impl RemoteBackupSite for FTPSBackup { type FileType = PathLocation; fn backup_to_remote(&mut self, file: PathBuf) -> error::Result<()> { let mut local_file = std::fs::File::open(&file)?; let location = self.target_dir.join(file); self.stream .put(location.to_str().unwrap(), &mut local_file)?; Ok(()) } fn get_backups(&mut self) -> error::Result> { let files = self.stream.list(Some(self.target_dir.to_str().unwrap()))?; Ok(files .into_iter() .filter_map(|file| Self::FileType::new(PathBuf::from(file))) .collect()) } fn remove_backup(&mut self, backup: Self::FileType) -> error::Result<()> { Ok(self.stream.rm(backup.location.to_str().unwrap())?) } fn backups_to_keep(&self) -> usize { self.backups_to_keep } }