1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
#![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::<Vec<_>>());
}
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::<shield::Frame>())
.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<T>(pub T);
impl<'r, T: Render> Responder<'r, 'static> for Template<T> {
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...")
}
|