123 lines
3.0 KiB
Rust
123 lines
3.0 KiB
Rust
use std::{path::PathBuf, sync::Arc};
|
|
|
|
use argh::FromArgs;
|
|
use color_eyre::eyre::{self, Context, bail};
|
|
use engine::Engine;
|
|
|
|
use axum::{
|
|
Router,
|
|
routing::{get, post},
|
|
};
|
|
use tokio::{fs, net::TcpListener, signal};
|
|
use tracing::{info, warn};
|
|
|
|
mod cache;
|
|
mod config;
|
|
mod delete;
|
|
mod disk;
|
|
mod engine;
|
|
mod index;
|
|
mod new;
|
|
mod view;
|
|
|
|
#[cfg(not(target_env = "msvc"))]
|
|
use tikv_jemallocator::Jemalloc;
|
|
|
|
#[cfg(not(target_env = "msvc"))]
|
|
#[global_allocator]
|
|
static GLOBAL: Jemalloc = Jemalloc;
|
|
|
|
/// breeze file server.
|
|
#[derive(FromArgs, Debug)]
|
|
struct Args {
|
|
/// the path to *.toml configuration file
|
|
#[argh(option, short = 'c', arg_name = "file")]
|
|
config: PathBuf,
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() -> eyre::Result<()> {
|
|
// Install color-eyre
|
|
color_eyre::install()?;
|
|
|
|
// Read & parse args
|
|
let args: Args = argh::from_env();
|
|
|
|
// Read & parse config
|
|
let cfg: config::Config = {
|
|
let config_str = fs::read_to_string(args.config).await.wrap_err(
|
|
"failed to read config file! make sure it exists and you have read permissions",
|
|
)?;
|
|
|
|
toml::from_str(&config_str).wrap_err(
|
|
"invalid config! ensure proper fields and structure. reference config is in readme",
|
|
)?
|
|
};
|
|
|
|
// Set up tracing
|
|
tracing_subscriber::fmt()
|
|
.with_max_level(cfg.logger.level)
|
|
.init();
|
|
|
|
// Check config
|
|
{
|
|
let save_path = cfg.engine.disk.save_path.clone();
|
|
if !save_path.exists() || !save_path.is_dir() {
|
|
bail!("the save path does not exist or is not a directory! this is invalid");
|
|
}
|
|
}
|
|
if cfg.engine.upload_key.is_empty() {
|
|
warn!("engine upload_key is empty! no key will be required for uploading new files");
|
|
}
|
|
|
|
// Create engine
|
|
let engine = Engine::with_config(cfg.engine);
|
|
|
|
// Build main router
|
|
let app = Router::new()
|
|
.route("/new", post(new::new))
|
|
.route("/p/{saved_name}", get(view::view))
|
|
.route("/del", get(delete::delete))
|
|
.route("/", get(index::index))
|
|
.route("/robots.txt", get(index::robots_txt))
|
|
.with_state(Arc::new(engine));
|
|
|
|
// Start web server
|
|
info!("starting server.");
|
|
let listener = TcpListener::bind(&cfg.http.listen_on)
|
|
.await
|
|
.wrap_err("failed to bind to given `http.listen_on` address! make sure it's valid, and the port isn't already bound")?;
|
|
axum::serve(listener, app)
|
|
.with_graceful_shutdown(shutdown_signal())
|
|
.await
|
|
.wrap_err("failed to start server")?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
async fn shutdown_signal() {
|
|
let ctrl_c = async {
|
|
signal::ctrl_c()
|
|
.await
|
|
.expect("failed to add SIGINT handler");
|
|
};
|
|
|
|
#[cfg(unix)]
|
|
let terminate = async {
|
|
signal::unix::signal(signal::unix::SignalKind::terminate())
|
|
.expect("failed to add SIGTERM handler")
|
|
.recv()
|
|
.await;
|
|
};
|
|
|
|
#[cfg(not(unix))]
|
|
let terminate = std::future::pending::<()>();
|
|
|
|
tokio::select! {
|
|
() = ctrl_c => {},
|
|
() = terminate => {},
|
|
}
|
|
|
|
info!("shutting down!");
|
|
}
|