use std::path::Path;
use crate::core::rclone::RcloneCommand as _;
use crate::core::rclone::command::CopyTo;
pub(crate) async fn push_one(
local_path: &Path,
destination_address: &str,
key: &str,
push_log_dir: &Path,
) -> Result<(), String> {
let bytes = std::fs::metadata(local_path)
.map(|meta| meta.len())
.unwrap_or(0);
let log_path = push_log_dir.join(format!("{}.jsonl", log_name_for(key)));
(CopyTo {
source: local_path.display().to_string(),
destination: format!("{destination_address}{key}"),
log_path,
job: "email-import",
step: "push",
emit_upload_metrics: true,
bytes,
})
.run()
.await
}
fn log_name_for(key: &str) -> String {
key.chars()
.map(|ch| match ch {
'/' | '\\' | ':' => '-',
other => other,
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn log_name_for_flattens_every_path_separator() {
assert_eq!(
log_name_for("a@b.com/inbox/1/attachments/a.pdf"),
"a@b.com-inbox-1-attachments-a.pdf"
);
assert_eq!(log_name_for("1.eml"), "1.eml");
}
#[tokio::test]
async fn push_one_copies_a_file_to_a_local_destination_path() {
if crate::core::rclone::check_available().await.is_err() {
eprintln!("skipping: rclone not found on PATH");
return;
}
let source_dir = tempfile::tempdir().unwrap();
let dest_dir = tempfile::tempdir().unwrap();
let local_path = source_dir.path().join("1.eml");
std::fs::write(&local_path, b"raw message bytes").unwrap();
let destination = format!("{}/", dest_dir.path().display());
push_one(
&local_path,
&destination,
"a@b.com/inbox/1.eml",
&source_dir.path().join("push-logs"),
)
.await
.unwrap();
assert_eq!(
std::fs::read(dest_dir.path().join("a@b.com/inbox/1.eml")).unwrap(),
b"raw message bytes"
);
}
}