From e9fbe574e4651b24970e4a62e85ce1ef58e2f778 Mon Sep 17 00:00:00 2001 From: Karcsesz Date: Wed, 14 Feb 2024 19:48:08 +0100 Subject: [PATCH] Cargo fmt and making clippy happy --- src/args_parser.rs | 22 ++++---- src/editor/commands.rs | 2 +- src/editor/commands/editor.rs | 9 +-- src/editor/commands/fetch.rs | 30 ++++++---- src/editor/commands/query.rs | 4 +- src/editor/finger_remote.rs | 44 ++++++++------- src/editor/mod.rs | 2 +- src/editor/open_in_editor.rs | 25 +++++---- src/editor/try_reload_server.rs | 23 +++++--- src/main.rs | 50 +++++++++++------ src/schema/lookup_handler.rs | 64 ++++++++++++++-------- src/schema/mod.rs | 2 +- src/schema/resource.rs | 23 ++++---- src/schema/resource_list.rs | 46 ++++++++++------ src/server/mod.rs | 97 +++++++++++++++++++++++---------- 15 files changed, 277 insertions(+), 166 deletions(-) diff --git a/src/args_parser.rs b/src/args_parser.rs index e0d4103..d743397 100644 --- a/src/args_parser.rs +++ b/src/args_parser.rs @@ -1,6 +1,6 @@ +use clap::{Args, Parser, Subcommand, ValueEnum}; use std::net::IpAddr; use std::path::PathBuf; -use clap::{Args, Parser, Subcommand, ValueEnum}; use tracing::Level; #[derive(Debug, Parser)] @@ -11,7 +11,7 @@ pub struct MainCommand { #[command(flatten)] pub data_paths: DataPaths, #[command(subcommand)] - pub run_mode: Command + pub run_mode: Command, } impl MainCommand { pub fn log_level(&self) -> Level { @@ -20,7 +20,7 @@ impl MainCommand { LoggingLevel::Debug => Level::DEBUG, LoggingLevel::Info => Level::INFO, LoggingLevel::Warning => Level::WARN, - LoggingLevel::Error => Level::ERROR + LoggingLevel::Error => Level::ERROR, } } } @@ -33,14 +33,13 @@ pub struct DataPaths { pub pid_file_path: PathBuf, } - #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, ValueEnum)] pub enum LoggingLevel { Trace, Debug, Info, Warning, - Error + Error, } #[derive(Debug, Clone, Args)] @@ -56,7 +55,7 @@ pub struct ServerParameters { pub force_pid: bool, /// Limits how many rel parameters will be processed in a single query #[arg(long, default_value = "10")] - pub max_allowed_rels_in_request: usize + pub max_allowed_rels_in_request: usize, } #[derive(Debug, Args)] @@ -73,7 +72,7 @@ pub struct SaveSettings { #[derive(Debug, Subcommand)] pub enum Command { /// Serve the database - Serve (ServerParameters), + Serve(ServerParameters), /// Fetch one or multiple handles from Fediverse-compatible software Fetch { #[command(flatten)] @@ -92,7 +91,7 @@ pub enum Command { /// Runs a single query against the database and returns the Resource associated with the value Query { /// The resource to query for - resource: String + resource: String, }, /// Open the resource in your system editor Editor { @@ -102,7 +101,7 @@ pub enum Command { resource: String, #[command(flatten)] server_reload: ServerReloadOptions, - } + }, } #[derive(ValueEnum, Debug, Eq, PartialEq, Copy, Clone)] @@ -115,8 +114,7 @@ pub enum CollisionHandling { /// Only overwrites if there's just a single resource the new item collides with OverwriteSingleSkipMultiple, /// Overwrites every already existing resource that the new item collides with - OverwriteMultiple - //TODO: Handlers to remove only the offending aliases, not the whole record? + OverwriteMultiple, //TODO: Handlers to remove only the offending aliases, not the whole record? } #[derive(Args, Debug)] @@ -124,4 +122,4 @@ pub struct ServerReloadOptions { /// Set this flag for the application to attempt to reload the running server process automaticallys #[arg(long, short = 'r')] pub reload_server: bool, -} \ No newline at end of file +} diff --git a/src/editor/commands.rs b/src/editor/commands.rs index 45bbe79..f83e586 100644 --- a/src/editor/commands.rs +++ b/src/editor/commands.rs @@ -1,3 +1,3 @@ +pub mod editor; pub mod fetch; pub mod query; -pub mod editor; diff --git a/src/editor/commands/editor.rs b/src/editor/commands/editor.rs index 8ab43af..431c5c4 100644 --- a/src/editor/commands/editor.rs +++ b/src/editor/commands/editor.rs @@ -1,11 +1,12 @@ -use std::path::PathBuf; use crate::args_parser::SaveSettings; use crate::editor::open_in_editor::open_resource_in_editor; use crate::schema::lookup_handler::LookupHandler; +use std::path::PathBuf; -pub fn editor(database_path: PathBuf, save_settings: SaveSettings, resource: String) { +pub fn editor(database_path: PathBuf, save_settings: SaveSettings, resource: String) { let resources = LookupHandler::load(&database_path).unwrap(); - let (index, resource) = resources.lookup_with_index(resource.as_str()) + let (index, resource) = resources + .lookup_with_index(resource.as_str()) .expect("Couldn't find a resource for that query"); let resource = open_resource_in_editor(resource).unwrap(); if save_settings.save { @@ -13,4 +14,4 @@ pub fn editor(database_path: PathBuf, save_settings: SaveSettings, resource: St resources.0[index] = resource; resources.save(database_path).unwrap(); } -} \ No newline at end of file +} diff --git a/src/editor/commands/fetch.rs b/src/editor/commands/fetch.rs index ac75c8f..79083d0 100644 --- a/src/editor/commands/fetch.rs +++ b/src/editor/commands/fetch.rs @@ -1,12 +1,18 @@ +use crate::args_parser::SaveSettings; +use crate::editor::finger_remote::finger_many_fedi; +use crate::schema::resource_list::ResourceList; use std::io::{BufRead, BufReader}; use std::path::PathBuf; use tracing::{debug, error, info, instrument, trace, warn}; -use crate::args_parser::{DataPaths, SaveSettings}; -use crate::editor::finger_remote::finger_many_fedi; -use crate::schema::resource_list::ResourceList; #[instrument(skip_all)] -pub fn fetch(database_path: PathBuf, save_settings: SaveSettings, handles: impl Iterator, handles_are_files: bool, new_domain: Option) { +pub fn fetch( + database_path: PathBuf, + save_settings: SaveSettings, + handles: impl Iterator, + handles_are_files: bool, + new_domain: Option, +) { let handles = handles.flat_map(|handle| { if handles_are_files { match std::fs::File::open(&handle) { @@ -26,7 +32,9 @@ pub fn fetch(database_path: PathBuf, save_settings: SaveSettings, handles: impl vec![] } } - } else {vec![handle]} + } else { + vec![handle] + } }); let new_resources = finger_many_fedi(handles).map(|mut new_resource| { info!("Fetched {}", new_resource.subject); @@ -36,15 +44,17 @@ pub fn fetch(database_path: PathBuf, save_settings: SaveSettings, handles: impl let (start, old_domain) = match current_subject.rsplit_once('@') { None => { warn!("Failed to parse the domain of {current_subject}, storing as-is."); - return new_resource - }, - Some(data) => data + return new_resource; + } + Some(data) => data, }; debug!("Replacing {old_domain} with {new_domain}"); new_resource.add_new_primary_subject(format!("{start}@{new_domain}")); trace!("{new_resource:?}"); new_resource - } else { new_resource } + } else { + new_resource + } }); if save_settings.save { let mut resource_list = ResourceList::load(&database_path).unwrap(); @@ -55,4 +65,4 @@ pub fn fetch(database_path: PathBuf, save_settings: SaveSettings, handles: impl println!("{resource}") } } -} \ No newline at end of file +} diff --git a/src/editor/commands/query.rs b/src/editor/commands/query.rs index a68dfca..eae225b 100644 --- a/src/editor/commands/query.rs +++ b/src/editor/commands/query.rs @@ -1,10 +1,10 @@ +use crate::schema::lookup_handler::LookupHandler; use std::io::stdout; use std::path::PathBuf; -use crate::schema::lookup_handler::LookupHandler; pub fn query(database_path: PathBuf, handle: String) { let data = LookupHandler::load(database_path).unwrap(); let resource = data.lookup(handle.trim()).unwrap(); serde_json::to_writer_pretty(stdout(), resource).unwrap(); println!() -} \ No newline at end of file +} diff --git a/src/editor/finger_remote.rs b/src/editor/finger_remote.rs index 097272f..0b0511e 100644 --- a/src/editor/finger_remote.rs +++ b/src/editor/finger_remote.rs @@ -1,10 +1,10 @@ -use std::fmt::Display; -use reqwest::blocking::Client; -use reqwest::Url; -use thiserror::Error; -use tracing::{debug, error, instrument}; use crate::editor::finger_remote::FediFingerError::UrlBuildFailed; use crate::schema::resource::Resource; +use reqwest::blocking::Client; +use reqwest::Url; +use std::fmt::Display; +use thiserror::Error; +use tracing::{debug, error, instrument}; /// Error type returned by `finger_url` #[derive(Debug, Error)] @@ -23,8 +23,7 @@ pub enum FingerError { pub fn finger_url(client: &Client, url: Url) -> Result { use FingerError::*; debug!("Fingering {url}..."); - let request = client.get(url) - .build().map_err(RequestBuildFailed)?; + let request = client.get(url).build().map_err(RequestBuildFailed)?; let response = client.execute(request).map_err(RequestFailed)?; debug!("Received response: {response:?}"); let response = response.json::().map_err(ParseFailed)?; @@ -40,7 +39,7 @@ pub enum FediFingerError { #[error("Failed to build request URL")] UrlBuildFailed, #[error("Failed to run WebFinger request: {0}")] - FingerFailed(#[from] FingerError) + FingerFailed(#[from] FingerError), } /// Finger a Fediverse compatible handle @@ -49,27 +48,32 @@ pub enum FediFingerError { #[instrument(skip(client))] pub fn finger_fedi(client: &Client, handle: &str) -> Result { let handle = handle.strip_prefix('@').unwrap_or(handle); - let (_account, domain) = handle.split_once('@').ok_or(FediFingerError::MissingMiddleAt)?; + let (_account, domain) = handle + .split_once('@') + .ok_or(FediFingerError::MissingMiddleAt)?; let account = format!("acct:{handle}"); - let url = Url::parse(format!("https://{domain}/.well-known/webfinger?resource={account}").as_str()).map_err(|_e| UrlBuildFailed)?; + let url = + Url::parse(format!("https://{domain}/.well-known/webfinger?resource={account}").as_str()) + .map_err(|_e| UrlBuildFailed)?; Ok(finger_url(client, url)?) } /// Finger multiple Fediverse compatible handles /// /// Runs `finger_fedi` on the provided list of handles. If any requests fail, prints an error and continues. -pub fn finger_many_fedi(handles: impl Iterator + Display>) -> impl Iterator { +pub fn finger_many_fedi( + handles: impl Iterator + Display>, +) -> impl Iterator { let client = Client::builder() .user_agent(concat!("Fingerlink/", env!("CARGO_PKG_VERSION"))) - .build().unwrap(); //Safety: setting user_agent can't cause an error. - handles.filter_map(move |handle| { - match finger_fedi(&client, handle.as_ref()) { - Err(e) => { - error!("Failed to finger {handle}: {e}"); - None - } - Ok(data) => Some(data) + .build() + .unwrap(); //Safety: setting user_agent can't cause an error. + handles.filter_map(move |handle| match finger_fedi(&client, handle.as_ref()) { + Err(e) => { + error!("Failed to finger {handle}: {e}"); + None } + Ok(data) => Some(data), }) -} \ No newline at end of file +} diff --git a/src/editor/mod.rs b/src/editor/mod.rs index 4652316..8f9523e 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -1,4 +1,4 @@ +pub mod commands; pub mod finger_remote; pub mod open_in_editor; pub mod try_reload_server; -pub mod commands; \ No newline at end of file diff --git a/src/editor/open_in_editor.rs b/src/editor/open_in_editor.rs index af262eb..5693f93 100644 --- a/src/editor/open_in_editor.rs +++ b/src/editor/open_in_editor.rs @@ -1,10 +1,10 @@ +use crate::schema::resource::Resource; use std::fmt::{Debug, Display}; use std::io::{Read, Seek, SeekFrom, Write}; use std::process::Command; use tempfile::NamedTempFile; use thiserror::Error; use tracing::{debug, instrument, trace}; -use crate::schema::resource::Resource; /// Error type returned by `spawn_editor` #[derive(Debug, Error)] @@ -40,23 +40,28 @@ pub fn spawn_editor(buffer: impl AsRef + Display) -> Result {/*All good*/} - None | Some(_) => {return Err(EditorExitCode)} + Some(0) => { /*All good*/ } + None | Some(_) => return Err(EditorExitCode), } - temp_file.seek(SeekFrom::Start(0)).map_err(BufferSeekFailed)?; + temp_file + .seek(SeekFrom::Start(0)) + .map_err(BufferSeekFailed)?; let mut buffer = Default::default(); - temp_file.read_to_string(&mut buffer).map_err(BufferReadbackFailed)?; + temp_file + .read_to_string(&mut buffer) + .map_err(BufferReadbackFailed)?; trace!("Read back buffer: {buffer}"); Ok(buffer) } @@ -69,7 +74,7 @@ pub enum ResourceEditingError { #[error("Downstream editor spawn failed: {0}")] EditorSpawnError(#[from] EditorSpawnError), #[error("Failed to parse edited JSON")] - ParseFailed(serde_json::Error) + ParseFailed(serde_json::Error), } /// Opens the provided `resource` in the system editor and returns the edited version or an error if something goes wrong. @@ -79,4 +84,4 @@ pub fn open_resource_in_editor(resource: &Resource) -> Result Result { use ServerReloadError::*; if !pid_file_path.exists() { - return Err(PIDFileNotFound(pid_file_path.to_string_lossy().to_string())) + return Err(PIDFileNotFound(pid_file_path.to_string_lossy().to_string())); } let mut file = std::fs::File::open(pid_file_path).map_err(FailedToOpenPIDFile)?; let mut buffer = Default::default(); - file.read_to_string(&mut buffer).map_err(FailedToReadPIDFile)?; + file.read_to_string(&mut buffer) + .map_err(FailedToReadPIDFile)?; let pid = FromStr::from_str(buffer.trim())?; Ok(Pid::from_raw(pid)) } @@ -43,8 +44,12 @@ pub fn reload(pid_file_path: PathBuf, options: ServerReloadOptions) { if options.reload_server { info!("Attempting to reload server..."); match try_reload_server(pid_file_path.as_path()) { - Ok(_) => {info!("Server reloading!")} - Err(e) => {error!("Failed to reload server: {e}")} + Ok(_) => { + info!("Server reloading!") + } + Err(e) => { + error!("Failed to reload server: {e}") + } } } -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index d3fb7f2..623dca8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,20 +1,17 @@ -use clap::{Parser}; -use tracing::info; -use tracing_subscriber::util::SubscriberInitExt; use crate::args_parser::Command; -use crate::editor::open_in_editor::open_resource_in_editor; -use editor::commands::fetch::fetch; -use editor::commands::query::query; use crate::editor::commands::editor::editor; use crate::editor::try_reload_server::reload; -use crate::schema::lookup_handler::LookupHandler; +use clap::Parser; +use editor::commands::fetch::fetch; +use editor::commands::query::query; +use tracing_subscriber::util::SubscriberInitExt; -mod schema; +mod args_parser; #[cfg(feature = "editor")] mod editor; +mod schema; #[cfg(feature = "server")] mod server; -mod args_parser; #[cfg(all(not(feature = "editor"), not(feature = "server")))] compile_error!("Please enable either the \"editor\" or the \"server\" feature"); @@ -23,8 +20,13 @@ fn main() { let args = args_parser::MainCommand::parse(); tracing_subscriber::FmtSubscriber::builder() .with_max_level(args.log_level()) - .finish().init(); - let args_parser::MainCommand { data_paths, run_mode, .. } = args; + .finish() + .init(); + let args_parser::MainCommand { + data_paths, + run_mode, + .. + } = args; match run_mode { Command::Serve(params) => { #[cfg(not(feature = "server"))] @@ -34,14 +36,28 @@ fn main() { #[cfg(feature = "server")] server::init(data_paths, params); } - Command::Fetch { save, handles, handles_are_files, new_domain, server_reload } => { - fetch(data_paths.database_path, save, handles.into_iter(), handles_are_files, new_domain); + Command::Fetch { + save, + handles, + handles_are_files, + new_domain, + server_reload, + } => { + fetch( + data_paths.database_path, + save, + handles.into_iter(), + handles_are_files, + new_domain, + ); reload(data_paths.pid_file_path, server_reload); } - Command::Query { resource } => { - query(data_paths.database_path, resource) - } - Command::Editor { save, resource, server_reload } => { + Command::Query { resource } => query(data_paths.database_path, resource), + Command::Editor { + save, + resource, + server_reload, + } => { editor(data_paths.database_path, save, resource); reload(data_paths.pid_file_path, server_reload); diff --git a/src/schema/lookup_handler.rs b/src/schema/lookup_handler.rs index 0ed7e69..6feb9f2 100644 --- a/src/schema/lookup_handler.rs +++ b/src/schema/lookup_handler.rs @@ -1,10 +1,10 @@ -use std::collections::HashMap; -use std::fmt::Debug; -use tracing::{debug, info, instrument}; -use std::path::Path; -use thiserror::Error; use crate::schema::resource::Resource; use crate::schema::resource_list::{ResourceList, ResourceLoadError}; +use std::collections::HashMap; +use std::fmt::Debug; +use std::path::Path; +use thiserror::Error; +use tracing::{debug, info, instrument}; /// Handles looking up resources based on the ?resource={} URL parameter #[derive(Debug)] @@ -30,6 +30,8 @@ impl LookupHandler { pub fn load(path: impl AsRef + Debug) -> Result { Self::build_from_resource_list(ResourceList::load(path)?) } + + #[cfg(test)] fn load_from_reader(reader: impl std::io::Read) -> Result { Self::build_from_resource_list(ResourceList::load_from_reader(reader)?) } @@ -56,9 +58,10 @@ impl LookupHandler { Ok(LookupHandler { resources, lookup }) } - #[instrument(level="debug")] + #[instrument(level = "debug")] pub fn lookup(&self, resource_query: &str) -> Option<&Resource> { - self.lookup_with_index(resource_query).map(|(_index, resource)| resource) + self.lookup_with_index(resource_query) + .map(|(_index, resource)| resource) } pub fn lookup_with_index(&self, resource_query: &str) -> Option<(usize, &Resource)> { @@ -92,7 +95,11 @@ mod tests { fn duplicate_subject() { let duplicated = "[{\"subject\": \"testing\"},{\"subject\": \"testing\"}]".as_bytes(); let result = LookupHandler::load_from_reader(duplicated); - if let Err(DataLoadError::DuplicateLookupFound { duplicated, subjects }) = result { + if let Err(DataLoadError::DuplicateLookupFound { + duplicated, + subjects, + }) = result + { assert_eq!(duplicated, "testing".to_string()); assert_eq!(subjects, ["testing".to_string(), "testing".to_string()]); } else { @@ -104,10 +111,17 @@ mod tests { fn duplicate_alias() { let duplicated = "[{\"subject\": \"testing\"},{\"subject\": \"more_testing\", \"aliases\": [\"testing\"]}]".as_bytes(); let result = LookupHandler::load_from_reader(duplicated); - if let Err(DataLoadError::DuplicateLookupFound { duplicated, mut subjects }) = result { + if let Err(DataLoadError::DuplicateLookupFound { + duplicated, + mut subjects, + }) = result + { assert_eq!(duplicated, "testing".to_string()); subjects.sort(); // Because we don't care about order for testing purposes - assert_eq!(subjects, ["more_testing".to_string(), "testing".to_string()]); + assert_eq!( + subjects, + ["more_testing".to_string(), "testing".to_string()] + ); } else { panic!("LookupHandler::load() returned {result:?}"); }; @@ -118,12 +132,15 @@ mod tests { let data = "[{\"subject\":\"testing\"},{\"subject\":\"more_testing\"}]".as_bytes(); let data = LookupHandler::load_from_reader(data).unwrap(); for subject in ["testing", "more_testing"] { - assert_eq!(data.lookup(subject), Some(&Resource { - subject: subject.to_string(), - aliases: None, - properties: None, - links: None, - })); + assert_eq!( + data.lookup(subject), + Some(&Resource { + subject: subject.to_string(), + aliases: None, + properties: None, + links: None, + }) + ); } } @@ -132,12 +149,15 @@ mod tests { let data = "[{\"subject\":\"testing\",\"aliases\":[\"alias1\",\"alias2\"]},{\"subject\":\"red herring\",\"aliases\":[\"alias\",\"1\", \"2\"]}]".as_bytes(); let data = LookupHandler::load_from_reader(data).unwrap(); for subject in ["alias1", "alias2"] { - assert_eq!(data.lookup(subject), Some(&Resource { - subject: "testing".to_string(), - aliases: Some(vec!["alias1".to_string(), "alias2".to_string()]), - properties: None, - links: None, - })); + assert_eq!( + data.lookup(subject), + Some(&Resource { + subject: "testing".to_string(), + aliases: Some(vec!["alias1".to_string(), "alias2".to_string()]), + properties: None, + links: None, + }) + ); } } } diff --git a/src/schema/mod.rs b/src/schema/mod.rs index 9f3d51f..485aae9 100644 --- a/src/schema/mod.rs +++ b/src/schema/mod.rs @@ -1,3 +1,3 @@ -pub mod resource; pub mod lookup_handler; +pub mod resource; pub mod resource_list; diff --git a/src/schema/resource.rs b/src/schema/resource.rs index 2b63348..057e902 100644 --- a/src/schema/resource.rs +++ b/src/schema/resource.rs @@ -81,16 +81,13 @@ pub mod test_data { pub fn user_with_single_alias() -> Resource { Resource { subject: "acct:user@domain.tld".to_string(), - aliases: Some(vec![ - "https://domain.tld/@user".to_string() - ]), + aliases: Some(vec!["https://domain.tld/@user".to_string()]), properties: None, links: None, } } } - #[cfg(test)] mod tests { use super::*; @@ -99,12 +96,14 @@ mod tests { fn insert_new_primary_subject_into_barebones_user() { let mut data = test_data::barebones_user(); data.add_new_primary_subject("username".to_string()); - assert_eq!(data, Resource { - subject: "username".to_string(), - aliases: Some(vec![test_data::barebones_user().subject]), - properties: None, - links: None, - }) - + assert_eq!( + data, + Resource { + subject: "username".to_string(), + aliases: Some(vec![test_data::barebones_user().subject]), + properties: None, + links: None, + } + ) } -} \ No newline at end of file +} diff --git a/src/schema/resource_list.rs b/src/schema/resource_list.rs index e7036c0..8968f91 100644 --- a/src/schema/resource_list.rs +++ b/src/schema/resource_list.rs @@ -1,10 +1,10 @@ -use std::collections::HashSet; -use tracing::{debug, info, instrument, trace, warn}; -use std::path::Path; -use std::fmt::Debug; -use thiserror::Error; use crate::args_parser::CollisionHandling; use crate::schema::resource::Resource; +use std::collections::HashSet; +use std::fmt::Debug; +use std::path::Path; +use thiserror::Error; +use tracing::{debug, info, instrument, trace, warn}; #[derive(Debug, Clone)] pub struct ResourceList(pub Vec); @@ -65,27 +65,39 @@ impl ResourceList { /// Merges `new_records` into the `ResourceList` with lookup collisions being handled as defined in `collision_handling` #[instrument(level = "debug", skip(self, new_records))] - pub fn merge_records(&mut self, new_records: impl Iterator, collision_handling: CollisionHandling) -> &ResourceList { + pub fn merge_records( + &mut self, + new_records: impl Iterator, + collision_handling: CollisionHandling, + ) -> &ResourceList { debug!("Building hashset of already taken queries..."); - let unique_check: HashSet = HashSet::from_iter(self.0.iter().flat_map(Resource::keys).cloned()); + let unique_check: HashSet = + HashSet::from_iter(self.0.iter().flat_map(Resource::keys).cloned()); for record in new_records { let record_keys = HashSet::from_iter(record.keys().cloned()); - let collisions = unique_check.intersection(&record_keys).collect::>(); + let collisions = unique_check + .intersection(&record_keys) + .collect::>(); if !collisions.is_empty() { - warn!("Resource collision detected with {}: {collisions:?}", record.subject); + warn!( + "Resource collision detected with {}: {collisions:?}", + record.subject + ); match collision_handling { CollisionHandling::Skip => { warn!("Skipping record..."); - continue + continue; } CollisionHandling::OverwriteSingleSkipMultiple => { let mut collided_resources = - self.0.iter().enumerate() - .filter(|record| record.1.keys().any(|elem| collisions.contains(elem))); - if let Some((collided_index, collided_resource)) = collided_resources.next() { + self.0.iter().enumerate().filter(|record| { + record.1.keys().any(|elem| collisions.contains(elem)) + }); + if let Some((collided_index, collided_resource)) = collided_resources.next() + { if collided_resources.next().is_some() { warn!("Resource collides with multiple records, skipping..."); - continue + continue; } warn!("Removing {}", collided_resource.subject); self.0.remove(collided_index); @@ -97,12 +109,14 @@ impl ResourceList { if record.keys().any(|elem| collisions.contains(elem)) { warn!("Removing {record:?}"); false - } else {true} + } else { + true + } }); } CollisionHandling::Terminate => { warn!("Collision found, terminating merge process..."); - return self + return self; } } } diff --git a/src/server/mod.rs b/src/server/mod.rs index 6e1ea09..0b7eddb 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,24 +1,27 @@ +use crate::args_parser::{DataPaths, ServerParameters}; +use crate::schema::lookup_handler::LookupHandler; +use crate::schema::resource::Resource; +use axum::body::Body; +use axum::extract::{Request, State}; +use axum::http::StatusCode; +use axum::response::Response; +use axum::routing::get; +use axum::Router; use std::io::Read; use std::net::SocketAddr; use std::ops::DerefMut; use std::path::{Path, PathBuf}; use std::sync::Arc; -use tokio::sync::RwLock; -use axum::body::Body; -use axum::extract::{Request, State}; -use axum::http::StatusCode; -use axum::response::Response; -use axum::Router; -use axum::routing::get; use tokio::select; use tokio::signal::unix::SignalKind; +use tokio::sync::RwLock; use tracing::{debug, error, info, instrument, trace}; -use crate::args_parser::{DataPaths, ServerParameters}; -use crate::schema::lookup_handler::LookupHandler; -use crate::schema::resource::Resource; pub fn init(data_paths: DataPaths, server_parameters: ServerParameters) { - let DataPaths { database_path, pid_file_path } = data_paths; + let DataPaths { + database_path, + pid_file_path, + } = data_paths; //TODO: Apparently you're supposed to keep this file around and verify that the PID in it is still active? debug!("Attempting to install PID file at {pid_file_path:?}"); if let Ok(mut file) = std::fs::File::open(&pid_file_path) { @@ -38,7 +41,7 @@ pub fn init(data_paths: DataPaths, server_parameters: ServerParameters) { error!("Failed to create tokio runtime: {e}"); return; } - Ok(runtime) => runtime + Ok(runtime) => runtime, }; if let Err(e) = runtime.block_on(async_main(database_path, server_parameters)) { error!("Failed to block on server's async_main: {e}"); @@ -48,7 +51,10 @@ pub fn init(data_paths: DataPaths, server_parameters: ServerParameters) { } #[instrument(skip_all)] -async fn async_main(db_path: PathBuf, server_parameters: ServerParameters) -> Result<(), std::io::Error> { +async fn async_main( + db_path: PathBuf, + server_parameters: ServerParameters, +) -> Result<(), std::io::Error> { info!("Initialising server..."); let datastore = Arc::new(RwLock::new(LookupHandler::load(&db_path).unwrap())); let _handler = tokio::spawn(hangup_handler(db_path, datastore.clone())); @@ -65,35 +71,64 @@ async fn async_main(db_path: PathBuf, server_parameters: ServerParameters) -> Re .await } -async fn run_webfinger_query(State(datastore): State>>, request: Request) -> Result { +async fn run_webfinger_query( + State(datastore): State>>, + request: Request, +) -> Result { let uri = request.uri(); info!("Received query with {uri}"); let query = uri.query().ok_or(StatusCode::BAD_REQUEST)?; debug!("Query string is {query}"); - let params = query.split('&').filter_map(|query_part| { - trace!("Processing part {query_part}"); - query_part.split_once('=') - }).collect::>(); + let params = query + .split('&') + .filter_map(|query_part| { + trace!("Processing part {query_part}"); + query_part.split_once('=') + }) + .collect::>(); trace!("Query parts are {params:?}"); - let mut resource_query_iter = params.iter().filter_map(|(key, value)| if key.trim() == "resource" {Some(value)} else {None}); + let mut resource_query_iter = params.iter().filter_map(|(key, value)| { + if key.trim() == "resource" { + Some(value) + } else { + None + } + }); let resource_query = *resource_query_iter.next().ok_or(StatusCode::BAD_REQUEST)?; if resource_query_iter.next().is_some() { debug!("Multiple resource parameters provided, bailing"); - return Err(StatusCode::BAD_REQUEST) + return Err(StatusCode::BAD_REQUEST); } - let resource = datastore.read().await.lookup(resource_query).ok_or(StatusCode::NOT_FOUND)?.clone(); + let resource = datastore + .read() + .await + .lookup(resource_query) + .ok_or(StatusCode::NOT_FOUND)? + .clone(); debug!("Found resource: {resource:?}"); - let mut rels = params.into_iter().filter_map(|(key, value)| if key.trim() == "rel" {Some(value)} else {None}).peekable(); + let mut rels = params + .into_iter() + .filter_map(|(key, value)| { + if key.trim() == "rel" { + Some(value) + } else { + None + } + }) + .peekable(); let response_body = if rels.peek().is_some() { debug!("There were rel parameters in the query"); if let Some(links) = resource.links { debug!("Filtering links..."); Resource { - links: Some(rels.filter_map(|rel| links.iter().find(|link| link.rel == rel).cloned()).collect()), + links: Some( + rels.filter_map(|rel| links.iter().find(|link| link.rel == rel).cloned()) + .collect(), + ), ..resource } } else { @@ -107,10 +142,12 @@ async fn run_webfinger_query(State(datastore): State>> Response::builder() .header("Content-Type", "application/jrd+json") - .body(Body::new(serde_json::to_string(&response_body).map_err(|e| { - error!("Server error occurred while serialising response body: {e}"); - StatusCode::INTERNAL_SERVER_ERROR - })?)) + .body(Body::new(serde_json::to_string(&response_body).map_err( + |e| { + error!("Server error occurred while serialising response body: {e}"); + StatusCode::INTERNAL_SERVER_ERROR + }, + )?)) .map_err(|e| { error!("Server error occurred while building response: {e}"); StatusCode::INTERNAL_SERVER_ERROR @@ -132,7 +169,9 @@ async fn hangup_handler(db_path: PathBuf, datastore: Arc>) std::mem::swap(lock.deref_mut(), &mut handler); info!("Data updated!"); } - Err(error) => {error!("Failed to reload datastore: {error}")} + Err(error) => { + error!("Failed to reload datastore: {error}") + } } } } @@ -149,4 +188,4 @@ async fn graceful_shutdown_handler() { Some(()) = sigint => info!("SIGINT received, shutting down..."), Some(()) = sigterm => info!("SIGTERM received, shutting down..."), } -} \ No newline at end of file +}