|
|
@ -1,7 +1,6 @@ |
|
|
|
use std::{ |
|
|
|
use std::{ |
|
|
|
collections::HashMap, |
|
|
|
collections::HashMap, |
|
|
|
ffi::OsString, |
|
|
|
fs::{read_to_string, DirBuilder, File}, |
|
|
|
fs::{DirBuilder, File}, |
|
|
|
|
|
|
|
io::{self, BufRead}, |
|
|
|
io::{self, BufRead}, |
|
|
|
net::SocketAddr, |
|
|
|
net::SocketAddr, |
|
|
|
path::PathBuf, |
|
|
|
path::PathBuf, |
|
|
@ -43,21 +42,70 @@ pub enum Error { |
|
|
|
Metadata, |
|
|
|
Metadata, |
|
|
|
#[error("some shit missing: {0}")] |
|
|
|
#[error("some shit missing: {0}")] |
|
|
|
ShitMissing(String), |
|
|
|
ShitMissing(String), |
|
|
|
|
|
|
|
#[error("filesystem error")] |
|
|
|
|
|
|
|
FS, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct TextPaste { |
|
|
|
struct TextPaste { |
|
|
|
pub text: String, |
|
|
|
pub text: String, |
|
|
|
pub meta: HashMap<String, String>, |
|
|
|
pub meta: TextMeta, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct TextMeta { |
|
|
|
|
|
|
|
language: Option<String>, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl TextMeta { |
|
|
|
|
|
|
|
pub fn parse(from: &str) -> Result<Self, Error> { |
|
|
|
|
|
|
|
let mut map = HashMap::new(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from.lines() |
|
|
|
|
|
|
|
.map(|line| line.trim()) |
|
|
|
|
|
|
|
.filter(|line| line.len() > 0) |
|
|
|
|
|
|
|
.map(|line| { |
|
|
|
|
|
|
|
line.split_once(": ") |
|
|
|
|
|
|
|
.ok_or(Error::Metadata) |
|
|
|
|
|
|
|
.map(|(k, v)| map.insert(k.to_string(), v.to_string())) |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
// meh, this prolly doesnt perform well but idc its only init code
|
|
|
|
|
|
|
|
Ok(Self { |
|
|
|
|
|
|
|
language: map.remove("language"), |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct FileMeta { |
|
|
|
struct FileMeta { |
|
|
|
file_name: String, |
|
|
|
file_name: String, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl FileMeta { |
|
|
|
|
|
|
|
pub fn parse(from: &str) -> Result<Self, Error> { |
|
|
|
|
|
|
|
let map = from |
|
|
|
|
|
|
|
.lines() |
|
|
|
|
|
|
|
.map(|line| line.trim()) |
|
|
|
|
|
|
|
.filter(|line| line.len() > 0) |
|
|
|
|
|
|
|
.map(|line| line.split_once(": ").ok_or(Error::Metadata)) |
|
|
|
|
|
|
|
.collect::<Result<HashMap<_, _>, Error>>()?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let file_name = map.remove("file_name").ok_or(Error::Metadata)?.to_string(); |
|
|
|
|
|
|
|
Ok(Self { file_name }) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct UserData { |
|
|
|
struct UserData { |
|
|
|
username: String, |
|
|
|
pub username: String, |
|
|
|
pw_hash: String, |
|
|
|
pub pw_hash: String, |
|
|
|
is_admin: bool, |
|
|
|
pub is_admin: bool, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
impl UserData { |
|
|
|
|
|
|
|
pub fn parse(line: &str, is_admin: bool) -> Result<Self, Error> { |
|
|
|
|
|
|
|
let (username, pw_hash) = line.split_once(": ").ok_or(Error::Metadata)?; |
|
|
|
|
|
|
|
Ok(Self { |
|
|
|
|
|
|
|
username: username.trim().to_string(), |
|
|
|
|
|
|
|
pw_hash: pw_hash.trim().to_string(), |
|
|
|
|
|
|
|
is_admin, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct DataStorage { |
|
|
|
struct DataStorage { |
|
|
@ -90,7 +138,7 @@ impl DataStorage { |
|
|
|
self.load_files()?; |
|
|
|
self.load_files()?; |
|
|
|
self.load_users()?; |
|
|
|
self.load_users()?; |
|
|
|
|
|
|
|
|
|
|
|
todo!() |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn ensure_folder_structure(&self) -> Result<(), Error> { |
|
|
|
fn ensure_folder_structure(&self) -> Result<(), Error> { |
|
|
@ -114,7 +162,7 @@ impl DataStorage { |
|
|
|
|
|
|
|
|
|
|
|
for line in io::BufReader::new(f).lines() { |
|
|
|
for line in io::BufReader::new(f).lines() { |
|
|
|
line?; |
|
|
|
line?; |
|
|
|
let (id, url) = line?.split_once(": ").expect("invalid redirect format"); |
|
|
|
let (id, url) = line?.split_once(": ").ok_or(Error::Metadata)?; |
|
|
|
self.redirects |
|
|
|
self.redirects |
|
|
|
.insert(id.trim().to_string(), url.trim().to_string()); |
|
|
|
.insert(id.trim().to_string(), url.trim().to_string()); |
|
|
|
// if there's a better way to do this let me know
|
|
|
|
// if there's a better way to do this let me know
|
|
|
@ -126,8 +174,18 @@ impl DataStorage { |
|
|
|
fn load_text(&mut self) -> Result<(), Error> { |
|
|
|
fn load_text(&mut self) -> Result<(), Error> { |
|
|
|
for thing in std::fs::read_dir(self.base_dir.join(TEXT_DIR)).expect("fs 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 dir_entry = thing?; // i'm so good at naming things
|
|
|
|
let f = File::open(dir_entry.path())?; |
|
|
|
let id = dir_entry.file_name().into_string().or(Err(Error::FS))?; |
|
|
|
let reader = io::BufReader::new(f); |
|
|
|
let (raw_metadata, text) = read_to_string(dir_entry.path())? |
|
|
|
|
|
|
|
.split_once("---") |
|
|
|
|
|
|
|
.expect("invalid text format"); |
|
|
|
|
|
|
|
let meta = TextMeta::parse(raw_metadata)?; |
|
|
|
|
|
|
|
self.text.insert( |
|
|
|
|
|
|
|
id, |
|
|
|
|
|
|
|
TextPaste { |
|
|
|
|
|
|
|
text: text.to_string(), |
|
|
|
|
|
|
|
meta, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
Ok(()) |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
@ -135,19 +193,14 @@ impl DataStorage { |
|
|
|
fn load_files(&mut self) -> Result<(), Error> { |
|
|
|
fn load_files(&mut self) -> Result<(), Error> { |
|
|
|
for thing in std::fs::read_dir(self.base_dir.join(FILE_DIR)).expect("fs 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 dir_entry = thing?; // i'm so good at naming things
|
|
|
|
let filename = dir_entry.file_name().into_string().expect("fucked up OS string"); |
|
|
|
let filename = dir_entry |
|
|
|
if filename |
|
|
|
.file_name() |
|
|
|
.ends_with(".meta") |
|
|
|
.into_string() |
|
|
|
{ |
|
|
|
.expect("fucked up OS string"); |
|
|
|
|
|
|
|
if filename.ends_with(".meta") { |
|
|
|
let id = filename.trim_end_matches(".meta").to_string(); |
|
|
|
let id = filename.trim_end_matches(".meta").to_string(); |
|
|
|
let f = File::open(dir_entry.path())?; |
|
|
|
let raw_metadata = read_to_string(dir_entry.path())?; |
|
|
|
let reader = io::BufReader::new(f); |
|
|
|
let metadata = FileMeta::parse(raw_metadata.as_str())?; |
|
|
|
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.files.insert(id, metadata); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -158,21 +211,26 @@ impl DataStorage { |
|
|
|
fn assert_all_files_present(&self) -> Result<(), Error> { |
|
|
|
fn assert_all_files_present(&self) -> Result<(), Error> { |
|
|
|
let files_folder = self.base_dir.join(FILE_DIR); |
|
|
|
let files_folder = self.base_dir.join(FILE_DIR); |
|
|
|
for (id, _) in self.files.into_iter() { |
|
|
|
for (id, _) in self.files.into_iter() { |
|
|
|
files_folder.join(id).try_exists().map_err(|_| Error::ShitMissing(id)); |
|
|
|
files_folder |
|
|
|
|
|
|
|
.join(id) |
|
|
|
|
|
|
|
.try_exists() |
|
|
|
|
|
|
|
.or(Err(Error::ShitMissing(id)))?; |
|
|
|
} |
|
|
|
} |
|
|
|
Ok(()) |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn parse_file_meta(raw: HashMap<String, String>) -> Result<FileMeta, Error> { |
|
|
|
|
|
|
|
let file_name = raw.get("file_name").ok_or(Error::Metadata)?.to_owned(); |
|
|
|
|
|
|
|
Ok(FileMeta { file_name }) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn load_users(&mut self) -> Result<(), Error> { |
|
|
|
fn load_users(&mut self) -> Result<(), Error> { |
|
|
|
todo!() |
|
|
|
let is_admin = true; |
|
|
|
|
|
|
|
for line in read_to_string(self.base_dir.join(USERS_FILE))?.lines() { |
|
|
|
|
|
|
|
if line.starts_with("---") { |
|
|
|
|
|
|
|
is_admin = false; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
let user = UserData::parse(line, is_admin)?; |
|
|
|
|
|
|
|
self.users.insert(user.username, user); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct AppState { |
|
|
|
struct AppState { |
|
|
|