From 0a71cce2d19eab067090fab13df5f5ea584db589 Mon Sep 17 00:00:00 2001 From: "Dustin J. Mitchell" Date: Thu, 10 Jul 2025 22:10:33 -0400 Subject: [PATCH] use a struct for arguments to WebServer::new --- server/src/api/add_snapshot.rs | 12 +++++----- server/src/api/add_version.rs | 28 +++++++++++++--------- server/src/api/get_child_version.rs | 18 +++++++------- server/src/api/get_snapshot.rs | 8 +++---- server/src/api/mod.rs | 23 ++++++++++-------- server/src/bin/taskchampion-sync-server.rs | 14 +++++++---- server/src/lib.rs | 27 +++++++++++++++++---- 7 files changed, 81 insertions(+), 49 deletions(-) diff --git a/server/src/api/add_snapshot.rs b/server/src/api/add_snapshot.rs index fb088e1..da6b654 100644 --- a/server/src/api/add_snapshot.rs +++ b/server/src/api/add_snapshot.rs @@ -55,11 +55,11 @@ pub(crate) async fn service( #[cfg(test)] mod test { - use crate::api::CLIENT_ID_HEADER; use crate::WebServer; + use crate::{api::CLIENT_ID_HEADER, WebConfig}; use actix_web::{http::StatusCode, test, App}; use pretty_assertions::assert_eq; - use taskchampion_sync_server_core::{InMemoryStorage, Storage, NIL_VERSION_ID}; + use taskchampion_sync_server_core::{InMemoryStorage, ServerConfig, Storage, NIL_VERSION_ID}; use uuid::Uuid; #[actix_rt::test] @@ -76,7 +76,7 @@ mod test { txn.commit()?; } - let server = WebServer::new(Default::default(), None, true, storage); + let server = WebServer::new(ServerConfig::default(), WebConfig::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let app = test::init_service(app).await; @@ -119,7 +119,7 @@ mod test { txn.commit().unwrap(); } - let server = WebServer::new(Default::default(), None, true, storage); + let server = WebServer::new(ServerConfig::default(), WebConfig::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let app = test::init_service(app).await; @@ -149,7 +149,7 @@ mod test { let client_id = Uuid::new_v4(); let version_id = Uuid::new_v4(); let storage = InMemoryStorage::new(); - let server = WebServer::new(Default::default(), None, true, storage); + let server = WebServer::new(ServerConfig::default(), WebConfig::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let app = test::init_service(app).await; @@ -169,7 +169,7 @@ mod test { let client_id = Uuid::new_v4(); let version_id = Uuid::new_v4(); let storage = InMemoryStorage::new(); - let server = WebServer::new(Default::default(), None, true, storage); + let server = WebServer::new(ServerConfig::default(), WebConfig::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let app = test::init_service(app).await; diff --git a/server/src/api/add_version.rs b/server/src/api/add_version.rs index c07035d..7f7e57b 100644 --- a/server/src/api/add_version.rs +++ b/server/src/api/add_version.rs @@ -80,7 +80,7 @@ pub(crate) async fn service( rb.append_header((PARENT_VERSION_ID_HEADER, parent_version_id.to_string())); Ok(rb.finish()) } - Err(ServerError::NoSuchClient) if server_state.create_clients => { + Err(ServerError::NoSuchClient) if server_state.web_config.create_clients => { // Create a new client and repeat the `add_version` call. let mut txn = server_state .server @@ -97,11 +97,11 @@ pub(crate) async fn service( #[cfg(test)] mod test { - use crate::api::CLIENT_ID_HEADER; use crate::WebServer; + use crate::{api::CLIENT_ID_HEADER, WebConfig}; use actix_web::{http::StatusCode, test, App}; use pretty_assertions::assert_eq; - use taskchampion_sync_server_core::{InMemoryStorage, Storage}; + use taskchampion_sync_server_core::{InMemoryStorage, ServerConfig, Storage}; use uuid::Uuid; #[actix_rt::test] @@ -118,7 +118,7 @@ mod test { txn.commit().unwrap(); } - let server = WebServer::new(Default::default(), None, true, storage); + let server = WebServer::new(ServerConfig::default(), WebConfig::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let app = test::init_service(app).await; @@ -152,7 +152,11 @@ mod test { let client_id = Uuid::new_v4(); let version_id = Uuid::new_v4(); let parent_version_id = Uuid::new_v4(); - let server = WebServer::new(Default::default(), None, true, InMemoryStorage::new()); + let server = WebServer::new( + ServerConfig::default(), + WebConfig::default(), + InMemoryStorage::new(), + ); let app = App::new().configure(|sc| server.config(sc)); let app = test::init_service(app).await; @@ -195,9 +199,11 @@ mod test { let client_id = Uuid::new_v4(); let parent_version_id = Uuid::new_v4(); let server = WebServer::new( - Default::default(), - None, - /*create_clients=*/ false, + ServerConfig::default(), + WebConfig { + create_clients: false, + ..WebConfig::default() + }, InMemoryStorage::new(), ); let app = App::new().configure(|sc| server.config(sc)); @@ -232,7 +238,7 @@ mod test { txn.commit().unwrap(); } - let server = WebServer::new(Default::default(), None, true, storage); + let server = WebServer::new(ServerConfig::default(), WebConfig::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let app = test::init_service(app).await; @@ -260,7 +266,7 @@ mod test { let client_id = Uuid::new_v4(); let parent_version_id = Uuid::new_v4(); let storage = InMemoryStorage::new(); - let server = WebServer::new(Default::default(), None, true, storage); + let server = WebServer::new(ServerConfig::default(), WebConfig::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let app = test::init_service(app).await; @@ -280,7 +286,7 @@ mod test { let client_id = Uuid::new_v4(); let parent_version_id = Uuid::new_v4(); let storage = InMemoryStorage::new(); - let server = WebServer::new(Default::default(), None, true, storage); + let server = WebServer::new(ServerConfig::default(), WebConfig::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let app = test::init_service(app).await; diff --git a/server/src/api/get_child_version.rs b/server/src/api/get_child_version.rs index 2341582..9f21b0f 100644 --- a/server/src/api/get_child_version.rs +++ b/server/src/api/get_child_version.rs @@ -48,11 +48,11 @@ pub(crate) async fn service( #[cfg(test)] mod test { - use crate::api::CLIENT_ID_HEADER; use crate::WebServer; + use crate::{api::CLIENT_ID_HEADER, WebConfig}; use actix_web::{http::StatusCode, test, App}; use pretty_assertions::assert_eq; - use taskchampion_sync_server_core::{InMemoryStorage, Storage, NIL_VERSION_ID}; + use taskchampion_sync_server_core::{InMemoryStorage, ServerConfig, Storage, NIL_VERSION_ID}; use uuid::Uuid; #[actix_rt::test] @@ -71,11 +71,11 @@ mod test { txn.commit().unwrap(); } - let server = WebServer::new(Default::default(), None, true, storage); + let server = WebServer::new(ServerConfig::default(), WebConfig::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let app = test::init_service(app).await; - let uri = format!("/v1/client/get-child-version/{}", parent_version_id); + let uri = format!("/v1/client/get-child-version/{parent_version_id}"); let req = test::TestRequest::get() .uri(&uri) .append_header((CLIENT_ID_HEADER, client_id.to_string())) @@ -105,11 +105,11 @@ mod test { let client_id = Uuid::new_v4(); let parent_version_id = Uuid::new_v4(); let storage = InMemoryStorage::new(); - let server = WebServer::new(Default::default(), None, true, storage); + let server = WebServer::new(ServerConfig::default(), WebConfig::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let app = test::init_service(app).await; - let uri = format!("/v1/client/get-child-version/{}", parent_version_id); + let uri = format!("/v1/client/get-child-version/{parent_version_id}"); let req = test::TestRequest::get() .uri(&uri) .append_header((CLIENT_ID_HEADER, client_id.to_string())) @@ -134,12 +134,12 @@ mod test { .unwrap(); txn.commit().unwrap(); } - let server = WebServer::new(Default::default(), None, true, storage); + let server = WebServer::new(ServerConfig::default(), WebConfig::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let app = test::init_service(app).await; // the child of the nil version is the added version - let uri = format!("/v1/client/get-child-version/{}", NIL_VERSION_ID); + let uri = format!("/v1/client/get-child-version/{NIL_VERSION_ID}"); let req = test::TestRequest::get() .uri(&uri) .append_header((CLIENT_ID_HEADER, client_id.to_string())) @@ -168,7 +168,7 @@ mod test { // The child of the latest version is NOT_FOUND. The tests in crate::server test more // corner cases. - let uri = format!("/v1/client/get-child-version/{}", test_version_id); + let uri = format!("/v1/client/get-child-version/{test_version_id}"); let req = test::TestRequest::get() .uri(&uri) .append_header((CLIENT_ID_HEADER, client_id.to_string())) diff --git a/server/src/api/get_snapshot.rs b/server/src/api/get_snapshot.rs index 24d616b..d7aabdb 100644 --- a/server/src/api/get_snapshot.rs +++ b/server/src/api/get_snapshot.rs @@ -33,12 +33,12 @@ pub(crate) async fn service( #[cfg(test)] mod test { - use crate::api::CLIENT_ID_HEADER; use crate::WebServer; + use crate::{api::CLIENT_ID_HEADER, WebConfig}; use actix_web::{http::StatusCode, test, App}; use chrono::{TimeZone, Utc}; use pretty_assertions::assert_eq; - use taskchampion_sync_server_core::{InMemoryStorage, Snapshot, Storage}; + use taskchampion_sync_server_core::{InMemoryStorage, ServerConfig, Snapshot, Storage}; use uuid::Uuid; #[actix_rt::test] @@ -53,7 +53,7 @@ mod test { txn.commit().unwrap(); } - let server = WebServer::new(Default::default(), None, true, storage); + let server = WebServer::new(ServerConfig::default(), WebConfig::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let app = test::init_service(app).await; @@ -89,7 +89,7 @@ mod test { txn.commit().unwrap(); } - let server = WebServer::new(Default::default(), None, true, storage); + let server = WebServer::new(ServerConfig::default(), WebConfig::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let app = test::init_service(app).await; diff --git a/server/src/api/mod.rs b/server/src/api/mod.rs index 672e795..ec19a5b 100644 --- a/server/src/api/mod.rs +++ b/server/src/api/mod.rs @@ -1,8 +1,7 @@ -use std::collections::HashSet; - use actix_web::{error, web, HttpRequest, Result, Scope}; use taskchampion_sync_server_core::{ClientId, Server, ServerError}; -use uuid::Uuid; + +use crate::WebConfig; mod add_snapshot; mod add_version; @@ -31,8 +30,7 @@ pub(crate) const SNAPSHOT_REQUEST_HEADER: &str = "X-Snapshot-Request"; /// The type containing a reference to the persistent state for the server pub(crate) struct ServerState { pub(crate) server: Server, - pub(crate) client_id_allowlist: Option>, - pub(crate) create_clients: bool, + pub(crate) web_config: WebConfig, } impl ServerState { @@ -44,7 +42,7 @@ impl ServerState { if let Some(client_id_hdr) = req.headers().get(CLIENT_ID_HEADER) { let client_id = client_id_hdr.to_str().map_err(|_| badrequest())?; let client_id = ClientId::parse_str(client_id).map_err(|_| badrequest())?; - if let Some(allow_list) = &self.client_id_allowlist { + if let Some(allow_list) = &self.web_config.client_id_allowlist { if !allow_list.contains(&client_id) { return Err(error::ErrorForbidden("unknown x-client-id")); } @@ -81,14 +79,17 @@ fn server_error_to_actix(err: ServerError) -> actix_web::Error { mod test { use super::*; use taskchampion_sync_server_core::InMemoryStorage; + use uuid::Uuid; #[test] fn client_id_header_allow_all() { let client_id = Uuid::new_v4(); let state = ServerState { server: Server::new(Default::default(), InMemoryStorage::new()), - client_id_allowlist: None, - create_clients: true, + web_config: WebConfig { + client_id_allowlist: None, + create_clients: true, + }, }; let req = actix_web::test::TestRequest::default() .insert_header((CLIENT_ID_HEADER, client_id.to_string())) @@ -102,8 +103,10 @@ mod test { let client_id_disallowed = Uuid::new_v4(); let state = ServerState { server: Server::new(Default::default(), InMemoryStorage::new()), - client_id_allowlist: Some([client_id_ok].into()), - create_clients: true, + web_config: WebConfig { + client_id_allowlist: Some([client_id_ok].into()), + create_clients: true, + }, }; let req = actix_web::test::TestRequest::default() .insert_header((CLIENT_ID_HEADER, client_id_ok.to_string())) diff --git a/server/src/bin/taskchampion-sync-server.rs b/server/src/bin/taskchampion-sync-server.rs index fc3b3de..bc59d01 100644 --- a/server/src/bin/taskchampion-sync-server.rs +++ b/server/src/bin/taskchampion-sync-server.rs @@ -8,7 +8,7 @@ use actix_web::{ }; use clap::{arg, builder::ValueParser, value_parser, ArgAction, Command}; use std::{collections::HashSet, ffi::OsString}; -use taskchampion_sync_server::WebServer; +use taskchampion_sync_server::{WebConfig, WebServer}; use taskchampion_sync_server_core::ServerConfig; use taskchampion_sync_server_storage_sqlite::SqliteStorage; use uuid::Uuid; @@ -111,8 +111,10 @@ async fn main() -> anyhow::Result<()> { }; let server = WebServer::new( config, - server_args.client_id_allowlist, - server_args.create_clients, + WebConfig { + client_id_allowlist: server_args.client_id_allowlist, + create_clients: server_args.create_clients, + }, SqliteStorage::new(server_args.data_dir)?, ); @@ -364,7 +366,11 @@ mod test { #[actix_rt::test] async fn test_index_get() { - let server = WebServer::new(Default::default(), None, true, InMemoryStorage::new()); + let server = WebServer::new( + ServerConfig::default(), + WebConfig::default(), + InMemoryStorage::new(), + ); let app = App::new().configure(|sc| server.config(sc)); let app = actix_web::test::init_service(app).await; diff --git a/server/src/lib.rs b/server/src/lib.rs index 20aa55d..46cded5 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -19,19 +19,32 @@ pub struct WebServer { server_state: Arc, } +/// Configuration for WebServer (as distinct from [`ServerConfig`]). +pub struct WebConfig { + pub client_id_allowlist: Option>, + pub create_clients: bool, +} + +impl Default for WebConfig { + fn default() -> Self { + Self { + client_id_allowlist: Default::default(), + create_clients: true, + } + } +} + impl WebServer { /// Create a new sync server with the given storage implementation. pub fn new( config: ServerConfig, - client_id_allowlist: Option>, - create_clients: bool, + web_config: WebConfig, storage: ST, ) -> Self { Self { server_state: Arc::new(ServerState { server: Server::new(config, storage), - client_id_allowlist, - create_clients, + web_config, }), } } @@ -59,7 +72,11 @@ mod test { #[actix_rt::test] async fn test_cache_control() { - let server = WebServer::new(Default::default(), None, true, InMemoryStorage::new()); + let server = WebServer::new( + ServerConfig::default(), + WebConfig::default(), + InMemoryStorage::new(), + ); let app = App::new().configure(|sc| server.config(sc)); let app = test::init_service(app).await;