use clap::{Args, Parser, Subcommand, ValueEnum}; use std::net::IpAddr; use std::path::PathBuf; use tracing::Level; /// A simple program to handle serving static WebFinger data. #[derive(Debug, Parser)] #[command(name = "Fingerlink", version, about, long_about = None)] pub struct MainCommand { #[arg(long, value_enum, default_value = "info")] pub log_level: LoggingLevel, #[command(flatten)] pub data_paths: DataPaths, #[command(subcommand)] pub run_mode: Command, } impl MainCommand { pub fn log_level(&self) -> Level { match self.log_level { LoggingLevel::Trace => Level::TRACE, LoggingLevel::Debug => Level::DEBUG, LoggingLevel::Info => Level::INFO, LoggingLevel::Warning => Level::WARN, LoggingLevel::Error => Level::ERROR, } } } #[derive(Args, Debug)] pub struct DataPaths { #[arg(long, short = 'd', default_value = "records.json")] pub database_path: PathBuf, #[arg(long, default_value = "server.pid")] pub pid_file_path: PathBuf, } #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, ValueEnum)] pub enum LoggingLevel { Trace, Debug, Info, Warning, Error, } #[derive(Debug, Clone, Args)] pub struct ServerParameters { /// The IP address to bind to #[arg(long, short = 'b', default_value = "127.0.0.1")] pub bind_ip: IpAddr, /// The port to listen on #[arg(long, short = 'p', default_value = "8080")] pub bind_port: u16, /// Whether to ignore the PID file already existing. #[arg(long)] 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, } #[derive(Debug, Args)] pub struct SaveSettings { /// Specify this flag to write the fetched records into the database #[arg(long, short = 's')] pub save: bool, /// Save behaviour when encountering a collision #[arg(long, default_value = "overwrite-single-skip-multiple")] pub collision_handling: CollisionHandling, } #[derive(Debug, Subcommand)] pub enum Command { /// Serve the database Serve(ServerParameters), /// Fetch one or multiple handles from Fediverse-compatible software Fetch { #[command(flatten)] save: SaveSettings, /// The handles to process in the format username@domainĂ³ handles: Vec, /// Set this flag to treat HANDLES as a list of file paths that contain the handles to process #[arg(long)] handles_are_files: bool, /// The domain to rewrite the acquired handles' subject domain to. If left unspecified, the domain is kept as-is #[arg(long)] new_domain: Option, #[command(flatten)] server_reload: ServerReloadOptions, }, /// Runs a single query against the database and returns the resource associated with the value Query { /// The resource to query for resource: String, }, /// Open the resource in your system editor Editor { #[command(flatten)] save: SaveSettings, /// The resource to query for and edit resource: String, /// Create a blank resource with RESOURCE as the subject if the query fails #[arg(long, short = 'c')] create: bool, #[command(flatten)] server_reload: ServerReloadOptions, }, /// Create a blank database Init { /// Force creating a new database even if one exists already. WILL DELETE DATA! #[arg(long, short = 'f')] force: bool, }, } #[derive(ValueEnum, Debug, Eq, PartialEq, Copy, Clone)] pub enum CollisionHandling { /// Terminate import process when encountering a collision. /// Still inserts resources processed before detecting a collision Terminate, /// Skip adding new resource if it would collide with an existing resource Skip, /// 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? } #[derive(Args, Debug)] pub struct ServerReloadOptions { /// Set this flag for the application to attempt to reload the running server process automatically #[arg(long, short = 'r')] pub reload_server: bool, }