diff --git a/filed/src/files/lookup.rs b/filed/src/files/lookup.rs index c5270b7..3e67233 100644 --- a/filed/src/files/lookup.rs +++ b/filed/src/files/lookup.rs @@ -1,7 +1,7 @@ use std::error::Error; -use redis::{Client, Commands}; +use redis::{Client, Commands, AsyncCommands, Connection}; use crate::env::Env; @@ -22,6 +22,60 @@ impl FileManager { pub fn new(conn: Client, env: Env) -> FileManager { FileManager { conn, env } } + + async fn find_all(self: &Self, predicate: String) -> Result, Box> { + let mut conn = self.conn.get_async_connection().await?; + let found: Vec = conn.keys(predicate).await?; + let serialized: Vec = + found.iter() + .map(|x| { + let result = serde_json::from_str(&x); + match result { + Ok(x) => Some(x), + Err(err) => { + log::error!("Error while serializing {x}: {:?}", err); + None + } + } + }) + .filter(|x| x.is_some()) + .map(|x| x.unwrap()) + .collect(); + Ok(serialized) + } + + /// Filter options + /// ``` + /// names: Find files with names + /// hash: Find files without names + /// ``` + /// + /// If both of those are false, this function will be optimized out + pub async fn get_all(self: &Self, names: bool, hash: bool) -> Result, Box> { + if (!names) && (!hash) { + return Ok(vec![]); + } + + let mut conn = self.conn.get_async_connection().await?; + let mut out = vec![]; + + if names { + self.find_all(format!("{}-name-*", self.env.redis.prefix)) + .await? + .iter() + .for_each(|x| out.push(x.clone())); + } + + if hash { + self.find_all(format!("{}-hash-*", self.env.redis.prefix)) + .await? + .iter() + .for_each(|x| out.push(x.clone())); + } + + Ok(out) + } + fn find(self: &Self, key: String) -> Result, Box> { let mut conn = self.conn.get_connection()?; diff --git a/filed/src/web/api.rs b/filed/src/web/api.rs index 5edfff9..3b3c255 100644 --- a/filed/src/web/api.rs +++ b/filed/src/web/api.rs @@ -6,6 +6,7 @@ use self::get_all::get_all_f; use super::state::SharedState; mod get_all; +mod types; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct APIError { diff --git a/filed/src/web/api/get_all.rs b/filed/src/web/api/get_all.rs index 72879e6..6b4286c 100644 --- a/filed/src/web/api/get_all.rs +++ b/filed/src/web/api/get_all.rs @@ -1,9 +1,31 @@ -use warp::{reply::Reply, reject::Rejection, Filter}; +use warp::{reply::{Reply, json}, reject::Rejection, Filter, http::StatusCode}; -use crate::web::state::SharedState; +use crate::web::{state::SharedState, rejection::HttpReject}; -pub async fn get_all(_state: SharedState) -> Result, Rejection> { - Ok(Box::new(warp::reply::json(&String::from("aaaaa")))) +use super::types::ErrorMessage; + +pub async fn get_all(state: SharedState) -> Result, Rejection> { + if ! state.config.api.enabled { + return Ok( + Box::new( + warp::reply::with_status( + json(&ErrorMessage::new(super::types::Error::APIDisabled)), + StatusCode::SERVICE_UNAVAILABLE + ) + ) + ) + } + + Ok( + Box::new( + json( + &state.file_mgr.get_all(true, true) + .await + .map_err(|x| x.to_string()) + .map_err(|x| HttpReject::StringError(x))? + ) + ) + ) } pub fn get_all_f(state: SharedState) -> impl Filter + Clone { diff --git a/filed/src/web/api/types.rs b/filed/src/web/api/types.rs new file mode 100644 index 0000000..a1ecb62 --- /dev/null +++ b/filed/src/web/api/types.rs @@ -0,0 +1,23 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum Error { + APIDisabled, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ErrorMessage { + pub error: Error, + pub details: Option, +} + +impl ErrorMessage { + pub fn new(error: Error) -> ErrorMessage { + ErrorMessage { + details: match error { + Error::APIDisabled => Some("API is disabled by the administrator. Please contact them for further details".into()) + }, + error, + } + } +} \ No newline at end of file