diff --git a/filed/Cargo.lock b/filed/Cargo.lock index 557b0a1..67bea6a 100644 --- a/filed/Cargo.lock +++ b/filed/Cargo.lock @@ -37,6 +37,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -375,6 +384,7 @@ dependencies = [ "num", "rand", "redis", + "regex", "serde", "serde_json", "sha2", @@ -941,7 +951,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ec3b11d443640ec35165ee8f6f0559f1c6f41878d70330fe9187012b5935f02" dependencies = [ - "aho-corasick", + "aho-corasick 0.7.20", "bumpalo", "hashbrown 0.13.2", "lazy_static", @@ -1078,6 +1088,35 @@ dependencies = [ "url", ] +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick 1.1.2", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick 1.1.2", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "rfc7239" version = "0.1.0" diff --git a/filed/Cargo.toml b/filed/Cargo.toml index e044e90..71a2624 100644 --- a/filed/Cargo.toml +++ b/filed/Cargo.toml @@ -19,6 +19,7 @@ log = "0.4.20" num = { version = "0.4.1", features = ["serde"] } rand = "0.8.5" redis = { version = "0.23.3", features = ["tokio", "tokio-comp"] } +regex = "1.10.2" serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.107" sha2 = "0.10.8" diff --git a/filed/src/config.rs b/filed/src/config.rs index dd198c6..80f76f7 100644 --- a/filed/src/config.rs +++ b/filed/src/config.rs @@ -1 +1,2 @@ -pub mod types; \ No newline at end of file +pub mod types; +pub mod resource; diff --git a/filed/src/config/resource.rs b/filed/src/config/resource.rs new file mode 100644 index 0000000..dd198c6 --- /dev/null +++ b/filed/src/config/resource.rs @@ -0,0 +1 @@ +pub mod types; \ No newline at end of file diff --git a/filed/src/config/resource/types.rs b/filed/src/config/resource/types.rs new file mode 100644 index 0000000..383c159 --- /dev/null +++ b/filed/src/config/resource/types.rs @@ -0,0 +1,80 @@ +use regex::Regex; +use serde::{Serialize, Deserialize}; +use std::{error::Error, fs, collections::HashMap, path::Path}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ResourceCollection(HashMap); + +impl ResourceCollection { + pub fn validate(self: &Self) -> Result<(), String> { + for (name, resource) in self.0.iter() { + resource.validate(Some(name.clone()))?; + } + Ok(()) + } + + pub fn init(self: &mut Self) -> Result<(), String> { + for (name, resource) in self.0.iter_mut() { + resource.init(Some(name.clone()))?; + } + Ok(()) + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Resource { + pub path: String, + pub mime: String, + cached_data: Option> +} + +impl Resource { + + pub fn init(self: &mut Self, name: Option) -> Result<(), String> { + if self.cached_data.is_none() { + self.read_to_cache().map_err(|x| + if let Some(name) = name { + format!("Error while initalizing resource {name}: {:?}", x) + } else { + format!("Error while initalizing unknown resource: {:?}", x) + } + )? + } + Ok(()) + } + + pub fn validate(self: &Self, name: Option) -> Result<(), String> { + // dont catch this panic + let re = Regex::new(r"^[a-z][a-z0-9_]*(\.[a-z0-9_]+)+[0-9a-z_]$").unwrap(); + + if let Some(name) = name.clone() { + if ! re.is_match(name.as_str()) { + return Err(format!("Invalid resource name: {name}")); + } + } + + let path = Path::new(&self.path); + if ! path.is_file() { + if let Some(name) = name { + return Err(format!("Resource {name} is not a file!")); + } else { + return Err(format!("A resource with path {} is not a file!", self.path)); + } + } + Ok(()) + } + + fn read_to_cache(self: &mut Self) -> Result<(), Box> { + let data = fs::read(self.path.clone())?; + self.cached_data = Some(data); + Ok(()) + } + + pub fn get(self: &mut Self) -> Result, Box> { + if let Some(cached) = self.cached_data.clone() { + Ok(cached) + } else { + Ok(fs::read(self.path.clone())?) + } + } +} \ No newline at end of file diff --git a/filed/src/config/types.rs b/filed/src/config/types.rs index 6905dd7..feffa1a 100644 --- a/filed/src/config/types.rs +++ b/filed/src/config/types.rs @@ -3,6 +3,8 @@ use std::{error::Error, fs, path::Path}; use crate::env::Env; +use super::resource; + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct FilesPolicy { /// Whether the uploads are enabled @@ -167,7 +169,8 @@ impl APISettings { pub struct Config { pub files: FilesPolicy, pub brand: Branding, - pub api: APISettings + pub api: APISettings, + pub resources: Option } impl Config { @@ -176,14 +179,26 @@ impl Config { self.files.validate()?; self.brand.validate()?; self.api .validate()?; + if let Some(resources) = self.resources.clone() { + resources.validate()?; + } Ok(()) } + pub fn init(self: &mut Self) -> Result<(), String> { + if let Some(ref mut resources) = self.resources { + resources.init()?; + } + Ok(()) + } + pub fn load(env: Env) -> Result> { let raw = fs::read_to_string(env.confpath.clone())?; - let conf: Config = toml::from_str(&raw)?; + let mut conf: Config = toml::from_str(&raw)?; conf.validate()?; + conf.init()?; + Ok(conf) } } \ No newline at end of file