#![feature(duration_constructors)] pub mod embed; pub mod error; pub mod info; pub mod state; pub mod tool; use anyhow::{anyhow, Context}; use embed::*; use info::*; use markup::Render; use rocket::{ catch, catchers, fairing::AdHoc, get, http::{ContentType, Header, Status}, response::{self, Responder}, routes, shield::{self, Shield}, tokio::{self}, Request, Response, }; use state::{AdInfo, Config, Logic}; use std::{env::args, fs::read_to_string, io::Cursor, net::IpAddr}; use tool::tool_main; fn main() -> anyhow::Result<()> { env_logger::init_from_env("LOG"); let mut args = args().skip(1); let config = args.next().expect("first arg needs to be the config"); let config = read_to_string(config).context(anyhow!("could not read config"))?; let mut config: Config = toml::from_str(config.as_str()).context(anyhow!("config invalid"))?; if let Some(action) = args.next() { return tool_main(config, &action, args.collect::>()); } for entry in config .ad_dir .read_dir() .context(anyhow!("cannot read ad directory"))? { if let Ok(entry) = entry { if entry .path() .file_name() .unwrap() .to_str() .unwrap() .ends_with(".toml") { let path = entry.path(); let imname = path.file_stem().unwrap().to_str().unwrap(); let basename = imname.split_once(".").unwrap().0; let info: AdInfo = toml::from_str(&read_to_string(entry.path()).unwrap()).unwrap(); config.ads.insert( basename.to_string(), AdInfo { image: imname.into(), ..info }, ); } } } tokio::runtime::Builder::new_multi_thread() .enable_all() .build()? .block_on(inner_main(config)); Ok(()) } async fn inner_main(config: Config) { let state = Logic::new(config); let _ = rocket::build() .configure(rocket::Config { port: state.config.port, ..Default::default() }) .attach(Shield::default().disable::()) .attach(AdHoc::on_response("set server header", |_req, res| { res.set_header(Header::new("server", "meta adservices")); Box::pin(async {}) })) .manage(state) .mount("/", routes![r_index, r_embed, r_style, r_image, r_iptest]) .register("/", catchers![r_catch]) .launch() .await; } #[get("/myip")] fn r_iptest(addr: IpAddr) -> String { format!("{addr}") } pub struct Template(pub T); impl<'r, T: Render> Responder<'r, 'static> for Template { fn respond_to(self, _req: &'r Request<'_>) -> response::Result<'static> { let mut out = String::new(); self.0.render(&mut out).unwrap(); Response::build() .header(ContentType::HTML) .streamed_body(Cursor::new(out)) .ok() } } #[catch(default)] pub fn r_catch<'a>(status: Status, _request: &Request) -> String { format!("{status}; This ad is likely misconfigured. Server could also be broken...") }