[add] move mutex to db::bundlesdb

[fix] don't require "&mut self" in BundlesDB methods
[fix] make AppData not mutable
[add] store caches in lazy static variables
This commit is contained in:
hkau 2024-02-26 12:15:38 -05:00
parent 777381c3f6
commit 4f2569af82
11 changed files with 110 additions and 281 deletions

View file

@ -25,6 +25,7 @@ either = "1.9.0"
env_logger = "0.11.2"
hex_fmt = "0.3.0"
idna = "0.5.0"
once_cell = "1.19.0"
pest = "2.7.7"
pest_derive = "2.7.7"
regex = "1.10.2"

View file

@ -1,5 +1,3 @@
use std::sync::Mutex;
use actix_web::{get, post, web, HttpRequest, HttpResponse, Responder};
use crate::{db::bundlesdb::AppData, utility};
@ -15,10 +13,7 @@ struct LoginInfo {
}
#[post("/api/auth/register")]
pub async fn register(
body: web::Json<RegisterInfo>,
data: web::Data<Mutex<AppData>>,
) -> impl Responder {
pub async fn register(body: web::Json<RegisterInfo>, data: web::Data<AppData>) -> impl Responder {
// if server disabled registration, return
let disabled = crate::config::get_var("REGISTRATION_DISABLED");
@ -27,15 +22,9 @@ pub async fn register(
.body("This server requires has registration disabled");
}
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
// ...
let username = &body.username.trim();
let res = lock.db.create_user(username.to_string()).await;
let res = data.db.create_user(username.to_string()).await;
let c = res.clone();
let set_cookie = if res.success && res.payload.is_some() {
@ -52,17 +41,11 @@ pub async fn register(
}
#[post("/api/auth/login")]
pub async fn login(body: web::Json<LoginInfo>, data: web::Data<Mutex<AppData>>) -> impl Responder {
pub async fn login(body: web::Json<LoginInfo>, data: web::Data<AppData>) -> impl Responder {
let id = body.uid.trim();
let id_hashed = utility::hash(id.to_string());
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
let res = lock
let res = data
.db
.get_user_by_hashed(id_hashed) // if the user is returned, that means the ID is valid
.await;
@ -82,20 +65,14 @@ pub async fn login(body: web::Json<LoginInfo>, data: web::Data<Mutex<AppData>>)
}
#[get("/api/auth/logout")]
pub async fn logout(req: HttpRequest, data: web::Data<Mutex<AppData>>) -> impl Responder {
pub async fn logout(req: HttpRequest, data: web::Data<AppData>) -> impl Responder {
let cookie = req.cookie("__Secure-Token");
if cookie.is_none() {
return HttpResponse::NotAcceptable().body("Missing token");
}
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
let res = lock
let res = data
.db
.get_user_by_hashed(cookie.unwrap().value().to_string()) // if the user is returned, that means the ID is valid
.await;

View file

@ -1,5 +1,3 @@
use std::sync::Mutex;
use actix_web::{get, post, web, HttpRequest, HttpResponse, Responder};
use crate::db::bundlesdb::{self, AtomicPasteFSFile};
@ -64,17 +62,10 @@ pub async fn render_ssm_request(body: web::Json<RenderInfo>) -> impl Responder {
#[get("/api/ssm/{url:.*}")]
pub async fn render_paste_ssm_request(
req: HttpRequest,
data: web::Data<Mutex<bundlesdb::AppData>>,
data: web::Data<bundlesdb::AppData>,
) -> impl Responder {
let custom_url: String = req.match_info().get("url").unwrap().to_string();
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
let res = lock.db.get_paste_by_url(custom_url).await;
let res = data.db.get_paste_by_url(custom_url).await;
if !res.success {
return HttpResponse::NotFound()
@ -107,7 +98,7 @@ pub async fn render_paste_ssm_request(
pub async fn create_request(
req: HttpRequest,
body: web::Json<CreateInfo>,
data: web::Data<Mutex<bundlesdb::AppData>>,
data: web::Data<bundlesdb::AppData>,
) -> impl Responder {
let custom_url: String = body.custom_url.trim().to_string();
let edit_password: &String = &body.edit_password;
@ -120,17 +111,11 @@ pub async fn create_request(
""
};
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
// get owner
let token_cookie = req.cookie("__Secure-Token");
let token_user = if token_cookie.is_some() {
Option::Some(
lock.db
data.db
.get_user_by_hashed(token_cookie.as_ref().unwrap().value().to_string()) // if the user is returned, that means the ID is valid
.await,
)
@ -154,7 +139,7 @@ pub async fn create_request(
}
// create paste
let res = lock
let res = data
.db
.create_paste(
&mut bundlesdb::Paste {
@ -188,7 +173,7 @@ pub async fn create_request(
pub async fn edit_request(
req: HttpRequest,
body: web::Json<EditInfo>,
data: web::Data<Mutex<bundlesdb::AppData>>,
data: web::Data<bundlesdb::AppData>,
) -> impl Responder {
let custom_url: String = body.custom_url.trim().to_string();
let content: String = body.content.trim().to_string();
@ -196,17 +181,11 @@ pub async fn edit_request(
let new_url: Option<String> = body.new_custom_url.to_owned();
let new_edit_password: Option<String> = body.new_edit_password.to_owned();
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
// get owner
let token_cookie = req.cookie("__Secure-Token");
let token_user = if token_cookie.is_some() {
Option::Some(
lock.db
data.db
.get_user_by_hashed(token_cookie.as_ref().unwrap().value().to_string()) // if the user is returned, that means the ID is valid
.await,
)
@ -222,7 +201,7 @@ pub async fn edit_request(
}
// ...
let res = lock
let res = data
.db
.edit_paste_by_url(
custom_url,
@ -249,7 +228,7 @@ pub async fn edit_request(
pub async fn edit_atomic_request(
req: HttpRequest,
body: web::Json<EditAtomicInfo>,
data: web::Data<Mutex<bundlesdb::AppData>>,
data: web::Data<bundlesdb::AppData>,
) -> impl Responder {
// this is essentially the same as edit_request but it handles the atomic JSON file system
// ...it does NOT accept an edit password! users must be authenticated
@ -257,17 +236,11 @@ pub async fn edit_atomic_request(
let path: String = body.path.trim().to_string();
let content: String = body.content.trim().to_string();
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
// get owner
let token_cookie = req.cookie("__Secure-Token");
let token_user = if token_cookie.is_some() {
Option::Some(
lock.db
data.db
.get_user_by_hashed(token_cookie.as_ref().unwrap().value().to_string()) // if the user is returned, that means the ID is valid
.await,
)
@ -284,7 +257,7 @@ pub async fn edit_atomic_request(
// get paste
let paste: bundlesdb::DefaultReturn<Option<bundlesdb::Paste<String>>> =
lock.db.get_paste_by_url(custom_url.clone()).await;
data.db.get_paste_by_url(custom_url.clone()).await;
if paste.success == false {
return HttpResponse::Ok()
@ -324,7 +297,7 @@ pub async fn edit_atomic_request(
});
// ...
let res = lock
let res = data
.db
.edit_paste_by_url(
custom_url,
@ -351,22 +324,16 @@ pub async fn edit_atomic_request(
pub async fn delete_request(
req: HttpRequest,
body: web::Json<DeleteInfo>,
data: web::Data<Mutex<bundlesdb::AppData>>,
data: web::Data<bundlesdb::AppData>,
) -> impl Responder {
let custom_url: String = body.custom_url.trim().to_string();
let edit_password: String = body.edit_password.to_owned();
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
// get owner
let token_cookie = req.cookie("__Secure-Token");
let token_user = if token_cookie.is_some() {
Option::Some(
lock.db
data.db
.get_user_by_hashed(token_cookie.as_ref().unwrap().value().to_string()) // if the user is returned, that means the ID is valid
.await,
)
@ -382,7 +349,7 @@ pub async fn delete_request(
}
// delete
let res = lock
let res = data
.db
.delete_paste_by_url(
custom_url,
@ -406,7 +373,7 @@ pub async fn delete_request(
pub async fn metadata_request(
req: HttpRequest,
body: web::Json<MetadataInfo>,
data: web::Data<Mutex<bundlesdb::AppData>>,
data: web::Data<bundlesdb::AppData>,
) -> impl Responder {
let custom_url: String = body.custom_url.trim().to_string();
let edit_password: String = body.edit_password.to_owned();
@ -414,17 +381,11 @@ pub async fn metadata_request(
let m = body.metadata.to_owned();
let metadata: bundlesdb::PasteMetadata = m;
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
// get owner
let token_cookie = req.cookie("__Secure-Token");
let token_user = if token_cookie.is_some() {
Option::Some(
lock.db
data.db
.get_user_by_hashed(token_cookie.as_ref().unwrap().value().to_string()) // if the user is returned, that means the ID is valid
.await,
)
@ -440,7 +401,7 @@ pub async fn metadata_request(
}
// ...
let res = lock
let res = data
.db
.edit_paste_metadata_by_url(
custom_url,
@ -464,17 +425,10 @@ pub async fn metadata_request(
/// Check if a paste exists
pub async fn exists_request(
req: HttpRequest,
data: web::Data<Mutex<bundlesdb::AppData>>,
data: web::Data<bundlesdb::AppData>,
) -> impl Responder {
let custom_url: String = req.match_info().get("url").unwrap().to_string();
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
let res = lock.db.get_paste_by_url(custom_url).await;
let res = data.db.get_paste_by_url(custom_url).await;
// return
return HttpResponse::Ok()
@ -486,18 +440,11 @@ pub async fn exists_request(
/// Get paste by `custom_url`
pub async fn get_from_url_request(
req: HttpRequest,
data: web::Data<Mutex<bundlesdb::AppData>>,
data: web::Data<bundlesdb::AppData>,
) -> impl Responder {
let custom_url: String = req.match_info().get("url").unwrap().to_string();
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
let res: bundlesdb::DefaultReturn<Option<bundlesdb::Paste<String>>> =
lock.db.get_paste_by_url(custom_url).await;
data.db.get_paste_by_url(custom_url).await;
// if res.metadata contains '"private_source":"on"', return NotFound
if res.payload.is_some()
@ -540,18 +487,11 @@ pub async fn get_from_url_request(
/// Get paste by ID
pub async fn get_from_id_request(
req: HttpRequest,
data: web::Data<Mutex<bundlesdb::AppData>>,
data: web::Data<bundlesdb::AppData>,
) -> impl Responder {
let id: String = req.match_info().get("id").unwrap().to_string();
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
let res: bundlesdb::DefaultReturn<Option<bundlesdb::Paste<String>>> =
lock.db.get_paste_by_id(id).await;
data.db.get_paste_by_id(id).await;
// if res.metadata contains '"private_source":"on"', return NotFound
if res.payload.is_some()
@ -594,18 +534,11 @@ pub async fn get_from_id_request(
/// Get all pastes by owner
pub async fn get_from_owner_request(
req: HttpRequest,
data: web::Data<Mutex<bundlesdb::AppData>>,
data: web::Data<bundlesdb::AppData>,
) -> impl Responder {
let username: String = req.match_info().get("username").unwrap().to_string();
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
let res: bundlesdb::DefaultReturn<Option<Vec<bundlesdb::PasteIdentifier>>> =
lock.db.get_pastes_by_owner(username).await;
data.db.get_pastes_by_owner(username).await;
// return
return HttpResponse::Ok()

View file

@ -1,6 +1,5 @@
//! # BundlesDB
//! Database handler for all database types
use super::{
cache::CacheStore,
sql::{self, Database, DatabaseOpts},
@ -12,6 +11,9 @@ use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use once_cell::sync::Lazy;
use std::sync::Mutex;
#[derive(Clone)]
pub struct AppData {
pub db: BundlesDB,
@ -130,36 +132,32 @@ pub struct Log {
#[cfg(feature = "postgres")]
pub struct BundlesDB {
pub db: Database<sqlx::PgPool>,
pub paste_cache: CacheStore<Paste<String>>,
pub auth_cache: CacheStore<UserState>,
}
#[derive(Clone)]
#[cfg(feature = "mysql")]
pub struct BundlesDB {
pub db: Database<sqlx::MySqlPool>,
pub paste_cache: CacheStore<Paste<String>>,
pub auth_cache: CacheStore<UserState>,
}
#[derive(Clone)]
#[cfg(feature = "sqlite")]
pub struct BundlesDB {
pub db: Database<sqlx::SqlitePool>,
pub paste_cache: CacheStore<Paste<String>>,
pub auth_cache: CacheStore<UserState>,
}
static PASTE_CACHE: Lazy<Mutex<CacheStore<Paste<String>>>> =
Lazy::new(|| Mutex::new(CacheStore::new()));
static AUTH_CACHE: Lazy<Mutex<CacheStore<UserState>>> = Lazy::new(|| Mutex::new(CacheStore::new()));
impl BundlesDB {
pub async fn new(options: DatabaseOpts) -> BundlesDB {
return BundlesDB {
db: sql::create_db(options).await,
paste_cache: CacheStore::new(),
auth_cache: CacheStore::new(),
};
}
pub async fn init(&mut self) {
pub async fn init(&self) {
// ...
// create tables
@ -217,7 +215,7 @@ impl BundlesDB {
}
#[cfg(feature = "sqlite")]
fn textify_row(&mut self, row: sqlx::sqlite::SqliteRow) -> DatabaseReturn {
fn textify_row(&self, row: sqlx::sqlite::SqliteRow) -> DatabaseReturn {
// get all columns
let columns = row.columns();
@ -234,7 +232,7 @@ impl BundlesDB {
}
#[cfg(feature = "postgres")]
fn textify_row(&mut self, row: sqlx::postgres::PgRow) -> DatabaseReturn {
fn textify_row(&self, row: sqlx::postgres::PgRow) -> DatabaseReturn {
// get all columns
let columns = row.columns();
@ -251,7 +249,7 @@ impl BundlesDB {
}
#[cfg(feature = "mysql")]
fn textify_row(&mut self, row: sqlx::mysql::MySqlRow) -> DatabaseReturn {
fn textify_row(&self, row: sqlx::mysql::MySqlRow) -> DatabaseReturn {
// get all columns
let columns = row.columns();
@ -288,14 +286,17 @@ impl BundlesDB {
///
/// # Arguments:
/// * `hashed` - `String` of the user's hashed ID
pub async fn get_user_by_hashed(&mut self, hashed: String) -> DefaultReturn<Option<UserState>> {
pub async fn get_user_by_hashed(&self, hashed: String) -> DefaultReturn<Option<UserState>> {
// ...
let exists_in_cache = &self.paste_cache.load(&hashed).is_some();
let paste_cache = PASTE_CACHE.lock().unwrap();
let mut auth_cache = AUTH_CACHE.lock().unwrap();
if exists_in_cache == &true {
let exists_in_cache = paste_cache.load(&hashed).is_some();
if exists_in_cache == true {
// get views
// if allow_cache is true, `selector` should ALWAYS be the custom_url since the cache stores by that, not ID
let user = &self.auth_cache.load(&hashed).unwrap();
let user = auth_cache.load(&hashed).unwrap();
// return
return DefaultReturn {
@ -343,8 +344,7 @@ impl BundlesDB {
timestamp: row.get("timestamp").unwrap().parse::<u128>().unwrap(),
};
self.auth_cache
.store(row.get("id_hashed").unwrap().to_string(), user.clone());
auth_cache.store(row.get("id_hashed").unwrap().to_string(), user.clone());
// return
return DefaultReturn {
@ -358,10 +358,7 @@ impl BundlesDB {
///
/// # Arguments:
/// * `username` - `String` of the user's username
pub async fn get_user_by_username(
&mut self,
username: String,
) -> DefaultReturn<Option<UserState>> {
pub async fn get_user_by_username(&self, username: String) -> DefaultReturn<Option<UserState>> {
let query: &str = if (self.db._type == "sqlite") | (self.db._type == "mysql") {
"SELECT * FROM \"Users\" WHERE \"username\" = ?"
} else {
@ -404,7 +401,7 @@ impl BundlesDB {
///
/// # Arguments:
/// * `username` - `String` of the user's `username`
pub async fn create_user(&mut self, username: String) -> DefaultReturn<Option<String>> {
pub async fn create_user(&self, username: String) -> DefaultReturn<Option<String>> {
// make sure user doesn't already exists
let existing = &self.get_user_by_username(username.clone()).await;
if existing.success {
@ -480,7 +477,7 @@ impl BundlesDB {
///
/// # Arguments:
/// * `id` - `String` of the log's `id`
pub async fn get_log_by_id(&mut self, id: String) -> DefaultReturn<Option<Log>> {
pub async fn get_log_by_id(&self, id: String) -> DefaultReturn<Option<Log>> {
let query: &str = if (self.db._type == "sqlite") | (self.db._type == "mysql") {
"SELECT * FROM \"Logs\" WHERE \"id\" = ?"
} else {
@ -522,7 +519,7 @@ impl BundlesDB {
/// * `logtype` - `String` of the log's `logtype`
/// * `content` - `String` of the log's `content`
pub async fn create_log(
&mut self,
&self,
logtype: String,
content: String,
) -> DefaultReturn<Option<String>> {
@ -564,7 +561,7 @@ impl BundlesDB {
/// # Arguments:
/// * `id` - `String` of the log's `id`
/// * `content` - `String` of the log's new content
pub async fn edit_log(&mut self, id: String, content: String) -> DefaultReturn<Option<String>> {
pub async fn edit_log(&self, id: String, content: String) -> DefaultReturn<Option<String>> {
// make sure log exists
let existing = &self.get_log_by_id(id.clone()).await;
if !existing.success {
@ -609,7 +606,7 @@ impl BundlesDB {
///
/// # Arguments:
/// * `id` - `String` of the log's `id`
pub async fn delete_log(&mut self, id: String) -> DefaultReturn<Option<String>> {
pub async fn delete_log(&self, id: String) -> DefaultReturn<Option<String>> {
// make sure log exists
let existing = &self.get_log_by_id(id.clone()).await;
if !existing.success {
@ -649,7 +646,7 @@ impl BundlesDB {
// pastes
/// Count the `view_paste` logs for a specific [`Paste`]
async fn count_paste_views(&mut self, custom_url: String) -> usize {
async fn count_paste_views(&self, custom_url: String) -> usize {
let c = &self.db.client;
// count views
@ -673,19 +670,20 @@ impl BundlesDB {
/// Build a [`Paste`] query with information about it
async fn build_result_from_query(
&mut self,
&self,
query: &str,
selector: &str,
allow_cache: bool,
) -> DefaultReturn<Option<Paste<String>>> {
// ...
let exists_in_cache = &self.paste_cache.load(selector).is_some();
let mut paste_cache = PASTE_CACHE.lock().unwrap();
let exists_in_cache = paste_cache.load(selector).is_some();
if (exists_in_cache == &true) && allow_cache {
if (exists_in_cache == true) && allow_cache {
// get views
// if allow_cache is true, `selector` should ALWAYS be the custom_url since the cache stores by that, not ID
let views = &self.count_paste_views(selector.to_owned()).await;
let paste = &self.paste_cache.load(selector).unwrap();
let paste = paste_cache.load(selector).unwrap();
// return
return DefaultReturn {
@ -745,8 +743,7 @@ impl BundlesDB {
};
if allow_cache {
self.paste_cache
.store(row.get("custom_url").unwrap().to_string(), paste.clone());
paste_cache.store(row.get("custom_url").unwrap().to_string(), paste.clone());
}
// return
@ -762,7 +759,7 @@ impl BundlesDB {
///
/// # Arguments:
/// * `url` - `String` of the paste's `custom_url`
pub async fn get_paste_by_url(&mut self, url: String) -> DefaultReturn<Option<Paste<String>>> {
pub async fn get_paste_by_url(&self, url: String) -> DefaultReturn<Option<Paste<String>>> {
let query: &str = if (self.db._type == "sqlite") | (self.db._type == "mysql") {
"SELECT * FROM \"Pastes\" WHERE \"custom_url\" = ?"
} else {
@ -776,7 +773,7 @@ impl BundlesDB {
///
/// # Arguments:
/// * `id` - `String` of the paste's `id`
pub async fn get_paste_by_id(&mut self, id: String) -> DefaultReturn<Option<Paste<String>>> {
pub async fn get_paste_by_id(&self, id: String) -> DefaultReturn<Option<Paste<String>>> {
let query: &str = if (self.db._type == "sqlite") | (self.db._type == "mysql") {
"SELECT * FROM \"Pastes\" WHERE \"id\" = ?"
} else {
@ -791,7 +788,7 @@ impl BundlesDB {
/// # Arguments:
/// * `owner` - `String` of the owner's `username`
pub async fn get_pastes_by_owner(
&mut self,
&self,
owner: String,
) -> DefaultReturn<Option<Vec<PasteIdentifier>>> {
let query: &str = if (self.db._type == "sqlite") | (self.db._type == "mysql") {
@ -838,7 +835,7 @@ impl BundlesDB {
/// # Arguments:
/// * `owner` - `String` of the owner's `username`
pub async fn get_atomic_pastes_by_owner(
&mut self,
&self,
owner: String,
) -> DefaultReturn<Option<Vec<PasteIdentifier>>> {
let query: &str = if (self.db._type == "sqlite") | (self.db._type == "mysql") {
@ -888,7 +885,7 @@ impl BundlesDB {
/// * `props` - [`Paste<String>`](Paste)
/// * `as_user` - The ID of the user creating the paste
pub async fn create_paste(
&mut self,
&self,
props: &mut Paste<String>,
as_user: Option<String>, // id of paste owner
) -> DefaultReturn<Option<Paste<String>>> {
@ -1064,7 +1061,7 @@ impl BundlesDB {
/// Edit an existing [`Paste`] given its `custom_url`
pub async fn edit_paste_by_url(
&mut self,
&self,
url: String,
content: String,
edit_password: String,
@ -1157,7 +1154,8 @@ impl BundlesDB {
// we're not even going to update the cache, just purge the paste from the cache
// this also means we don't have to handle any decisions on if the paste custom_url changed or not
self.paste_cache.clear(&custom_url);
let mut paste_cache = PASTE_CACHE.lock().unwrap();
paste_cache.clear(&custom_url);
// return
return DefaultReturn {
@ -1169,7 +1167,7 @@ impl BundlesDB {
/// Update a [`Paste`]'s metadata by its `custom_url`
pub async fn edit_paste_metadata_by_url(
&mut self,
&self,
url: String,
metadata: PasteMetadata,
edit_password: String,
@ -1244,7 +1242,8 @@ impl BundlesDB {
// we're not even going to update the cache, just purge the paste from the cache
// this also means we don't have to handle any decisions on if the paste custom_url changed or not
self.paste_cache.clear(&url);
let mut paste_cache = PASTE_CACHE.lock().unwrap();
paste_cache.clear(&url);
// return
return DefaultReturn {
@ -1259,7 +1258,7 @@ impl BundlesDB {
/// # Arguments:
/// * `view_as` - The username of the account that viewed the paste
pub async fn add_view_to_url(
&mut self,
&self,
url: &String,
view_as: &String, // username of account that is viewing this paste
) -> DefaultReturn<Option<String>> {
@ -1324,7 +1323,7 @@ impl BundlesDB {
/// Delete a [`Paste`] given its `custom_url` and `edit_password`
pub async fn delete_paste_by_url(
&mut self,
&self,
url: String,
edit_password: String,
delete_as: Option<String>,
@ -1413,7 +1412,8 @@ impl BundlesDB {
}
// remove from cache
self.paste_cache.clear(&url);
let mut paste_cache = PASTE_CACHE.lock().unwrap();
paste_cache.clear(&url);
// return
return DefaultReturn {
@ -1430,7 +1430,7 @@ impl BundlesDB {
///
/// # Arguments:
/// * `url` - group name
pub async fn get_group_by_name(&mut self, url: String) -> DefaultReturn<Option<Group<String>>> {
pub async fn get_group_by_name(&self, url: String) -> DefaultReturn<Option<Group<String>>> {
let query: &str = if (self.db._type == "sqlite") | (self.db._type == "mysql") {
"SELECT * FROM \"Groups\" WHERE \"name\" = ?"
} else {
@ -1468,10 +1468,7 @@ impl BundlesDB {
///
/// # Arguments:
/// * `props` - [`Group<GroupMetadata>`](Group)
pub async fn create_group(
&mut self,
props: Group<GroupMetadata>,
) -> DefaultReturn<Option<String>> {
pub async fn create_group(&self, props: Group<GroupMetadata>) -> DefaultReturn<Option<String>> {
let p: &Group<GroupMetadata> = &props; // borrowed props
// make sure group does not exist

View file

@ -16,7 +16,7 @@ impl<T> CacheStore<T> {
self.objects.insert(key, value)
}
pub fn load(&mut self, key: &str) -> Option<&T> {
pub fn load(&self, key: &str) -> Option<&T> {
self.objects.get(key)
}

View file

@ -1,5 +1,3 @@
use std::sync::Mutex;
use actix_files as fs;
use actix_web::{web, App, HttpResponse, HttpServer};
use dotenv;
@ -83,7 +81,7 @@ async fn main() -> std::io::Result<()> {
println!("Starting server at: http://localhost:{port}");
// create data
let data = web::Data::new(Mutex::new(AppData { db: db.clone() }));
let data = web::Data::new(AppData { db: db.clone() });
// serve routes
HttpServer::new(move || {

View file

@ -1,5 +1,3 @@
use std::sync::Mutex;
use actix_web::HttpRequest;
use actix_web::{get, web, HttpResponse, Responder};
@ -82,21 +80,15 @@ fn build_dashboard_renderer_with_props(props: Props) -> ServerRenderer<Dashboard
/// Available at "/d/atomic"
pub async fn dashboard_request(
req: HttpRequest,
data: web::Data<Mutex<db::bundlesdb::AppData>>,
data: web::Data<db::bundlesdb::AppData>,
) -> impl Responder {
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
// verify auth status
let token_cookie = req.cookie("__Secure-Token");
let mut set_cookie: &str = "";
let token_user = if token_cookie.is_some() {
Option::Some(
lock.db
data.db
.get_user_by_hashed(token_cookie.as_ref().unwrap().value().to_string()) // if the user is returned, that means the ID is valid
.await,
)
@ -120,7 +112,7 @@ You can create an account at: /d/auth/register",
}
// fetch pastes
let pastes = lock
let pastes = data
.db
.get_atomic_pastes_by_owner(token_user.clone().unwrap().payload.unwrap().username)
.await;
@ -191,21 +183,15 @@ fn build_new_renderer_with_props(props: NewProps) -> ServerRenderer<CreateNew> {
/// Available at "/d/atomic/new"
pub async fn new_request(
req: HttpRequest,
data: web::Data<Mutex<db::bundlesdb::AppData>>,
data: web::Data<db::bundlesdb::AppData>,
) -> impl Responder {
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
// verify auth status
let token_cookie = req.cookie("__Secure-Token");
let mut set_cookie: &str = "";
let token_user = if token_cookie.is_some() {
Option::Some(
lock.db
data.db
.get_user_by_hashed(token_cookie.as_ref().unwrap().value().to_string()) // if the user is returned, that means the ID is valid
.await,
)
@ -316,22 +302,16 @@ fn build_fs_renderer_with_props(props: FSProps) -> ServerRenderer<PasteFiles> {
/// Available at "/d/atomic/{id}"
pub async fn edit_request(
req: HttpRequest,
data: web::Data<Mutex<db::bundlesdb::AppData>>,
data: web::Data<db::bundlesdb::AppData>,
info: web::Query<EditQueryProps>,
) -> impl Responder {
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
// verify auth status
let token_cookie = req.cookie("__Secure-Token");
let mut set_cookie: &str = "";
let token_user = if token_cookie.is_some() {
Option::Some(
lock.db
data.db
.get_user_by_hashed(token_cookie.as_ref().unwrap().value().to_string()) // if the user is returned, that means the ID is valid
.await,
)
@ -356,14 +336,7 @@ You can create an account at: /d/auth/register",
// get paste
let id: String = req.match_info().get("id").unwrap().to_string();
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
let paste: bundlesdb::DefaultReturn<Option<Paste<String>>> = lock.db.get_paste_by_id(id).await;
let paste: bundlesdb::DefaultReturn<Option<Paste<String>>> = data.db.get_paste_by_id(id).await;
if paste.success == false {
let renderer = ServerRenderer::<crate::pages::errors::_404Page>::new();

View file

@ -1,5 +1,3 @@
use std::sync::Mutex;
use actix_web::HttpResponse;
use actix_web::{get, web, HttpRequest, Responder};
@ -177,22 +175,13 @@ fn build_renderer_with_props(props: Props) -> ServerRenderer<ProfileView> {
#[get("/~{username:.*}")]
/// Available at "/~{username}"
pub async fn profile_view_request(
req: HttpRequest,
data: web::Data<Mutex<AppData>>,
) -> impl Responder {
pub async fn profile_view_request(req: HttpRequest, data: web::Data<AppData>) -> impl Responder {
// get paste
let username: String = req.match_info().get("username").unwrap().to_string();
let username_c = username.clone();
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
let user: bundlesdb::DefaultReturn<Option<UserState>> =
lock.db.get_user_by_username(username).await;
data.db.get_user_by_username(username).await;
if user.success == false {
let renderer = ServerRenderer::<crate::pages::errors::_404Page>::new();
@ -212,7 +201,7 @@ pub async fn profile_view_request(
let token_user = if token_cookie.is_some() {
Option::Some(
lock.db
data.db
.get_user_by_hashed(token_cookie.as_ref().unwrap().value().to_string()) // if the user is returned, that means the ID is valid
.await,
)
@ -229,7 +218,7 @@ pub async fn profile_view_request(
// ...
let pastes_res: bundlesdb::DefaultReturn<Option<Vec<bundlesdb::PasteIdentifier>>> =
lock.db.get_pastes_by_owner(username_c.clone()).await;
data.db.get_pastes_by_owner(username_c.clone()).await;
let renderer = build_renderer_with_props(Props {
user: unwrap.clone(),

View file

@ -1,5 +1,3 @@
use std::sync::Mutex;
use actix_web::HttpRequest;
use actix_web::{get, web, HttpResponse, Responder};
@ -198,22 +196,16 @@ fn build_renderer_with_props(props: Props) -> ServerRenderer<Home> {
/// Available at "/"
pub async fn home_request(
req: HttpRequest,
data: web::Data<Mutex<db::bundlesdb::AppData>>,
data: web::Data<db::bundlesdb::AppData>,
info: web::Query<Props>,
) -> impl Responder {
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
// verify auth status
let token_cookie = req.cookie("__Secure-Token");
let mut set_cookie: &str = "";
let token_user = if token_cookie.is_some() {
Option::Some(
lock.db
data.db
.get_user_by_hashed(token_cookie.as_ref().unwrap().value().to_string()) // if the user is returned, that means the ID is valid
.await,
)
@ -232,7 +224,7 @@ pub async fn home_request(
let str: &Option<String> = &info.editing;
let paste = if str.is_some() {
Option::Some(lock.db.get_paste_by_url(str.to_owned().unwrap()).await)
Option::Some(data.db.get_paste_by_url(str.to_owned().unwrap()).await)
} else {
Option::None
};

View file

@ -1,5 +1,3 @@
use std::sync::Mutex;
use actix_web::HttpResponse;
use actix_web::{get, web, HttpRequest, Responder};
@ -130,21 +128,15 @@ pub fn build_password_ask_renderer_with_props(props: Props) -> ServerRenderer<Pa
/// Available at "/{custom_url}"
pub async fn paste_view_request(
req: HttpRequest,
data: web::Data<Mutex<AppData>>,
data: web::Data<AppData>,
info: web::Query<PasteViewProps>,
) -> impl Responder {
// get paste
let url: String = req.match_info().get("url").unwrap().to_string();
let url_c = url.clone();
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
let paste: bundlesdb::DefaultReturn<Option<Paste<String>>> =
lock.db.get_paste_by_url(url).await;
data.db.get_paste_by_url(url).await;
if paste.success == false {
let renderer = ServerRenderer::<crate::pages::errors::_404Page>::new();
@ -215,7 +207,7 @@ pub async fn paste_view_request(
let token_user = if token_cookie.is_some() {
Option::Some(
lock.db
data.db
.get_user_by_hashed(token_cookie.as_ref().unwrap().value().to_string()) // if the user is returned, that means the ID is valid
.await,
)
@ -232,7 +224,7 @@ pub async fn paste_view_request(
// count view (this will check for an existing view!)
let payload = &token_user.as_ref().unwrap().payload;
if payload.as_ref().is_some() {
lock.db
data.db
.add_view_to_url(&url_c, &payload.as_ref().unwrap().username)
.await;
}
@ -309,20 +301,14 @@ pub async fn paste_view_request(
/// Available at "/h/{custom_url}/{file_path}"
pub async fn atomic_paste_view_request(
req: HttpRequest,
data: web::Data<Mutex<AppData>>,
data: web::Data<AppData>,
) -> impl Responder {
// get paste
let url: String = req.match_info().get("url").unwrap().to_string();
let path: String = req.match_info().get("path").unwrap().to_string();
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
let paste: bundlesdb::DefaultReturn<Option<Paste<String>>> =
lock.db.get_paste_by_url(url).await;
data.db.get_paste_by_url(url).await;
if paste.success == false {
let renderer = ServerRenderer::<crate::pages::errors::_404Page>::new();

View file

@ -1,5 +1,3 @@
use std::sync::Mutex;
use actix_web::HttpResponse;
use actix_web::{get, web, HttpRequest, Responder};
@ -90,23 +88,14 @@ fn build_user_settings_with_props(props: UserSettingsProps) -> ServerRenderer<Us
#[get("/d/settings")]
/// Available at "/d/settings"
pub async fn user_settings_request(
req: HttpRequest,
data: web::Data<Mutex<AppData>>,
) -> impl Responder {
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
pub async fn user_settings_request(req: HttpRequest, data: web::Data<AppData>) -> impl Responder {
// verify auth status
let token_cookie = req.cookie("__Secure-Token");
let mut set_cookie: &str = "";
let token_user = if token_cookie.is_some() {
Option::Some(
lock.db
data.db
.get_user_by_hashed(token_cookie.as_ref().unwrap().value().to_string()) // if the user is returned, that means the ID is valid
.await,
)
@ -145,21 +134,15 @@ pub async fn user_settings_request(
/// Available at "/d/settings/paste/{custom_url}"
pub async fn paste_settings_request(
req: HttpRequest,
data: web::Data<Mutex<AppData>>,
data: web::Data<AppData>,
info: web::Query<paste_view::PasteViewProps>,
) -> impl Responder {
// get paste
let url: String = req.match_info().get("url").unwrap().to_string();
let url_c = url.clone();
let mut lock = match data.lock() {
Ok(lock) => lock,
// the poisoned guard tells us that something panicked while handling a locked guard
Err(poisoned) => poisoned.into_inner(),
};
let paste: bundlesdb::DefaultReturn<Option<Paste<String>>> =
lock.db.get_paste_by_url(url).await;
data.db.get_paste_by_url(url).await;
if paste.success == false {
return HttpResponse::NotFound().body(paste.message);
@ -171,7 +154,7 @@ pub async fn paste_settings_request(
let token_user = if token_cookie.is_some() {
Option::Some(
lock.db
data.db
.get_user_by_hashed(token_cookie.as_ref().unwrap().value().to_string()) // if the user is returned, that means the ID is valid
.await,
)