132 lines
3.9 KiB
Rust
132 lines
3.9 KiB
Rust
|
|
use std::error::Error;
|
|
|
|
use redis::{Client, Commands, AsyncCommands, Connection};
|
|
|
|
use crate::env::Env;
|
|
|
|
use super::File;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct FileManager {
|
|
conn: Client,
|
|
env: Env
|
|
}
|
|
|
|
pub enum LookupKind {
|
|
ByName,
|
|
ByHash
|
|
}
|
|
|
|
impl FileManager {
|
|
pub fn new(conn: Client, env: Env) -> FileManager {
|
|
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>> {
|
|
let mut conn = self.conn.get_connection()?;
|
|
|
|
if ! conn.exists(&key)? {
|
|
return Ok(None)
|
|
}
|
|
|
|
let data: String = conn.get(&key)?;
|
|
Ok(Some(serde_json::from_str(data.as_str())?))
|
|
}
|
|
pub fn find_by_name(self: &Self, name: String) -> Result<Option<File>, Box<dyn Error>> {
|
|
Ok(self.find(format!("{}-name-{}", self.env.redis.prefix, name))?)
|
|
}
|
|
pub fn find_by_hash(self: &Self, hash: String) -> Result<Option<File>, Box<dyn Error>> {
|
|
Ok(self.find(format!("{}-hash-{}", self.env.redis.prefix, hash))?)
|
|
}
|
|
|
|
fn save_int(self: &Self, file: &File, key: String) -> Result<(), Box<dyn Error>> {
|
|
log::debug!("Saving a file with key: {key}");
|
|
let mut conn = self.conn.get_connection()?;
|
|
conn.set(key, serde_json::to_string(&file)?)?;
|
|
Ok(())
|
|
}
|
|
|
|
pub fn save(self: &Self, file: &File, kind: LookupKind) -> Result<(), Box<dyn Error>> {
|
|
let file = file.clone();
|
|
let midfix = match kind {
|
|
LookupKind::ByName => "-name-",
|
|
LookupKind::ByHash => "-hash-"
|
|
};
|
|
|
|
match kind {
|
|
LookupKind::ByName => {
|
|
if (&file).name.is_none() {
|
|
return Err("Filename can't be None when LookupKind is ByName!".into())
|
|
}
|
|
}
|
|
_ => ()
|
|
}
|
|
|
|
self.save_int(
|
|
&file,
|
|
format!(
|
|
"{}{}{}",
|
|
self.env.redis.prefix,
|
|
midfix,
|
|
match kind {
|
|
LookupKind::ByName => (&file).name.as_ref().unwrap().clone(),
|
|
LookupKind::ByHash => (&file).hash()
|
|
}
|
|
)
|
|
)
|
|
}
|
|
} |