Ver Fonte

[7] Updated temporary file paths

Temporary file path generation on the backend was updated.
at-robins há 7 meses atrás
pai
commit
5f26888c17

+ 206 - 19
backend/Cargo.lock

@@ -79,7 +79,7 @@ dependencies = [
  "tokio",
  "tokio-util",
  "tracing",
- "zstd",
+ "zstd 0.12.3+zstd.1.5.2",
 ]
 
 [[package]]
@@ -271,6 +271,17 @@ version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
+[[package]]
+name = "aes"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
+dependencies = [
+ "cfg-if",
+ "cipher",
+ "cpufeatures",
+]
+
 [[package]]
 name = "ahash"
 version = "0.7.6"
@@ -392,6 +403,8 @@ dependencies = [
  "twox-hash",
  "uuid",
  "walkdir",
+ "zip",
+ "zip-extensions",
 ]
 
 [[package]]
@@ -400,6 +413,12 @@ version = "0.21.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
 
+[[package]]
+name = "base64ct"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
+
 [[package]]
 name = "bitflags"
 version = "1.3.2"
@@ -442,6 +461,12 @@ version = "3.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8"
 
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
 [[package]]
 name = "bytes"
 version = "1.1.0"
@@ -457,6 +482,27 @@ dependencies = [
  "bytes",
 ]
 
+[[package]]
+name = "bzip2"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
+dependencies = [
+ "bzip2-sys",
+ "libc",
+]
+
+[[package]]
+name = "bzip2-sys"
+version = "0.1.11+1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+]
+
 [[package]]
 name = "cc"
 version = "1.0.72"
@@ -488,6 +534,16 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "cipher"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common",
+ "inout",
+]
+
 [[package]]
 name = "codespan-reporting"
 version = "0.11.1"
@@ -498,6 +554,12 @@ dependencies = [
  "unicode-width",
 ]
 
+[[package]]
+name = "constant_time_eq"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
+
 [[package]]
 name = "convert_case"
 version = "0.4.0"
@@ -539,11 +601,20 @@ dependencies = [
  "cfg-if",
 ]
 
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
+dependencies = [
+ "cfg-if",
+]
+
 [[package]]
 name = "crypto-common"
-version = "0.1.3"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
 dependencies = [
  "generic-array",
  "typenum",
@@ -695,6 +766,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
 dependencies = [
  "block-buffer",
  "crypto-common",
+ "subtle",
 ]
 
 [[package]]
@@ -772,13 +844,11 @@ checksum = "2c5f6c2c942da57e2aaaa84b8a521489486f14e75e7fa91dab70aba913975f98"
 
 [[package]]
 name = "flate2"
-version = "1.0.22"
+version = "1.0.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f"
+checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
 dependencies = [
- "cfg-if",
  "crc32fast",
- "libc",
  "miniz_oxide",
 ]
 
@@ -985,6 +1055,15 @@ version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
 
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest",
+]
+
 [[package]]
 name = "html5ever"
 version = "0.26.0"
@@ -1085,6 +1164,15 @@ dependencies = [
  "hashbrown",
 ]
 
+[[package]]
+name = "inout"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
+dependencies = [
+ "generic-array",
+]
+
 [[package]]
 name = "instant"
 version = "0.1.12"
