Use unstable options

This commit is contained in:
Edward Shen 2021-04-25 12:55:31 -04:00
parent 316e69851e
commit 6da2cba78a
Signed by: edward
GPG key ID: 19182661E818369F
4 changed files with 110 additions and 26 deletions

View file

@ -1,6 +1,9 @@
use std::num::{NonZeroU16, NonZeroU64}; use std::{fmt::Display, path::PathBuf};
use std::path::PathBuf; use std::{fmt::Formatter, sync::atomic::AtomicBool};
use std::sync::atomic::AtomicBool; use std::{
num::{NonZeroU16, NonZeroU64},
str::FromStr,
};
use clap::{crate_authors, crate_description, crate_version, Clap}; use clap::{crate_authors, crate_description, crate_version, Clap};
use url::Url; use url::Url;
@ -43,7 +46,6 @@ pub struct CliArgs {
short, short,
long, long,
conflicts_with("memory-quota"), conflicts_with("memory-quota"),
conflicts_with("use-lfu"),
env = "LOW_MEMORY_MODE", env = "LOW_MEMORY_MODE",
takes_value = false takes_value = false
)] )]
@ -57,16 +59,46 @@ pub struct CliArgs {
/// respectively. /// respectively.
#[clap(short, long, parse(from_occurrences), conflicts_with = "verbose")] #[clap(short, long, parse(from_occurrences), conflicts_with = "verbose")]
pub quiet: usize, pub quiet: usize,
/// Overrides the upstream URL to fetch images from. Don't use this unless #[clap(short = 'Z', long)]
/// you know what you're dealing with. pub unstable_options: Vec<UnstableOptions>,
#[clap(long)] #[clap(long)]
pub override_upstream: Option<Url>, pub override_upstream: Option<Url>,
/// Disables token validation. Don't use this unless you know the }
/// ramifications of this command.
#[clap(long)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub disable_token_validation: bool, pub enum UnstableOptions {
/// Overrides the upstream URL to fetch images from. Don't use this unless
/// you know what you're dealing with.
OverrideUpstream,
/// Use an LFU implementation for the in-memory cache instead of the default /// Use an LFU implementation for the in-memory cache instead of the default
/// LRU implementation. /// LRU implementation.
#[clap(short = 'F', long)] UseLfu,
pub use_lfu: bool,
/// Disables token validation. Don't use this unless you know the
/// ramifications of this command.
DisableTokenValidation,
}
impl FromStr for UnstableOptions {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"override-upstream" => Ok(Self::OverrideUpstream),
"use-lfu" => Ok(Self::UseLfu),
"disable-token-validation" => Ok(Self::DisableTokenValidation),
_ => Err("Unknown unstable option"),
}
}
}
impl Display for UnstableOptions {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::OverrideUpstream => write!(f, "override-upstream"),
Self::UseLfu => write!(f, "use-lfu"),
Self::DisableTokenValidation => write!(f, "disable-token-validation"),
}
}
} }

View file

