From 0b10737403b7edee11477222c28de71e6f039ae8 Mon Sep 17 00:00:00 2001 From: _ <> Date: Sat, 2 Oct 2021 17:26:56 +0000 Subject: [PATCH] :recycle: refactor: move ptth_server's main into its library so I can make a busybox-style multi-use binary --- Cargo.lock | 1 + crates/ptth_core/Cargo.toml | 1 + crates/ptth_core/src/prelude.rs | 5 + crates/ptth_server/src/bin/ptth_server.rs | 122 +----------------- crates/ptth_server/src/lib.rs | 146 ++++++++++++++++++++-- crates/ptth_server/src/prelude.rs | 9 +- 6 files changed, 144 insertions(+), 140 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ae75527..274dee2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1158,6 +1158,7 @@ dependencies = [ name = "ptth_core" version = "2.0.0" dependencies = [ + "anyhow", "base64", "ctrlc", "futures", diff --git a/crates/ptth_core/Cargo.toml b/crates/ptth_core/Cargo.toml index 636bc79..566d6e5 100644 --- a/crates/ptth_core/Cargo.toml +++ b/crates/ptth_core/Cargo.toml @@ -10,6 +10,7 @@ description = "Common code for the PTTH relay and server" [dependencies] +anyhow = "1.0.38" base64 = "0.13.0" ctrlc = { version = "3.1.8", features = [ "termination" ] } futures = "0.3.7" diff --git a/crates/ptth_core/src/prelude.rs b/crates/ptth_core/src/prelude.rs index 44db49e..4a2b7d2 100644 --- a/crates/ptth_core/src/prelude.rs +++ b/crates/ptth_core/src/prelude.rs @@ -1,8 +1,13 @@ pub use std::{ + io::Write, sync::Arc, time::{Duration, Instant}, }; +pub use anyhow::{ + Context, + bail, +}; pub use tracing::{ debug, error, info, trace, warn, instrument, diff --git a/crates/ptth_server/src/bin/ptth_server.rs b/crates/ptth_server/src/bin/ptth_server.rs index 4a47bc6..06eeaea 100644 --- a/crates/ptth_server/src/bin/ptth_server.rs +++ b/crates/ptth_server/src/bin/ptth_server.rs @@ -1,126 +1,8 @@ #![warn (clippy::pedantic)] -use std::{ - fs::File, - path::{Path, PathBuf}, -}; - -use structopt::StructOpt; - -use ptth_server::{ - load_toml, - prelude::*, - run_server, -}; - -#[derive (Debug, StructOpt)] -struct Opt { - #[structopt (long)] - auto_gen_key: bool, - - #[structopt (long)] - throttle_upload: bool, - - #[structopt (long)] - file_server_root: Option , - - #[structopt (long)] - asset_root: Option , - - #[structopt (long)] - config_path: Option , - - #[structopt (long)] - name: Option , - - #[structopt (long)] - print_tripcode: bool, - - #[structopt (long)] - relay_url: Option , -} - -#[derive (Default, serde::Deserialize)] -pub struct ConfigFile { - pub name: Option , - pub api_key: String, - pub relay_url: Option , - pub file_server_root: Option , -} - -fn gen_and_save_key (path: &Path) -> anyhow::Result <()> { - let api_key = ptth_core::gen_key (); - - let mut f = File::create (path).with_context (|| format! ("Can't create config file `{:?}`", path))?; - - #[cfg (unix)] - { - use std::os::unix::fs::PermissionsExt; - - let metadata = f.metadata ()?; - let mut permissions = metadata.permissions (); - permissions.set_mode (0o600); - f.set_permissions (permissions)?; - } - #[cfg (not (unix))] - { - tracing::warn! ("Error VR6VW5QT: API keys aren't protected from clients on non-Unix OSes yet"); - } - - f.write_all (format! ("api_key = \"{}\"\n", api_key).as_bytes ())?; - - Ok (()) -} - #[tokio::main] -async fn main () -> Result <(), anyhow::Error> { +async fn main () -> anyhow::Result <()> { tracing_subscriber::fmt::init (); - let opt = Opt::from_args (); - let asset_root = opt.asset_root; - - let path = opt.config_path.clone ().unwrap_or_else (|| PathBuf::from ("./config/ptth_server.toml")); - - let config_file: ConfigFile = if opt.auto_gen_key { - // If we're in autonomous mode, try harder to fix things - - match load_toml::load (&path) { - Err (_) => { - gen_and_save_key (&path)?; - - load_toml::load (&path)? - }, - Ok (x) => x, - } - } - else { - match load_toml::load (&path) { - Err (ptth_server::errors::LoadTomlError::Io (_)) => bail! ("API key not provided in config file and auto-gen-key not provided"), - Ok (x) => x, - Err (e) => return Err (e.into ()), - } - }; - - let config_file = ptth_server::ConfigFile { - name: opt.name.or (config_file.name).ok_or (anyhow::anyhow! ("`name` must be provided in command line or config file"))?, - api_key: config_file.api_key, - relay_url: opt.relay_url.or (config_file.relay_url).ok_or (anyhow::anyhow! ("`--relay-url` must be provided in command line or `relay_url` in config file"))?, - file_server_root: opt.file_server_root.or (config_file.file_server_root), - throttle_upload: opt.throttle_upload, - }; - - if opt.print_tripcode { - println! (r#"name = "{}""#, config_file.name); - println! (r#"tripcode = "{}""#, config_file.tripcode ()); - return Ok (()); - } - - run_server ( - config_file, - ptth_core::graceful_shutdown::init (), - Some (path), - asset_root - ).await?; - - Ok (()) + ptth_server::executable::main ().await } diff --git a/crates/ptth_server/src/lib.rs b/crates/ptth_server/src/lib.rs index 4f4875f..25f8d61 100644 --- a/crates/ptth_server/src/lib.rs +++ b/crates/ptth_server/src/lib.rs @@ -39,6 +39,17 @@ // False positive on futures::select! macro #![allow (clippy::mut_mut)] +pub mod errors; + +/// In-process file server module with byte range and ETag support +pub mod file_server; + +/// Load and de-serialize structures from TOML, with a size limit +/// and checking permissions (On Unix) +pub mod load_toml; + +pub mod prelude; + use std::{ future::Future, path::PathBuf, @@ -58,21 +69,10 @@ use tokio_stream::wrappers::ReceiverStream; use ptth_core::{ http_serde, - prelude::*, }; -pub mod errors; - -/// In-process file server module with byte range and ETag support -pub mod file_server; - -/// Load and de-serialize structures from TOML, with a size limit -/// and checking permissions (On Unix) -pub mod load_toml; - -pub mod prelude; - use errors::ServerError; +use prelude::*; pub struct State { // file_server: file_server::FileServer, @@ -480,6 +480,128 @@ impl State { } } +pub mod executable { + use std::{ + path::{Path, PathBuf}, + }; + use structopt::StructOpt; + use super::{ + load_toml, + prelude::*, + }; + + pub async fn main () -> anyhow::Result <()> { + let opt = Opt::from_args (); + let asset_root = opt.asset_root; + + let path = opt.config_path.clone ().unwrap_or_else (|| PathBuf::from ("./config/ptth_server.toml")); + + let config_file: ConfigFile = if opt.auto_gen_key { + // If we're in autonomous mode, try harder to fix things + + match load_toml::load (&path) { + Err (_) => { + gen_and_save_key (&path)?; + + load_toml::load (&path)? + }, + Ok (x) => x, + } + } + else { + match load_toml::load (&path) { + Err (super::errors::LoadTomlError::Io (_)) => bail! ("API key not provided in config file and auto-gen-key not provided"), + Ok (x) => x, + Err (e) => return Err (e.into ()), + } + }; + + let config_file = super::ConfigFile { + name: opt.name.or (config_file.name).ok_or (anyhow::anyhow! ("`name` must be provided in command line or config file"))?, + api_key: config_file.api_key, + relay_url: opt.relay_url.or (config_file.relay_url).ok_or (anyhow::anyhow! ("`--relay-url` must be provided in command line or `relay_url` in config file"))?, + file_server_root: opt.file_server_root.or (config_file.file_server_root), + throttle_upload: opt.throttle_upload, + }; + + if opt.print_tripcode { + println! (r#"name = "{}""#, config_file.name); + println! (r#"tripcode = "{}""#, config_file.tripcode ()); + return Ok (()); + } + + super::run_server ( + config_file, + ptth_core::graceful_shutdown::init (), + Some (path), + asset_root + ).await?; + + Ok (()) + } + + #[derive (Debug, StructOpt)] + struct Opt { + #[structopt (long)] + auto_gen_key: bool, + + #[structopt (long)] + throttle_upload: bool, + + #[structopt (long)] + file_server_root: Option , + + #[structopt (long)] + asset_root: Option , + + #[structopt (long)] + config_path: Option , + + #[structopt (long)] + name: Option , + + #[structopt (long)] + print_tripcode: bool, + + #[structopt (long)] + relay_url: Option , + } + + #[derive (Default, serde::Deserialize)] + struct ConfigFile { + pub name: Option , + pub api_key: String, + pub relay_url: Option , + pub file_server_root: Option , + } + + fn gen_and_save_key (path: &Path) -> anyhow::Result <()> { + use std::fs::File; + + let api_key = ptth_core::gen_key (); + + let mut f = File::create (path).with_context (|| format! ("Can't create config file `{:?}`", path))?; + + #[cfg (unix)] + { + use std::os::unix::fs::PermissionsExt; + + let metadata = f.metadata ()?; + let mut permissions = metadata.permissions (); + permissions.set_mode (0o600); + f.set_permissions (permissions)?; + } + #[cfg (not (unix))] + { + tracing::warn! ("Error VR6VW5QT: API keys aren't protected from clients on non-Unix OSes yet"); + } + + f.write_all (format! ("api_key = \"{}\"\n", api_key).as_bytes ())?; + + Ok (()) + } +} + #[cfg (test)] mod tests { use super::*; diff --git a/crates/ptth_server/src/prelude.rs b/crates/ptth_server/src/prelude.rs index 7b25ad1..61786cc 100644 --- a/crates/ptth_server/src/prelude.rs +++ b/crates/ptth_server/src/prelude.rs @@ -1,8 +1 @@ -pub use std::{ - io::Write, -}; - -pub use anyhow::{ - Context, - bail, -}; +pub use ptth_core::prelude::*;