From 3efb2b8ec2a6f7ff2d63e631d2b23e6fba32fee8 Mon Sep 17 00:00:00 2001 From: xenua Date: Sun, 1 Jan 2023 02:38:14 +0100 Subject: [PATCH] fuck new years explosives --- .data-example/accounts | 0 .data-example/redirects | 1 + .data-example/stats | 3 + .data-example/users | 6 ++ Cargo.lock | 1 + Cargo.toml | 1 + src/main.rs | 157 +++++++++++++++++++++++++++++++++++++--- 7 files changed, 159 insertions(+), 10 deletions(-) delete mode 100644 .data-example/accounts create mode 100644 .data-example/redirects create mode 100644 .data-example/stats create mode 100644 .data-example/users diff --git a/.data-example/accounts b/.data-example/accounts deleted file mode 100644 index e69de29..0000000 diff --git a/.data-example/redirects b/.data-example/redirects new file mode 100644 index 0000000..1269212 --- /dev/null +++ b/.data-example/redirects @@ -0,0 +1 @@ +id: https://www.youtube.com/watch?v=dQw4w9WgXcQ \ No newline at end of file diff --git a/.data-example/stats b/.data-example/stats new file mode 100644 index 0000000..f46c678 --- /dev/null +++ b/.data-example/stats @@ -0,0 +1,3 @@ +version: 1 +id_collisions: 0 +requests_served: 420691337 \ No newline at end of file diff --git a/.data-example/users b/.data-example/users new file mode 100644 index 0000000..04d9390 --- /dev/null +++ b/.data-example/users @@ -0,0 +1,6 @@ +admin: hash +admin2: hash +--- +user: hash +user2: hash +user3: hash \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 7ee05ea..a91d916 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1286,6 +1286,7 @@ dependencies = [ "parking_lot", "serde", "tera", + "thiserror", "tokio", ] diff --git a/Cargo.toml b/Cargo.toml index 4561edd..b4df6ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,5 @@ nanoid = "0.4.0" parking_lot = "0.12.1" serde = { version = "1.0.152", features = ["derive", "serde_derive"] } tera = "1.17.1" +thiserror = "1.0.38" tokio = { version = "1.23.0", features = ["full"] } diff --git a/src/main.rs b/src/main.rs index 47959dd..e191aca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,17 @@ -use std::{collections::HashMap, net::SocketAddr, path::PathBuf}; +use std::{ + collections::HashMap, + ffi::OsString, + fs::{DirBuilder, File}, + io::{self, BufRead}, + net::SocketAddr, + path::PathBuf, +}; + +#[cfg(target_family = "unix")] +use std::os::unix::fs::DirBuilderExt; use axum::{routing::get, Router}; use dashmap::DashMap; -use parking_lot::RwLock; use serde::{Deserialize, Serialize}; use lazy_static::lazy_static; @@ -11,15 +20,31 @@ use tera::Tera; mod down; mod up; +const TEXT_DIR: String = "text".to_string(); +const FILE_DIR: String = "files".to_string(); +const REDIRECTS_FILE: String = "redirects".to_string(); +const STATS_FILE: String = "stats".to_string(); +const USERS_FILE: String = "users".to_string(); + lazy_static! { pub static ref TEMPLATES: Tera = { let tera = Tera::new(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*.html")) - .expect("Parsing error(s):"); + .expect("Parsing error(s)"); tera }; } +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("io error")] + IO(#[from] std::io::Error), + #[error("metadata error")] + Metadata, + #[error("some shit missing: {0}")] + ShitMissing(String), +} + struct TextPaste { pub text: String, pub meta: HashMap, @@ -29,22 +54,134 @@ struct FileMeta { file_name: String, } +struct UserData { + username: String, + pw_hash: String, + is_admin: bool, +} + struct DataStorage { - links: DashMap, + base_dir: PathBuf, + redirects: DashMap, text: DashMap, files: DashMap, + users: DashMap, +} + +impl DataStorage { + pub fn new(base_dir: PathBuf) -> Self { + let redirects = DashMap::new(); + let text = DashMap::new(); + let files = DashMap::new(); + let users = DashMap::new(); + DataStorage { + base_dir, + redirects, + text, + files, + users, + } + } + + pub fn init(&mut self) -> Result<(), Error> { + self.ensure_folder_structure()?; + self.load_redirects()?; + self.load_text()?; + self.load_files()?; + self.load_users()?; + + todo!() + } + + fn ensure_folder_structure(&self) -> Result<(), Error> { + let dir_builder = DirBuilder::new().recursive(true); + if cfg!(target_family = "unix") { + dir_builder = dir_builder.mode(0o775); + } + + dir_builder.create(self.base_dir)?; + dir_builder.create(self.base_dir.join(FILE_DIR))?; + dir_builder.create(self.base_dir.join(TEXT_DIR))?; + + Ok(()) + } + + fn load_redirects(&mut self) -> Result<(), Error> { + let f = File::options() + .create(true) + .read(true) + .open(self.base_dir.join(REDIRECTS_FILE))?; + + for line in io::BufReader::new(f).lines() { + line?; + let (id, url) = line?.split_once(": ").expect("invalid redirect format"); + self.redirects + .insert(id.trim().to_string(), url.trim().to_string()); + // if there's a better way to do this let me know + } + + Ok(()) + } + + fn load_text(&mut self) -> Result<(), Error> { + for thing in std::fs::read_dir(self.base_dir.join(TEXT_DIR)).expect("fs error") { + let dir_entry = thing?; // i'm so good at naming things + let f = File::open(dir_entry.path())?; + let reader = io::BufReader::new(f); + } + Ok(()) + } + + fn load_files(&mut self) -> Result<(), Error> { + for thing in std::fs::read_dir(self.base_dir.join(FILE_DIR)).expect("fs error") { + let dir_entry = thing?; // i'm so good at naming things + let filename = dir_entry.file_name().into_string().expect("fucked up OS string"); + if filename + .ends_with(".meta") + { + let id = filename.trim_end_matches(".meta").to_string(); + let f = File::open(dir_entry.path())?; + let reader = io::BufReader::new(f); + let raw_metadata = HashMap::new(); + for line in reader.lines() { + let (k, v) = line?.split_once(": ").expect("invalid metadata"); + raw_metadata.insert(k.trim().to_string(), v.trim().to_string()); + } + let metadata = Self::parse_file_meta(raw_metadata)?; + self.files.insert(id, metadata); + } + } + self.assert_all_files_present()?; + Ok(()) + } + + fn assert_all_files_present(&self) -> Result<(), Error> { + let files_folder = self.base_dir.join(FILE_DIR); + for (id, _) in self.files.into_iter() { + files_folder.join(id).try_exists().map_err(|_| Error::ShitMissing(id)); + } + Ok(()) + } + + fn parse_file_meta(raw: HashMap) -> Result { + let file_name = raw.get("file_name").ok_or(Error::Metadata)?.to_owned(); + Ok(FileMeta { file_name }) + } + + fn load_users(&mut self) -> Result<(), Error> { + todo!() + } + + } struct AppState { - alphabet: Box<[char; 32]>, + alphabet: Vec, id_length: usize, cache: DataStorage, - base_dir: PathBuf, } -impl AppState { - -} +impl AppState {} fn routes() -> Router { let up = up::routes(); @@ -60,7 +197,7 @@ async fn main() -> anyhow::Result<()> { let addr: SocketAddr = std::env::var("LISTEN_ADDR") .unwrap_or("127.0.0.1:8080".to_string()) .parse() - .expect("parse error"); + .expect("LISTEN_ADDR parse error"); let app = routes();