start implementing diesel and SQLite db

This commit is contained in:
MrDulfin 2025-05-24 10:01:58 -04:00
parent 5a8a19cb64
commit 21977fe74f
10 changed files with 79 additions and 24 deletions

3
.gitignore vendored
View file

@ -8,3 +8,6 @@ settings.toml
test/ test/
Cargo.lock Cargo.lock
.env
*.db

View file

@ -9,7 +9,7 @@ members = [
authors = ["G2-Games <ke0bhogsg@gmail.com>", "MrDulfin"] authors = ["G2-Games <ke0bhogsg@gmail.com>", "MrDulfin"]
[workspace.lints.rust] [workspace.lints.rust]
unsafe_code = "forbid" # unsafe_code = "forbid"
[profile.production] [profile.production]
inherits = "release" inherits = "release"

View file

@ -29,6 +29,10 @@ toml = "0.8"
unidecode = "0.3" unidecode = "0.3"
urlencoding = "2.1" urlencoding = "2.1"
uuid = { version = "1.11", features = ["serde", "v4"] } uuid = { version = "1.11", features = ["serde", "v4"] }
diesel = { version = "2.2.0", features = ["sqlite", "returning_clauses_for_sqlite_3_35", "chrono"] }
libsqlite3-sys = { version = "0.30", features = ["bundled"] }
dotenvy = "0.15"
diesel-derive-newtype = "2.1.2"
[build-dependencies] [build-dependencies]

View file

@ -1,33 +1,31 @@
mod schema;
use std::{ use std::{
collections::{hash_map::Values, HashMap, HashSet}, collections::{hash_map::Values, HashMap, HashSet},
ffi::OsStr, ffi::OsStr,
fs::{self, File}, fs::{self, File},
io::{self, Write}, io::{self, Write},
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::{Arc, RwLock}, sync::{Arc, Mutex, RwLock},
}; };
use blake3::Hash; use blake3::Hash;
use chrono::{DateTime, TimeDelta, Utc}; use chrono::{DateTime, NaiveDateTime, TimeDelta, Utc};
use ciborium::{from_reader, into_writer}; use ciborium::{from_reader, into_writer};
use diesel::{prelude::Queryable, Selectable};
use log::{error, info, warn}; use log::{error, info, warn};
use rand::distributions::{Alphanumeric, DistString}; use rand::distributions::{Alphanumeric, DistString};
use rocket::{ use rocket::{
form::{self, FromFormField, ValueField}, form::{self, FromFormField, ValueField},
serde::{Deserialize, Serialize}, serde::{Deserialize, Serialize},
}; };
use serde_with::{serde_as, DisplayFromStr}; use serde_with::serde_as;
use uuid::Uuid; use uuid::Uuid;
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Mochibase { pub struct Mochibase {
path: PathBuf, path: PathBuf,
/// connection to the db
/// Every hash in the database along with the [`Mmid`]s associated with them db: Arc<Mutex<diesel::sqlite::SqliteConnection>>,
hashes: HashMap<Hash, HashSet<Mmid>>,
/// All entries in the database
entries: HashMap<Mmid, MochiFile>,
} }
impl Mochibase { impl Mochibase {
@ -150,8 +148,10 @@ impl Mochibase {
} }
/// An entry in the database storing metadata about a file /// An entry in the database storing metadata about a file
#[serde_as] #[derive(Queryable, Selectable)]
#[derive(Debug, Clone, Deserialize, Serialize)] #[diesel(table_name = crate::database::schema::mochifiles)]
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MochiFile { pub struct MochiFile {
/// A unique identifier describing this file /// A unique identifier describing this file
mmid: Mmid, mmid: Mmid,
@ -163,25 +163,25 @@ pub struct MochiFile {
mime_type: String, mime_type: String,
/// The Blake3 hash of the file /// The Blake3 hash of the file
#[serde_as(as = "DisplayFromStr")] hash: String,
hash: Hash,
/// The datetime when the file was uploaded /// The datetime when the file was uploaded
upload_datetime: DateTime<Utc>, upload_datetime: chrono::NaiveDateTime,
/// The datetime when the file is set to expire /// The datetime when the file is set to expire
expiry_datetime: DateTime<Utc>, expiry_datetime: chrono::NaiveDateTime,
} }
impl MochiFile { impl MochiFile {
/// Create a new file that expires in `expiry`. /// Create a new file that expires in `expiry`.
pub fn new( pub fn new(
mmid: Mmid, mmid: Mmid,
name: String, name: String,
mime_type: String, mime_type: String,
hash: Hash, hash: String,
upload: DateTime<Utc>, upload: NaiveDateTime,
expiry: DateTime<Utc>, expiry: NaiveDateTime,
) -> Self { ) -> Self {
Self { Self {
mmid, mmid,
@ -197,16 +197,16 @@ impl MochiFile {
&self.name &self.name
} }
pub fn expiry(&self) -> DateTime<Utc> { pub fn expiry(&self) -> NaiveDateTime {
self.expiry_datetime self.expiry_datetime
} }
pub fn is_expired(&self) -> bool { pub fn is_expired(&self) -> bool {
let datetime = Utc::now(); let datetime = Utc::now();
datetime > self.expiry_datetime datetime > self.expiry_datetime.and_utc()
} }
pub fn hash(&self) -> &Hash { pub fn hash(&self) -> &String {
&self.hash &self.hash
} }
@ -219,6 +219,8 @@ impl MochiFile {
} }
} }
/// Clean the database. Removes files which are past their expiry /// Clean the database. Removes files which are past their expiry
/// [`chrono::DateTime`]. Also removes files which no longer exist on the disk. /// [`chrono::DateTime`]. Also removes files which no longer exist on the disk.
pub fn clean_database(db: &Arc<RwLock<Mochibase>>, file_path: &Path) { pub fn clean_database(db: &Arc<RwLock<Mochibase>>, file_path: &Path) {
@ -262,7 +264,8 @@ pub fn clean_database(db: &Arc<RwLock<Mochibase>>, file_path: &Path) {
/// A unique identifier for an entry in the database, 8 characters long, /// A unique identifier for an entry in the database, 8 characters long,
/// consists of ASCII alphanumeric characters (`a-z`, `A-Z`, and `0-9`). /// consists of ASCII alphanumeric characters (`a-z`, `A-Z`, and `0-9`).
#[derive(Debug, PartialEq, Eq, Clone, Hash, Deserialize, Serialize)] #[derive(diesel_derive_newtype::DieselNewType)]
#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
pub struct Mmid(String); pub struct Mmid(String);
impl Mmid { impl Mmid {

View file

@ -0,0 +1,12 @@
// @generated automatically by Diesel CLI.
diesel::table! {
mochifiles (mmid) {
mmid -> Text,
name -> Text,
mime_type -> Text,
hash -> Text,
upload_datetime -> Timestamp,
expiry_datetime -> Timestamp,
}
}

9
diesel.toml Normal file
View file

@ -0,0 +1,9 @@
# For documentation on how to configure this file,
# see https://diesel.rs/guides/configuring-diesel-cli
[print_schema]
file = "confetti-box/src/database/schema.rs"
custom_type_derives = ["diesel::query_builder::QueryId", "Clone"]
[migrations_directory]
dir = "migrations/"

0
migrations/.keep Normal file
View file

View file

@ -0,0 +1,2 @@
-- This file should undo anything in `up.sql`
DROP TABLE mochifiles

View file

@ -0,0 +1,10 @@
-- Your SQL goes here
CREATE TABLE mochifiles (
mmid TEXT PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
mime_type TEXT NOT NULL,
hash TEXT NOT NULL UNIQUE,
upload_datetime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
expiry_datetime DATETIME NOT NULL
)

12
src/database/schema.rs Normal file
View file

@ -0,0 +1,12 @@
// @generated automatically by Diesel CLI.
diesel::table! {
mochifiles (mmid) {
mmid -> Nullable<Integer>,
name -> Text,
mime_type -> Text,
hash -> Text,
upload_datetime -> Nullable<Timestamp>,
expiry_datetime -> Timestamp,
}
}