#![warn (clippy::pedantic)]
use std::{
net::SocketAddr,
path::PathBuf,
sync::Arc,
};
use arc_swap::ArcSwap;
use hyper::{
Body,
Request,
Response,
Server,
service::{
make_service_fn,
service_fn,
},
StatusCode,
};
use serde::Deserialize;
use tracing::debug;
use ptth_core::{
http_serde::RequestParts,
prelude::*,
};
use ptth_server::{
file_server::{
self,
metrics,
State,
},
load_toml,
};
async fn handle_all (req: Request
, state: Arc )
-> Result , anyhow::Error>
{
use std::str::FromStr;
use hyper::header::HeaderName;
debug! ("req.uri () = {:?}", req.uri ());
let path_and_query = req.uri ().path_and_query ().map_or_else (|| req.uri ().path (), http::uri::PathAndQuery::as_str);
let path_and_query = path_and_query.into ();
let (parts, _) = req.into_parts ();
let ptth_req = RequestParts::from_hyper (parts.method, path_and_query, parts.headers)?;
let default_root = PathBuf::from ("./");
let file_server_root: &std::path::Path = state.config.file_server_root
.as_ref ()
.unwrap_or (&default_root);
let ptth_resp = file_server::serve_all (
&state,
file_server_root,
ptth_req.method,
&ptth_req.uri,
&ptth_req.headers
).await?;
let mut resp = Response::builder ()
.status (StatusCode::from (ptth_resp.parts.status_code));
for (k, v) in ptth_resp.parts.headers {
resp = resp.header (HeaderName::from_str (&k)?, v);
}
let body = ptth_resp.body.map_or_else (Body::empty, Body::wrap_stream);
Ok (resp.body (body)?)
}
#[derive (Deserialize)]
pub struct ConfigFile {
pub file_server_root: Option ,
pub name: Option ,
}
#[tokio::main]
async fn main () -> Result <(), anyhow::Error> {
tracing_subscriber::fmt::init ();
let path = PathBuf::from ("./config/ptth_server.toml");
let config_file: ConfigFile = load_toml::load (&path)?;
info! ("file_server_root: {:?}", config_file.file_server_root);
let addr = SocketAddr::from(([0, 0, 0, 0], 4000));
let handlebars = file_server::load_templates (&PathBuf::new ())?;
let metrics_startup = metrics::Startup::new (
config_file.name.unwrap_or_else (|| "PTTH File Server".to_string ())
);
let metrics_interval = Arc::new (ArcSwap::default ());
let interval_writer = Arc::clone (&metrics_interval);
tokio::spawn (async move {
use std::time::Duration;
use uom::si::ratio::percent;
let mut interval = tokio::time::interval (Duration::from_secs (60));
let mut counter = 0_u64;
let mut next_10_time = counter;
let mut metrics_at_last_10: Arc