rskit_storage/
transfer.rs1use rskit_errors::AppResult;
4
5use crate::{
6 FileSink, FileSource, ProgressCallback, UploadOptions, store::FileStore, store::StoredFile,
7};
8
9pub async fn copy_file(
11 source: &FileSource,
12 sink: &FileSink,
13 _on_progress: Option<ProgressCallback>,
14) -> AppResult<FileSource> {
15 let data = source.read_all().await?;
16 let mut writer = sink.writer().await?;
17 writer.write_all(&data).await?;
18 writer.finalize().await
19}
20
21pub async fn transfer(
23 from_store: &dyn FileStore,
24 from_key: &str,
25 to_store: &dyn FileStore,
26 to_key: &str,
27) -> AppResult<StoredFile> {
28 let source = from_store.download(from_key).await?;
29 let meta = from_store.head(from_key).await?;
30 to_store
31 .upload(
32 &source,
33 to_key,
34 UploadOptions::new().with_content_type(&meta.content_type),
35 )
36 .await
37}
38
39#[cfg(test)]
40mod tests {
41 use bytes::Bytes;
42
43 use super::*;
44 use crate::{FileStore, LocalStore, LocalStoreConfig};
45
46 #[tokio::test]
47 async fn copy_file_moves_source_bytes_to_each_sink_type() {
48 let source = FileSource::from_bytes(Bytes::from_static(b"copy-data"));
49
50 let memory = copy_file(&source, &FileSink::Memory, None).await.unwrap();
51 assert_eq!(
52 memory.read_all().await.unwrap(),
53 Bytes::from_static(b"copy-data")
54 );
55
56 let temp = copy_file(&source, &FileSink::Temp, None).await.unwrap();
57 assert_eq!(
58 temp.read_all().await.unwrap(),
59 Bytes::from_static(b"copy-data")
60 );
61
62 let dir = tempfile::tempdir().unwrap();
63 let output = dir.path().join("copied.bin");
64 let path = copy_file(&source, &FileSink::Path(output.clone()), None)
65 .await
66 .unwrap();
67 assert!(matches!(path, FileSource::Path(_)));
68 assert_eq!(tokio::fs::read(output).await.unwrap(), b"copy-data");
69 }
70
71 #[tokio::test]
72 async fn transfer_downloads_from_source_store_and_uploads_to_destination() {
73 let from_dir = tempfile::tempdir().unwrap();
74 let to_dir = tempfile::tempdir().unwrap();
75 let from_store = LocalStore::new(LocalStoreConfig {
76 root_dir: from_dir.path().to_path_buf(),
77 auto_create: false,
78 })
79 .unwrap();
80 let to_store = LocalStore::new(LocalStoreConfig {
81 root_dir: to_dir.path().to_path_buf(),
82 auto_create: false,
83 })
84 .unwrap();
85
86 from_store
87 .upload(
88 &FileSource::from_bytes(Bytes::from_static(b"transfer-data")),
89 "source.bin",
90 UploadOptions::new().with_content_type("application/custom"),
91 )
92 .await
93 .unwrap();
94
95 let stored = transfer(&from_store, "source.bin", &to_store, "nested/target.bin")
96 .await
97 .unwrap();
98
99 assert_eq!(stored.key, "nested/target.bin");
100 assert_eq!(stored.content_type, "application/octet-stream");
101 assert_eq!(
102 to_store
103 .download("nested/target.bin")
104 .await
105 .unwrap()
106 .read_all()
107 .await
108 .unwrap(),
109 Bytes::from_static(b"transfer-data")
110 );
111 }
112}