From 1d400ce38bfa07abd4f6f212da98fdddb1e6cca3 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Tue, 24 Dec 2024 14:37:37 -0500 Subject: [PATCH] Start wrapping routes into standalone functions --- visions/server/src/database.rs | 3 +- visions/server/src/filters/mod.rs | 125 ++++++++++++++++ visions/server/src/filters/user_management.rs | 39 +++++ visions/server/src/handlers.rs | 17 +++ visions/server/src/main.rs | 138 ++---------------- 5 files changed, 195 insertions(+), 127 deletions(-) create mode 100644 visions/server/src/filters/mod.rs create mode 100644 visions/server/src/filters/user_management.rs diff --git a/visions/server/src/database.rs b/visions/server/src/database.rs index 9e3502e..b85df30 100644 --- a/visions/server/src/database.rs +++ b/visions/server/src/database.rs @@ -668,6 +668,7 @@ mod test { use std::path::PathBuf; use cool_asserts::assert_matches; + use result_extended::ResultExt; use super::*; @@ -700,7 +701,7 @@ mod test { assert_matches!( conn.character(CharacterId::from("1")).await, - ResultExt::Ok(None) + Ok(None) ); } } diff --git a/visions/server/src/filters/mod.rs b/visions/server/src/filters/mod.rs new file mode 100644 index 0000000..adf876d --- /dev/null +++ b/visions/server/src/filters/mod.rs @@ -0,0 +1,125 @@ +mod user_management; +pub use user_management::routes_user_management; + +use warp::{ + filters::cors::Builder, + http::{header::CONTENT_TYPE, HeaderName, Method, Response}, + reply::*, + Filter, +}; + +use crate::{ + asset_db::AssetId, core::Core, handlers::{handle_auth, handle_available_images, handle_connect_websocket, handle_file, handle_get_charsheet, handle_get_users, handle_register_client, handle_server_status, handle_set_admin_password, handle_set_background_image, handle_unregister_client, RegisterRequest} +}; + +fn cors(methods: Vec, headers: Vec) -> Builder +where + M: Into, + H: Into, +{ + warp::cors() + .allow_credentials(true) + .allow_methods(methods) + .allow_headers(headers) +} + +pub fn route_server_status( + core: Core, +) -> impl Filter + Clone { + warp::path!("api" / "v1" / "status") + .and(warp::get()) + .then(move || handle_server_status(core.clone())) +} + +pub fn route_set_bg_image( + core: Core, +) -> impl Filter + Clone { + warp::path!("api" / "v1" / "tabletop" / "bg_image") + .and(warp::put()) + .and(warp::body::json()) + .then({ + let core = core.clone(); + move |body| handle_set_background_image(core.clone(), body) + }) + .with(cors::(vec![Method::PUT], vec![])) +} + + +pub fn route_image( + core: Core, +) -> impl Filter + Clone { + warp::path!("api" / "v1" / "image" / String) + .and(warp::get()) + .then({ + let core = core.clone(); + move |file_name| handle_file(core.clone(), AssetId::from(file_name)) + }) +} + +pub fn route_available_images( + core: Core, +) -> impl Filter + Clone { + warp::path!("api" / "v1" / "image").and(warp::get()).then({ + let core = core.clone(); + move || handle_available_images(core.clone()) + }) +} + +pub fn route_register_client( + core: Core, +) -> impl Filter + Clone { + warp::path!("api" / "v1" / "client") + .and(warp::post()) + .then({ + let core = core.clone(); + move || handle_register_client(core.clone(), RegisterRequest {}) + }) +} + + +pub fn route_unregister_client( + core: Core, +) -> impl Filter + Clone { + warp::path!("api" / "v1" / "client" / String) + .and(warp::delete()) + .then({ + let core = core.clone(); + move |client_id| handle_unregister_client(core.clone(), client_id) + }) +} + +pub fn route_websocket( + core: Core, +) -> impl Filter + Clone { + warp::path("ws") + .and(warp::ws()) + .and(warp::path::param()) + .then({ + let core = core.clone(); + move |ws, client_id| handle_connect_websocket(core.clone(), ws, client_id) + }) +} + +pub fn route_get_charsheet( + core: Core, +) -> impl Filter + Clone { + warp::path!("api" / "v1" / "charsheet" / String) + .and(warp::get()) + .then({ + let core = core.clone(); + move |charid| handle_get_charsheet(core.clone(), charid) + }) +} + +pub fn route_check_password( + core: Core, +) -> impl Filter + Clone { + warp::path!("api" / "v1" / "auth") + .and(warp::put()) + .and(warp::body::json()) + .then({ + let core = core.clone(); + move |body| handle_auth(core.clone(), body) + }) +} + diff --git a/visions/server/src/filters/user_management.rs b/visions/server/src/filters/user_management.rs new file mode 100644 index 0000000..7353c21 --- /dev/null +++ b/visions/server/src/filters/user_management.rs @@ -0,0 +1,39 @@ +use warp::{ + http::{header::CONTENT_TYPE, Method}, + reply::Reply, + Filter, +}; + +use crate::{ + core::Core, + handlers::{handle_get_users, handle_set_admin_password}, +}; + +use super::cors; + +fn route_get_users( + core: Core, +) -> impl Filter + Clone { + warp::path!("api" / "v1" / "users") + .and(warp::get()) + .then(move || handle_get_users(core.clone())) +} + +fn route_set_admin_password( + core: Core, +) -> impl Filter + Clone { + warp::path!("api" / "v1" / "admin_password") + .and(warp::put()) + .and(warp::body::json()) + .then({ + let core = core.clone(); + move |body| handle_set_admin_password(core.clone(), body) + }) + .with(cors(vec![Method::PUT], vec![CONTENT_TYPE])) +} + +pub fn routes_user_management( + core: Core, +) -> impl Filter + Clone { + route_get_users(core.clone()).or(route_set_admin_password(core.clone())) +} diff --git a/visions/server/src/handlers.rs b/visions/server/src/handlers.rs index a3a3754..34145e4 100644 --- a/visions/server/src/handlers.rs +++ b/visions/server/src/handlers.rs @@ -262,6 +262,7 @@ pub async fn handle_set_admin_password(core: Core, password: String) -> impl Rep pub struct AuthRequest { username: String, password: String, + } pub async fn handle_auth(core: Core, auth_request: AuthRequest) -> impl Reply { @@ -277,3 +278,19 @@ pub async fn handle_auth(core: Core, auth_request: AuthRequest) -> impl Reply { .unwrap()) }).await } + +#[cfg(test)] +mod test { + use std::path::PathBuf; + + use crate::{asset_db::mocks::MemoryAssets, database::DbConn}; + + use super::*; + + fn setup() -> Core { + let asset_store = MemoryAssets::new(vec![]); + let memory_file: Option = None; + let db = DbConn::new(memory_file); + Core::new(asset_store, db) + } +} diff --git a/visions/server/src/main.rs b/visions/server/src/main.rs index f4e4fa4..9219215 100644 --- a/visions/server/src/main.rs +++ b/visions/server/src/main.rs @@ -7,6 +7,7 @@ use std::{ use asset_db::{AssetId, FsAssets}; use authdb::AuthError; use database::DbConn; +use filters::{route_available_images, route_check_password, route_get_charsheet, route_image, route_register_client, route_server_status, route_set_bg_image, route_unregister_client, route_websocket, routes_user_management}; use handlers::{ handle_auth, handle_available_images, handle_connect_websocket, handle_file, handle_get_charsheet, handle_get_users, handle_register_client, handle_server_status, @@ -26,6 +27,7 @@ mod core; mod database; mod handlers; mod types; +mod filters; #[derive(Debug)] struct Unauthorized; @@ -109,133 +111,17 @@ pub async fn main() { let core = core::Core::new(FsAssets::new(PathBuf::from("/home/savanni/Pictures")), conn); - let route_server_status = warp::path!("api" / "v1" / "status").and(warp::get()).then({ - let core = core.clone(); - move || handle_server_status(core.clone()) - }); - let route_image = warp::path!("api" / "v1" / "image" / String) - .and(warp::get()) - .then({ - let core = core.clone(); - move |file_name| handle_file(core.clone(), AssetId::from(file_name)) - }); - - let route_available_images = warp::path!("api" / "v1" / "image").and(warp::get()).then({ - let core = core.clone(); - move || handle_available_images(core.clone()) - }); - - let route_register_client = warp::path!("api" / "v1" / "client") - .and(warp::post()) - .then({ - let core = core.clone(); - move || handle_register_client(core.clone(), RegisterRequest {}) - }); - - let route_unregister_client = warp::path!("api" / "v1" / "client" / String) - .and(warp::delete()) - .then({ - let core = core.clone(); - move |client_id| handle_unregister_client(core.clone(), client_id) - }); - - let route_websocket = warp::path("ws") - .and(warp::ws()) - .and(warp::path::param()) - .then({ - let core = core.clone(); - move |ws, client_id| handle_connect_websocket(core.clone(), ws, client_id) - }); - - let route_set_bg_image_options = warp::path!("api" / "v1" / "tabletop" / "bg_image") - .and(warp::options()) - .map({ - move || { - Response::builder() - .header("Access-Control-Allow-Origin", "*") - .header("Access-Control-Allow-Methods", "PUT") - .header("Access-Control-Allow-Headers", "content-type") - .header("Content-Type", "application/json") - .body("") - .unwrap() - } - }); - let route_set_bg_image = warp::path!("api" / "v1" / "tabletop" / "bg_image") - .and(warp::put()) - .and(warp::body::json()) - .then({ - let core = core.clone(); - move |body| handle_set_background_image(core.clone(), body) - }); - - let route_get_users = warp::path!("api" / "v1" / "users").and(warp::get()).then({ - let core = core.clone(); - move || handle_get_users(core.clone()) - }); - - let route_get_charsheet = warp::path!("api" / "v1" / "charsheet" / String) - .and(warp::get()) - .then({ - let core = core.clone(); - move |charid| handle_get_charsheet(core.clone(), charid) - }); - - let route_set_admin_password_options = warp::path!("api" / "v1" / "admin_password") - .and(warp::options()) - .map({ - move || { - Response::builder() - .header("Access-Control-Allow-Origin", "*") - .header("Access-Control-Allow-Methods", "PUT") - .header("Access-Control-Allow-Headers", "content-type") - .header("Content-Type", "application/json") - .body("") - .unwrap() - } - }); - let route_set_admin_password = warp::path!("api" / "v1" / "admin_password") - .and(warp::put()) - .and(warp::body::json()) - .then({ - let core = core.clone(); - move |body| handle_set_admin_password(core.clone(), body) - }); - - let route_check_password_options = warp::path!("api" / "v1" / "auth") - .and(warp::options()) - .map({ - move || { - Response::builder() - .header("Access-Control-Allow-Origin", "*") - .header("Access-Control-Allow-Methods", "PUT") - .header("Access-Control-Allow-Headers", "content-type") - .body("") - .unwrap() - } - }); - let route_check_password = warp::path!("api" / "v1" / "auth") - .and(warp::put()) - .and(warp::body::json()) - .then({ - let core = core.clone(); - move |body| handle_auth(core.clone(), body) - }); - - let filter = route_server_status - .or(route_register_client) - .or(route_unregister_client) - .or(route_websocket) - .or(route_image) - .or(route_available_images) - .or(route_set_bg_image_options) - .or(route_set_bg_image) - .or(route_get_users) - .or(route_get_charsheet) - .or(route_set_admin_password_options) - .or(route_set_admin_password) - .or(route_check_password_options) - .or(route_check_password) + let filter = route_server_status(core.clone()) + .or(route_register_client(core.clone())) + .or(route_unregister_client(core.clone())) + .or(route_websocket(core.clone())) + .or(route_image(core.clone())) + .or(route_available_images(core.clone())) + .or(route_set_bg_image(core.clone())) + .or(routes_user_management(core.clone())) + .or(route_get_charsheet(core.clone())) + .or(route_check_password(core.clone())) .with(warp::log("visions")) .recover(handle_rejection);