implement /api/get_all

This commit is contained in:
blek 2023-10-22 14:22:19 +10:00
parent fef2ba8231
commit 5d05f7190a
Signed by: blek
GPG Key ID: 14546221E3595D0C
4 changed files with 105 additions and 5 deletions

View File

@ -1,7 +1,7 @@
use std::error::Error; use std::error::Error;
use redis::{Client, Commands}; use redis::{Client, Commands, AsyncCommands, Connection};
use crate::env::Env; use crate::env::Env;
@ -22,6 +22,60 @@ impl FileManager {
pub fn new(conn: Client, env: Env) -> FileManager { pub fn new(conn: Client, env: Env) -> FileManager {
FileManager { conn, env } FileManager { conn, env }
} }
async fn find_all(self: &Self, predicate: String) -> Result<Vec<File>, Box<dyn Error>> {
let mut conn = self.conn.get_async_connection().await?;
let found: Vec<String> = conn.keys(predicate).await?;
let serialized: Vec<File> =
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<Vec<File>, Box<dyn Error>> {
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<Option<File>, Box<dyn Error>> { fn find(self: &Self, key: String) -> Result<Option<File>, Box<dyn Error>> {
let mut conn = self.conn.get_connection()?; let mut conn = self.conn.get_connection()?;

View File

@ -6,6 +6,7 @@ use self::get_all::get_all_f;
use super::state::SharedState; use super::state::SharedState;
mod get_all; mod get_all;
mod types;
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct APIError { pub struct APIError {

View File

@ -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<Box<dyn Reply>, Rejection> { use super::types::ErrorMessage;
Ok(Box::new(warp::reply::json(&String::from("aaaaa"))))
pub async fn get_all(state: SharedState) -> Result<Box<dyn Reply>, 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<Extract = impl Reply, Error = Rejection> + Clone { pub fn get_all_f(state: SharedState) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {

View File

@ -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<String>,
}
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,
}
}
}