From b4d42113aaf944d8dfd5df8cb5311f08955233ac Mon Sep 17 00:00:00 2001 From: Ninjdai Date: Thu, 7 Aug 2025 21:28:15 +0200 Subject: [PATCH 1/2] feat: more CLI config options: port, token expiry time --- src/main.rs | 32 ++++++++++++++++++++++---------- src/routes/auth.rs | 9 ++++++--- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index 8af7fbb..10e35eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use std::{net::SocketAddr, path::PathBuf, sync::{Arc, LazyLock}}; +use std::{net::{Ipv4Addr, SocketAddr}, path::PathBuf, sync::{Arc, LazyLock}}; use axum::{extract::State, http::HeaderMap, middleware, routing::get}; use clap::{Parser, Subcommand}; @@ -21,7 +21,8 @@ pub mod routes; #[command(version = "1.0")] #[command(about = "BAL management server", long_about = None)] struct Cli { - #[arg(long, short, value_name = "FILE")] + /// Path to the sqlite database [default: ./alexandria.db] + #[arg(long, short, global = true, value_name = "FILE")] database: Option, #[command(subcommand)] @@ -30,7 +31,16 @@ struct Cli { #[derive(Subcommand)] enum Commands { - Run, + /// Serves the web server + Run { + /// Port on which to serve the web server + #[arg(short, long, default_value_t = 3000)] + port: u16, + /// How many seconds generated JWTs are valid for. Default equates to 6 months + #[arg(long, default_value_t = 15_778_476)] + token_expiration_time: u64, + }, + /// Open a TUI to manage user accounts User } @@ -59,13 +69,15 @@ static KEYS: LazyLock = LazyLock::new(|| { Keys::new(secret.as_bytes()) }); +static CLI: LazyLock = LazyLock::new(|| { + Cli::parse() +}); + #[tokio::main] async fn main() { pretty_env_logger::init(); - let cli = Cli::parse(); - - let db_path = match cli.database { + let db_path = match &CLI.database { Some(path) => { if path.is_dir() { log::error!("{path:?} is a directory"); @@ -112,13 +124,13 @@ async fn main() { return; } - match cli.command { - Commands::Run => run_server(db).await, + match &CLI.command { + Commands::Run {port,..} => run_server(db, *port).await, Commands::User => utils::cli::manage_users(db).await } } -async fn run_server(db: Arc) { +async fn run_server(db: Arc, port: u16) { let (event_bus, _) = broadcast::channel(16); if std::env::var("JWT_SECRET").is_err() { @@ -217,7 +229,7 @@ async fn run_server(db: Arc) { let router = router.merge(swagger); - let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); + let listener = tokio::net::TcpListener::bind(SocketAddr::new(std::net::IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), port)).await.unwrap(); log::info!("Running on http://{}", listener.local_addr().unwrap()); axum::serve( listener, diff --git a/src/routes/auth.rs b/src/routes/auth.rs index f972682..8cbe842 100644 --- a/src/routes/auth.rs +++ b/src/routes/auth.rs @@ -7,9 +7,9 @@ use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; use serde::{Deserialize, Serialize}; use serde_json::json; -use crate::{entities::user, AppState, KEYS}; +use crate::{entities::user, AppState, Commands, CLI, KEYS}; -const TOKEN_EXPIRY_TIME: u64 = 15_778_476; // 6 Months +//const TOKEN_EXPIRY_TIME: u64 = 15_778_476; // 6 Months pub async fn auth_middleware( _claims: Claims, @@ -49,7 +49,10 @@ pub async fn auth(State(state): State>, Json(payload): Json token_expiration_time, + _ => panic!("The auth endpoint cannot be used outside of a Run command") + }, user_id: user.id }; let token = encode(&Header::default(), &claims, &KEYS.encoding) From 88aaf3d0d66966f093b515ed7bc1f5f499319f08 Mon Sep 17 00:00:00 2001 From: Ninjdai Date: Thu, 7 Aug 2025 21:43:37 +0200 Subject: [PATCH 2/2] feat: make API available at /api instead of at root of the server --- src/main.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 10e35eb..7595d37 100644 --- a/src/main.rs +++ b/src/main.rs @@ -171,7 +171,7 @@ async fn run_server(db: Arc, port: u16) { } } - let (router, mut api) = OpenApiRouter::new() + let open_api_router = OpenApiRouter::new() // Book API .routes(routes!(routes::book::get_book_by_ean)) .routes(routes!(routes::book::get_book_by_id)) @@ -200,8 +200,12 @@ async fn run_server(db: Arc, port: u16) { .routes(routes!(routes::auth::check_token)) // Misc .routes(routes!(routes::websocket::ws_handler)) - .route("/", get(index)) + .with_state(shared_state.clone()); + + let (router, mut api) = OpenApiRouter::new() + .nest("/api", open_api_router) + .route("/", get(index)) // temporary index page, will redirect/proxy to flutter app .with_state(shared_state) .split_for_parts();