@@ -1297,12 +1385,11 @@ dependencies = [
 
 [[package]]
 name = "miniz_oxide"
-version = "0.4.4"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
+checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
 dependencies = [
  "adler",
- "autocfg",
 ]
 
 [[package]]
@@ -1459,12 +1546,35 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "944553dd59c802559559161f9816429058b869003836120e262e8caec061b7ae"
 
+[[package]]
+name = "password-hash"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
+dependencies = [
+ "base64ct",
+ "rand_core",
+ "subtle",
+]
+
 [[package]]
 name = "paste"
 version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc"
 
+[[package]]
+name = "pbkdf2"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
+dependencies = [
+ "digest",
+ "hmac",
+ "password-hash",
+ "sha2",
+]
+
 [[package]]
 name = "percent-encoding"
 version = "2.1.0"
@@ -1642,9 +1752,21 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.8.3"
+version = "1.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390"
+checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -1653,9 +1775,9 @@ dependencies = [
 
 [[package]]
 name = "regex-syntax"
-version = "0.7.2"
+version = "0.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
+checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
 
 [[package]]
 name = "rustc_version"
@@ -1697,9 +1819,9 @@ dependencies = [
 
 [[package]]
 name = "sanitize-filename"
-version = "0.4.0"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08c502bdb638f1396509467cb0580ef3b29aa2a45c5d43e5d84928241280296c"
+checksum = "2ed72fbaf78e6f2d41744923916966c4fbe3d7c74e3037a8ee482f1115572603"
 dependencies = [
  "lazy_static",
  "regex",
@@ -1820,6 +1942,17 @@ dependencies = [
  "digest",
 ]
 
+[[package]]
+name = "sha2"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
 [[package]]
 name = "signal-hook-registry"
 version = "1.4.0"
@@ -1895,6 +2028,12 @@ version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
 
+[[package]]
+name = "subtle"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
+
 [[package]]
 name = "syn"
 version = "1.0.99"
@@ -2152,9 +2291,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
 
 [[package]]
 name = "uuid"
-version = "1.3.3"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2"
+checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
 dependencies = [
  "atomic",
  "getrandom",
@@ -2464,13 +2603,61 @@ version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
 
+[[package]]
+name = "zip"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
+dependencies = [
+ "aes",
+ "byteorder",
+ "bzip2",
+ "constant_time_eq",
+ "crc32fast",
+ "crossbeam-utils",
+ "flate2",
+ "hmac",
+ "pbkdf2",
+ "sha1",
+ "time 0.3.9",
+ "zstd 0.11.2+zstd.1.5.2",
+]
+
+[[package]]
+name = "zip-extensions"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cecf62554c4ff96bce01a7ef123d160c3ffe9180638820f8b4d545c65b221b8c"
+dependencies = [
+ "zip",
+]
+
+[[package]]
+name = "zstd"
+version = "0.11.2+zstd.1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4"
+dependencies = [
+ "zstd-safe 5.0.2+zstd.1.5.2",
+]
+
 [[package]]
 name = "zstd"
 version = "0.12.3+zstd.1.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806"
 dependencies = [
- "zstd-safe",
+ "zstd-safe 6.0.5+zstd.1.5.4",
+]
+
+[[package]]
+name = "zstd-safe"
+version = "5.0.2+zstd.1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db"
+dependencies = [
+ "libc",
+ "zstd-sys",
 ]
 
 [[package]]

+ 4 - 2
backend/Cargo.toml

@@ -23,12 +23,14 @@ openssl = "0.10.52"
 parking_lot = "0.12.1"
 rand = "0.8.5"
 regex = "1.8.1"
-sanitize-filename = "0.4.0"
+sanitize-filename = "0.5.0"
 serde = { version = "1.0.163", features = ["derive"] }
 serde_json = "1.0.96"
 twox-hash = "1.6.3"
-uuid = { version = "1.3.3", features = ["serde", "v1", "v4"] }
+uuid = { version = "1.5.0", features = ["serde", "v1", "v4"] }
 walkdir = "2.3.3"
+zip = "0.6.6"
+zip-extensions = "0.6.2"
 
 [dev-dependencies]
 mime = "0.3.17"

+ 58 - 9
backend/src/application/config.rs

@@ -4,8 +4,12 @@
 const UUID_CONTEXT: Context = Context::new(0);
 /// The node ID for UUID generation.
 const UUID_NODE_ID: &[u8; 6] = &[12, 221, 33, 14, 35, 16];
-/// The context path where temporary files are stored.
-const PATH_FILES_TEMPORARY: &str = "tmp/files";
+/// The context path where temporary data are stored.
+const PATH_TEMPORARY: &str = "tmp";
+/// The context path where temporary upload files are stored.
+const PATH_TEMPORARY_UPLOAD: &str = "upload";
+/// The context path where temporary download files are stored.
+const PATH_TEMPORARY_DOWNLOAD: &str = "download";
 /// The context path where data related to specific experiments or samples is stored.
 const PATH_FILES_EXPERIMENTS: &str = "experiments";
 /// The file inside each pipeline folder defining the pipeline.
@@ -117,10 +121,33 @@ impl Configuration {
             .map_err(|error| SeqError::from_var_error(error, environment_variable))
     }
 
-    /// The context path where temporary files are stored.
-    pub fn temporary_file_path(&self) -> PathBuf {
-        let mut path: PathBuf = self.context_folder().clone();
-        path.push(PATH_FILES_TEMPORARY);
+    /// The context path where temporary data are stored.
+    pub fn temporary_path(&self) -> PathBuf {
+        self.context_folder().join(PATH_TEMPORARY)
+    }
+
+    /// The context path where temporary upload files are stored.
+    pub fn temporary_upload_path(&self) -> PathBuf {
+        let mut path: PathBuf = self.temporary_path();
+        path.push(PATH_TEMPORARY_UPLOAD);
+        path
+    }
+
+    /// The context path where temporary download files are stored.
+    pub fn temporary_download_path(&self) -> PathBuf {
+        let mut path: PathBuf = self.temporary_path();
+        path.push(PATH_TEMPORARY_DOWNLOAD);
+        path
+    }
+
+    /// The context path where a specific temporary download file is stored.
+    ///
+    /// # Parameters
+    ///
+    /// * `file_id` - the ID of the temporary file
+    pub fn temporary_download_file_path<T: Into<String>>(&self, file_id: T) -> PathBuf {
+        let mut path: PathBuf = self.temporary_download_path();
+        path.push(file_id.into());
         path
     }
 
@@ -359,10 +386,32 @@ mod tests {
     }
 
     #[test]
-    fn test_temporary_file_path() {
+    fn test_temporary_path() {
+        let config = Configuration::new("", "", "", "", "./application/context", "");
+        let path: PathBuf = "./application/context/tmp".into();
+        assert_eq!(config.temporary_path(), path);
+    }
+
+    #[test]
+    fn test_temporary_upload_path() {
+        let config = Configuration::new("", "", "", "", "./application/context", "");
+        let path: PathBuf = "./application/context/tmp/upload".into();
+        assert_eq!(config.temporary_upload_path(), path);
+    }
+
+    #[test]
+    fn test_temporary_download_path() {
+        let config = Configuration::new("", "", "", "", "./application/context", "");
+        let path: PathBuf = "./application/context/tmp/download".into();
+        assert_eq!(config.temporary_download_path(), path);
+    }
+
+    #[test]
+    fn test_temporary_download_file_path() {
         let config = Configuration::new("", "", "", "", "./application/context", "");
-        let path: PathBuf = "./application/context/tmp/files".into();
-        assert_eq!(config.temporary_file_path(), path);
+        let id = "01234567-89ab-cdef-0123-456789abcdef";
+        let path: PathBuf = format!("./application/context/tmp/download/{}", id).into();
+        assert_eq!(config.temporary_download_file_path(id), path);
     }
 
     #[test]

+ 1 - 0
backend/src/model/internal.rs

@@ -1,2 +1,3 @@
+pub mod archive;
 pub mod pipeline_blueprint;
 pub mod step;

+ 71 - 0
backend/src/model/internal/archive.rs

@@ -0,0 +1,71 @@
+use std::path::PathBuf;
+
+use getset::Getters;
+use serde::{Deserialize, Serialize};
+
+/// The file extension of archive metadata files.
+const ARCHIVE_METADATA_FILE_EXTENSION: &str = "meta";
+
+/// The metadata of a downloadable archive.
+#[derive(Debug, Clone, Getters, PartialEq, Serialize, Deserialize)]
+pub struct ArchiveMetadata {
+    /// The file name of the archive.
+    #[getset(get = "pub")]
+    file_name: String,
+}
+
+impl ArchiveMetadata {
+    /// Creates a new archive metadata struct.
+    ///
+    /// # Parameters
+    ///
+    /// * `file_name` - the name of the archive file
+    pub fn new<T: AsRef<str>>(file_name: T) -> Self {
+        Self {
+            file_name: sanitize_filename::sanitize(file_name),
+        }
+    }
+
+    /// Returns the archive metadata path for the specified archive file.
+    ///
+    /// # Parameters
+    ///
+    /// * `archive_path` - the path of the archive file
+    pub fn metadata_path<T: Into<PathBuf>>(archive_path: T) -> PathBuf {
+        let mut archive_meta_path: PathBuf = archive_path.into();
+        archive_meta_path.set_extension(ARCHIVE_METADATA_FILE_EXTENSION);
+        archive_meta_path
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use crate::application::config::Configuration;
+
+    use super::*;
+
+    #[test]
+    fn test_archive_metadata_file_name() {
+        let archive_name = "some_name";
+        let metadata = ArchiveMetadata::new(archive_name);
+        assert_eq!(metadata.file_name(), archive_name);
+    }
+
+    #[test]
+    fn test_archive_metadata_file_name_invalid_characters() {
+        let archive_name = "some/*?name";
+        let metadata = ArchiveMetadata::new(archive_name);
+        assert_eq!(metadata.file_name(), "somename");
+    }
+
+    #[test]
+    fn test_metadata_path() {
+        let config = Configuration::new("", "", "", "", "./application/context", "");
+        let archive_id = "01234567-89ab-cdef-0123-456789abcdef";
+        let archive_path = config.temporary_download_file_path(archive_id);
+        let expected_meta_path: PathBuf =
+            "./application/context/tmp/download/01234567-89ab-cdef-0123-456789abcdef.meta".into();
+        assert_eq!(ArchiveMetadata::metadata_path(archive_path), expected_meta_path);
+    }
+}

+ 3 - 3
backend/src/service/multipart_service.rs

@@ -103,7 +103,7 @@ pub async fn parse_multipart_file<T: UploadForm, P: AsRef<Path>>(
 /// * `uuid` - the UUID of the temporary file
 /// * `app_config` - the app [`Configuration`]
 pub fn delete_temporary_file(uuid: Uuid, app_config: Arc<Configuration>) -> Result<(), SeqError> {
-    let mut file_path: PathBuf = app_config.temporary_file_path();
+    let mut file_path: PathBuf = app_config.temporary_upload_path();
     file_path.push(uuid.to_string());
     if file_path.exists() {
         std::fs::remove_file(&file_path)?;
@@ -125,7 +125,7 @@ pub fn create_temporary_file(app_config: Arc<Configuration>) -> Result<(PathBuf,
     let uuid = Configuration::generate_uuid();
 
     // Create the temporary folder.
-    let mut temp_file_path: PathBuf = app_config.temporary_file_path();
+    let mut temp_file_path: PathBuf = app_config.temporary_upload_path();
     std::fs::create_dir_all(&temp_file_path)?;
     temp_file_path.push(uuid.to_string());
     Ok((temp_file_path, uuid))
@@ -153,7 +153,7 @@ mod tests {
         let app_config: Arc<Configuration> = Arc::new((&context).into());
         let (path, id) = create_temporary_file(Arc::clone(&app_config)).unwrap();
         assert!(path.ends_with(id.to_string()));
-        assert!(path.starts_with(app_config.temporary_file_path()));
+        assert!(path.starts_with(app_config.temporary_upload_path()));
         assert!(!path.exists());
     }