mirror of
https://github.com/Dangoware/confetti-box.git
synced 2025-04-19 07:12:58 -05:00
113 lines
3 KiB
Rust
113 lines
3 KiB
Rust
use std::{collections::HashMap, fs::{self, File}, path::{Path, PathBuf}};
|
|
|
|
use bincode::{config::Configuration, decode_from_std_read, encode_into_std_write, Decode, Encode};
|
|
use chrono::{DateTime, TimeDelta, Utc};
|
|
use blake3::Hash;
|
|
|
|
const BINCODE_CFG: Configuration = bincode::config::standard();
|
|
|
|
#[derive(Debug, Clone)]
|
|
#[derive(Decode, Encode)]
|
|
pub struct Database {
|
|
path: PathBuf,
|
|
#[bincode(with_serde)]
|
|
pub files: HashMap<MochiKey, MochiFile>
|
|
}
|
|
|
|
impl Database {
|
|
pub fn new<P: AsRef<Path>>(path: &P) -> Self {
|
|
let mut file = File::create_new(path).expect("Could not create database!");
|
|
|
|
let output = Self {
|
|
path: path.as_ref().to_path_buf(),
|
|
files: HashMap::new()
|
|
};
|
|
|
|
encode_into_std_write(&output, &mut file, BINCODE_CFG).expect("Could not write database!");
|
|
|
|
output
|
|
}
|
|
|
|
pub fn open<P: AsRef<Path>>(path: &P) -> Self {
|
|
if !path.as_ref().exists() {
|
|
Self::new(path)
|
|
} else {
|
|
let mut file = File::open(path).expect("Could not get database file!");
|
|
decode_from_std_read(&mut file, BINCODE_CFG).expect("Could not decode database")
|
|
}
|
|
}
|
|
|
|
pub fn save(&self) {
|
|
let mut out_path = self.path.clone();
|
|
out_path.set_extension(".bkp");
|
|
let mut file = File::create(&out_path).expect("Could not save!");
|
|
encode_into_std_write(&self, &mut file, BINCODE_CFG).expect("Could not write out!");
|
|
|
|
fs::rename(out_path, &self.path).unwrap();
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
#[derive(Decode, Encode)]
|
|
#[derive(serde::Deserialize, serde::Serialize)]
|
|
pub struct MochiFile {
|
|
/// The original name of the file
|
|
name: String,
|
|
|
|
/// Size of the file in bytes
|
|
size: usize,
|
|
|
|
/// The location on disk (for deletion and management)
|
|
filename: PathBuf,
|
|
|
|
/// The hashed contents of the file as a Blake3 hash
|
|
#[bincode(with_serde)]
|
|
hash: Hash,
|
|
|
|
/// The datetime when the file was uploaded
|
|
#[bincode(with_serde)]
|
|
upload_datetime: DateTime<Utc>,
|
|
|
|
/// The datetime when the file is set to expire
|
|
#[bincode(with_serde)]
|
|
expiry_datetime: DateTime<Utc>,
|
|
}
|
|
|
|
impl MochiFile {
|
|
/// Create a new file that expires in `expiry`.
|
|
pub fn new_with_expiry(
|
|
name: &str,
|
|
size: usize,
|
|
hash: Hash,
|
|
filename: PathBuf,
|
|
expire_duration: TimeDelta
|
|
) -> Self {
|
|
let current = Utc::now();
|
|
let expiry = current + expire_duration;
|
|
|
|
Self {
|
|
name: name.to_string(),
|
|
size,
|
|
filename,
|
|
hash,
|
|
upload_datetime: current,
|
|
expiry_datetime: expiry,
|
|
}
|
|
}
|
|
|
|
pub fn get_key(&self) -> MochiKey {
|
|
MochiKey {
|
|
name: self.name.clone(),
|
|
hash: self.hash
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
#[derive(Decode, Encode)]
|
|
#[derive(serde::Deserialize, serde::Serialize)]
|
|
pub struct MochiKey {
|
|
name: String,
|
|
#[bincode(with_serde)]
|
|
hash: Hash,
|
|
}
|