use anyhow::Result;
use std::path::Path;
use std::time::Instant;
use crate::path::SyncPath;
use crate::ssh::config::SshConfig;
use crate::streaming::StreamingSync;
use crate::sync::SyncStats;
use crate::transport::server::ServerSession;
pub async fn sync_push(source: &Path, dest: &SyncPath, delete: bool, compress: bool) -> Result<SyncStats> {
let session = match dest {
SyncPath::Remote { host, user, .. } => {
let config = if let Some(user) = user {
SshConfig { hostname: host.clone(), user: user.clone(), ..Default::default() }
} else {
crate::ssh::config::parse_ssh_config(host)?
};
ServerSession::connect_ssh(&config, dest.path()).await?
}
SyncPath::Local { path, .. } => ServerSession::connect_local(path).await?,
SyncPath::S3 { .. } | SyncPath::Gcs { .. } => {
anyhow::bail!("Cloud storage paths not supported in server mode")
}
};
let (mut stdin, mut stdout) = session.split();
let sync = StreamingSync::new(source.to_path_buf(), dest.path().to_path_buf(), delete, compress);
let stats = sync.push(&mut stdout, &mut stdin).await?;
Ok(make_sync_stats(stats))
}
pub async fn sync_pull(source: &SyncPath, dest: &Path, delete: bool, compress: bool) -> Result<SyncStats> {
let session = match source {
SyncPath::Remote { host, user, .. } => {
let config = if let Some(user) = user {
SshConfig { hostname: host.clone(), user: user.clone(), ..Default::default() }
} else {
crate::ssh::config::parse_ssh_config(host)?
};
ServerSession::connect_ssh(&config, source.path()).await?
}
SyncPath::Local { path, .. } => ServerSession::connect_local(path).await?,
SyncPath::S3 { .. } | SyncPath::Gcs { .. } => {
anyhow::bail!("Cloud storage paths not supported in server mode")
}
};
let (mut stdin, mut stdout) = session.split();
let sync = StreamingSync::new(dest.to_path_buf(), source.path().to_path_buf(), delete, compress);
let stats = sync.pull(&mut stdout, &mut stdin).await?;
Ok(make_sync_stats(stats))
}
fn make_sync_stats(stats: crate::streaming::channel::SyncStats) -> SyncStats {
SyncStats {
files_scanned: stats.files_ok,
files_created: stats.files_ok,
files_updated: 0,
files_deleted: stats.deleted as usize,
files_skipped: 0,
bytes_transferred: stats.bytes_transferred,
files_delta_synced: stats.delta_files as usize,
delta_bytes_saved: stats.delta_bytes_saved,
files_compressed: 0,
compression_bytes_saved: 0,
files_verified: 0,
verification_failures: 0,
duration: Instant::now().elapsed(),
bytes_would_add: 0,
bytes_would_change: 0,
bytes_would_delete: 0,
dirs_created: stats.dirs_created,
symlinks_created: stats.symlinks_created,
errors: vec![],
}
}