@ -2,13 +2,16 @@
// We're end users, so these is ok // We're end users, so these is ok
#![allow(clippy::module_name_repetitions)] #![allow(clippy::module_name_repetitions)]
use std::env::{self, VarError};
use std::hint::unreachable_unchecked;
use std::num::ParseIntError; use std::num::ParseIntError;
use std::process; use std::process;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use std::{
env::{self, VarError},
fmt::Display,
};
use std::{error::Error, hint::unreachable_unchecked};
use actix_web::rt::{spawn, time, System}; use actix_web::rt::{spawn, time, System};
use actix_web::web::{self, Data}; use actix_web::web::{self, Data};
@ -24,8 +27,11 @@ use state::{RwLockServerState, ServerState};
use stop::send_stop; use stop::send_stop;
use thiserror::Error; use thiserror::Error;
use crate::cache::{MemoryLfuCache, MemoryLruCache};
use crate::state::DynamicServerCert; use crate::state::DynamicServerCert;
use crate::{
cache::{MemoryLfuCache, MemoryLruCache},
config::UnstableOptions,
};
mod cache; mod cache;
mod config; mod config;
@ -50,7 +56,7 @@ enum ServerError {
} }
#[actix_web::main] #[actix_web::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn Error>> {
// It's ok to fail early here, it would imply we have a invalid config. // It's ok to fail early here, it would imply we have a invalid config.
dotenv::dotenv().ok(); dotenv::dotenv().ok();
let cli_args = CliArgs::parse(); let cli_args = CliArgs::parse();
@ -60,7 +66,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let disk_quota = cli_args.disk_quota; let disk_quota = cli_args.disk_quota;
let cache_path = cli_args.cache_path.clone(); let cache_path = cli_args.cache_path.clone();
let low_mem_mode = cli_args.low_memory; let low_mem_mode = cli_args.low_memory;
let use_lfu = cli_args.use_lfu; let use_lfu = cli_args.unstable_options.contains(&UnstableOptions::UseLfu);
let log_level = match (cli_args.quiet, cli_args.verbose) { let log_level = match (cli_args.quiet, cli_args.verbose) {
(n, _) if n > 2 => LevelFilter::Off, (n, _) if n > 2 => LevelFilter::Off,
@ -74,7 +80,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
SimpleLogger::new().with_level(log_level).init()?; SimpleLogger::new().with_level(log_level).init()?;
print_preamble_and_warnings(); if let Err(e) = print_preamble_and_warnings(&cli_args) {
error!("{}", e);
return Err(e);
}
let client_secret = if let Ok(v) = env::var("CLIENT_SECRET") { let client_secret = if let Ok(v) = env::var("CLIENT_SECRET") {
v v
@ -163,7 +172,28 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(()) Ok(())
} }
fn print_preamble_and_warnings() { #[derive(Debug)]
enum InvalidCombination {
MissingUnstableOption(&'static str, UnstableOptions),
}
impl Display for InvalidCombination {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
InvalidCombination::MissingUnstableOption(opt, arg) => {
write!(
f,
"The option '{}' requires the unstable option '-Z {}'",
opt, arg
)
}
}
}
}
impl Error for InvalidCombination {}
fn print_preamble_and_warnings(args: &CliArgs) -> Result<(), Box<dyn Error>> {
println!(concat!( println!(concat!(
env!("CARGO_PKG_NAME"), env!("CARGO_PKG_NAME"),
" ", " ",
@ -186,4 +216,21 @@ fn print_preamble_and_warnings() {
env!("CARGO_PKG_NAME"), env!("CARGO_PKG_NAME"),
". If not, see <https://www.gnu.org/licenses/>.\n" ". If not, see <https://www.gnu.org/licenses/>.\n"
)); ));
if !args.unstable_options.is_empty() {
warn!("Unstable options are enabled. These options should not be used in production!");
}
if args.override_upstream.is_some()
&& !args
.unstable_options
.contains(&UnstableOptions::OverrideUpstream)
{
Err(Box::new(InvalidCombination::MissingUnstableOption(
"override-upstream",
UnstableOptions::OverrideUpstream,
)))
} else {
Ok(())
}
} }

View file

@ -11,12 +11,12 @@ use serde::{Deserialize, Serialize};
use sodiumoxide::crypto::box_::PrecomputedKey; use sodiumoxide::crypto::box_::PrecomputedKey;
use url::Url; use url::Url;
use crate::client_api_version;
use crate::config::{CliArgs, VALIDATE_TOKENS}; use crate::config::{CliArgs, VALIDATE_TOKENS};
use crate::state::{ use crate::state::{
RwLockServerState, PREVIOUSLY_COMPROMISED, PREVIOUSLY_PAUSED, TLS_CERTS, RwLockServerState, PREVIOUSLY_COMPROMISED, PREVIOUSLY_PAUSED, TLS_CERTS,
TLS_PREVIOUSLY_CREATED, TLS_SIGNING_KEY, TLS_PREVIOUSLY_CREATED, TLS_SIGNING_KEY,
}; };
use crate::{client_api_version, config::UnstableOptions};
pub const CONTROL_CENTER_PING_URL: &str = "https://api.mangadex.network/ping"; pub const CONTROL_CENTER_PING_URL: &str = "https://api.mangadex.network/ping";
@ -170,7 +170,9 @@ pub async fn update_server_state(secret: &str, cli: &CliArgs, data: &mut Arc<RwL
} }
} }
if !cli.disable_token_validation if !cli
.unstable_options
.contains(&UnstableOptions::DisableTokenValidation)
&& VALIDATE_TOKENS.load(Ordering::Acquire) != resp.force_tokens && VALIDATE_TOKENS.load(Ordering::Acquire) != resp.force_tokens
{ {
if resp.force_tokens { if resp.force_tokens {

View file

@ -1,6 +1,6 @@
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use crate::config::{CliArgs, SEND_SERVER_VERSION, VALIDATE_TOKENS}; use crate::config::{CliArgs, UnstableOptions, SEND_SERVER_VERSION, VALIDATE_TOKENS};
use crate::ping::{Request, Response, CONTROL_CENTER_PING_URL}; use crate::ping::{Request, Response, CONTROL_CENTER_PING_URL};
use arc_swap::ArcSwap; use arc_swap::ArcSwap;
use log::{error, info, warn}; use log::{error, info, warn};
@ -90,7 +90,10 @@ impl ServerState {
info!("This client's URL has been set to {}", resp.url); info!("This client's URL has been set to {}", resp.url);
if config.disable_token_validation { if config
.unstable_options
.contains(&UnstableOptions::DisableTokenValidation)
{
warn!("Token validation is explicitly disabled!"); warn!("Token validation is explicitly disabled!");
} else { } else {
if resp.force_tokens { if resp.force_tokens {
@ -116,17 +119,17 @@ impl ServerState {
}) })
} }
Err(e) => { Err(e) => {
warn!("Got malformed response: {}", e); error!("Got malformed response: {}. Is MangaDex@Home down?", e);
Err(ServerInitError::MalformedResponse(e)) Err(ServerInitError::MalformedResponse(e))
} }
}, },
Err(e) => match e { Err(e) => match e {
e if e.is_timeout() => { e if e.is_timeout() => {
error!("Response timed out to control server. Is MangaDex down?"); error!("Response timed out to control server. Is MangaDex@Home down?");
Err(ServerInitError::Timeout(e)) Err(ServerInitError::Timeout(e))
} }
e => { e => {
warn!("Failed to send request: {}", e); error!("Failed to send request: {}", e);
Err(ServerInitError::SendFailure(e)) Err(ServerInitError::SendFailure(e))
} }
}, },