mangadex-home-rs/src/main.rs

184 lines
5.6 KiB
Rust
Raw Normal View History

#![warn(clippy::pedantic, clippy::nursery)]
2021-03-23 00:00:21 +00:00
// We're end users, so these is ok
2021-04-18 03:19:27 +00:00
#![allow(clippy::module_name_repetitions)]
2021-03-18 01:45:16 +00:00
2021-03-26 02:58:07 +00:00
use std::env::{self, VarError};
2021-04-23 22:03:53 +00:00
use std::hint::unreachable_unchecked;
use std::num::ParseIntError;
2021-03-26 02:58:07 +00:00
use std::process;
2021-04-23 22:03:53 +00:00
use std::sync::atomic::{AtomicBool, Ordering};
2021-03-22 21:47:56 +00:00
use std::sync::Arc;
2021-03-18 01:45:16 +00:00
use std::time::Duration;
2021-03-22 21:47:56 +00:00
use actix_web::rt::{spawn, time, System};
2021-03-23 03:04:54 +00:00
use actix_web::web::{self, Data};
2021-03-18 01:45:16 +00:00
use actix_web::{App, HttpServer};
2021-04-23 21:22:29 +00:00
use cache::{Cache, DiskCache};
2021-03-26 01:06:54 +00:00
use clap::Clap;
use config::CliArgs;
2021-03-23 03:19:56 +00:00
use log::{debug, error, warn, LevelFilter};
2021-04-19 04:16:13 +00:00
use parking_lot::RwLock;
2021-03-22 21:47:56 +00:00
use rustls::{NoClientAuth, ServerConfig};
2021-03-18 01:45:16 +00:00
use simple_logger::SimpleLogger;
2021-03-22 21:47:56 +00:00
use state::{RwLockServerState, ServerState};
use stop::send_stop;
2021-03-18 01:45:16 +00:00
use thiserror::Error;
2021-04-23 04:11:30 +00:00
use crate::cache::MemoryLruCache;
2021-03-22 21:47:56 +00:00
mod cache;
2021-03-26 01:06:54 +00:00
mod config;
2021-03-18 01:45:16 +00:00
mod ping;
mod routes;
2021-03-22 21:47:56 +00:00
mod state;
2021-03-18 01:45:16 +00:00
mod stop;
#[macro_export]
macro_rules! client_api_version {
() => {
"30"
};
}
2021-03-26 02:58:07 +00:00
2021-03-18 01:45:16 +00:00
#[derive(Error, Debug)]
enum ServerError {
#[error("There was a failure parsing config")]
Config(#[from] VarError),
#[error("Failed to parse an int")]
ParseInt(#[from] ParseIntError),
}
#[actix_web::main]
2021-04-23 22:03:53 +00:00
async fn main() -> Result<(), Box<dyn std::error::Error>> {
2021-03-22 21:47:56 +00:00
// It's ok to fail early here, it would imply we have a invalid config.
2021-03-18 01:45:16 +00:00
dotenv::dotenv().ok();
2021-03-26 01:06:54 +00:00
let cli_args = CliArgs::parse();
2021-04-18 02:12:02 +00:00
2021-03-26 02:58:07 +00:00
let port = cli_args.port;
2021-03-26 04:07:32 +00:00
let memory_max_size = cli_args.memory_quota.get();
let disk_quota = cli_args.disk_quota;
let cache_path = cli_args.cache_path.clone();
let low_mem_mode = cli_args.low_memory;
2021-03-26 01:06:54 +00:00
2021-04-20 18:12:20 +00:00
let log_level = match (cli_args.quiet, cli_args.verbose) {
(n, _) if n > 2 => LevelFilter::Off,
(2, _) => LevelFilter::Error,
(1, _) => LevelFilter::Warn,
(0, 0) => LevelFilter::Info,
(_, 1) => LevelFilter::Debug,
(_, n) if n > 1 => LevelFilter::Trace,
2021-04-23 22:03:53 +00:00
_ => unsafe { unreachable_unchecked() },
2021-04-20 18:12:20 +00:00
};
2021-04-23 22:03:53 +00:00
SimpleLogger::new().with_level(log_level).init()?;
2021-03-26 01:06:54 +00:00
2021-04-19 03:06:18 +00:00
print_preamble_and_warnings();
2021-03-26 01:06:54 +00:00
let client_secret = if let Ok(v) = env::var("CLIENT_SECRET") {
v
} else {
2021-03-26 02:58:07 +00:00
error!("Client secret not found in ENV. Please set CLIENT_SECRET.");
2021-03-26 01:06:54 +00:00
process::exit(1);
};
let client_secret_1 = client_secret.clone();
2021-04-23 22:03:53 +00:00
let server = ServerState::init(&client_secret, &cli_args).await?;
2021-03-26 02:58:07 +00:00
let data_0 = Arc::new(RwLockServerState(RwLock::new(server)));
let data_1 = Arc::clone(&data_0);
// What's nice is that Rustls only supports TLS 1.2 and 1.3.
let mut tls_config = ServerConfig::new(NoClientAuth::new());
tls_config.cert_resolver = data_0.clone();
//
// At this point, the server is ready to start, and starts the necessary
// threads.
//
2021-03-22 21:47:56 +00:00
// Set ctrl+c to send a stop message
let running = Arc::new(AtomicBool::new(true));
2021-04-19 03:06:18 +00:00
let running_1 = running.clone();
let system = System::current();
2021-03-22 21:47:56 +00:00
ctrlc::set_handler(move || {
2021-04-19 03:06:18 +00:00
let system = &system;
2021-03-22 21:47:56 +00:00
let client_secret = client_secret.clone();
2021-04-19 03:06:18 +00:00
let running_2 = Arc::clone(&running_1);
2021-03-22 21:47:56 +00:00
System::new().block_on(async move {
2021-04-19 03:06:18 +00:00
if running_2.load(Ordering::SeqCst) {
send_stop(&client_secret).await;
} else {
warn!("Got second ctrl-c, forcefully exiting");
system.stop()
}
2021-03-22 21:47:56 +00:00
});
2021-04-19 03:06:18 +00:00
running_1.store(false, Ordering::SeqCst);
2021-03-22 21:47:56 +00:00
})
.expect("Error setting Ctrl-C handler");
2021-03-26 02:58:07 +00:00
// Spawn ping task
2021-03-18 01:45:16 +00:00
spawn(async move {
let mut interval = time::interval(Duration::from_secs(90));
let mut data = Arc::clone(&data_0);
loop {
interval.tick().await;
2021-03-23 03:19:56 +00:00
debug!("Sending ping!");
2021-03-26 01:06:54 +00:00
ping::update_server_state(&client_secret_1, &cli_args, &mut data).await;
2021-03-18 01:45:16 +00:00
}
});
2021-04-23 04:11:30 +00:00
let cache: Arc<Box<dyn Cache>> = if low_mem_mode {
2021-04-23 21:22:29 +00:00
DiskCache::new(disk_quota, cache_path.clone()).await
2021-04-23 04:11:30 +00:00
} else {
MemoryLruCache::new(disk_quota, cache_path.clone(), memory_max_size).await
};
2021-04-22 17:11:08 +00:00
let cache_0 = Arc::clone(&cache);
2021-04-18 21:38:33 +00:00
2021-03-26 02:58:07 +00:00
// Start HTTPS server
2021-03-18 01:45:16 +00:00
HttpServer::new(move || {
App::new()
.service(routes::token_data)
2021-03-22 21:47:56 +00:00
.service(routes::token_data_saver)
.route("{tail:.*}", web::get().to(routes::default))
2021-03-18 01:45:16 +00:00
.app_data(Data::from(Arc::clone(&data_1)))
2021-04-22 17:11:08 +00:00
.app_data(Data::from(Arc::clone(&cache_0)))
2021-03-18 01:45:16 +00:00
})
.shutdown_timeout(60)
.bind_rustls(format!("0.0.0.0:{}", port), tls_config)?
2021-04-24 03:28:47 +00:00
// .bind(format!("0.0.0.0:{}", port))?
2021-03-18 01:45:16 +00:00
.run()
2021-03-22 21:47:56 +00:00
.await?;
// Waiting for us to finish sending stop message
while running.load(Ordering::SeqCst) {
std::thread::sleep(Duration::from_millis(250));
}
Ok(())
2021-03-18 01:45:16 +00:00
}
2021-04-19 03:06:18 +00:00
fn print_preamble_and_warnings() {
println!(concat!(
env!("CARGO_PKG_NAME"),
" ",
env!("CARGO_PKG_VERSION"),
" Copyright (C) 2021 ",
env!("CARGO_PKG_AUTHORS"),
"\n\n",
env!("CARGO_PKG_NAME"),
" is free software: you can redistribute it and/or modify\n\
it under the terms of the GNU General Public License as published by\n\
the Free Software Foundation, either version 3 of the License, or\n\
(at your option) any later version.\n\n",
env!("CARGO_PKG_NAME"),
" is distributed in the hope that it will be useful,\n\
but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
GNU General Public License for more details.\n\n\
You should have received a copy of the GNU General Public License\n\
along with ",
env!("CARGO_PKG_NAME"),
". If not, see <https://www.gnu.org/licenses/>.\n"
));
}