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
|
use crate::{error::MyResult, state::Logic, Template};
use anyhow::anyhow;
use log::warn;
use markup::{doctype, DynRender};
use rand::{seq::IndexedRandom, thread_rng};
use rocket::{
get,
http::{Header, Status},
response::{self, Responder},
tokio::fs::File,
uri, Request, Response, State,
};
use std::net::IpAddr;
use std::sync::Arc;
#[get("/v1/embed?<s>")]
pub async fn r_embed<'a>(
state: &State<Arc<Logic>>,
addr: IpAddr,
s: &str,
) -> MyResult<Template<DynRender<'a>>> {
let key = state
.ad_keys
.choose(&mut thread_rng())
.ok_or(anyhow!("no ads configured"))?;
let ad = state.config.ads.get(key).unwrap();
let image_url = uri!(r_image(key)).to_string();
let target_url = ad.target.clone();
if let Err(e) = state.register_impression(s, &key, addr).await {
warn!("could not register impression: {e}")
}
Ok(Template(markup::new! {
@doctype()
html {
head {
title { "advertisement by meta adservices" }
style {
"*{user-select:none}"
"body,p{margin:0px}"
"div,p{position:absolute}"
"p{font-size:11px;bottom:0px;right:0px;color:#fff;background-color:#0009}"
"body{width:728px;height:90px;overflow:hidden;position:relative;background-color:grey}"
"div{pointer-events:none;opacity:0;transition:opacity 0.5s;top:-64px;left:-300px;width:374px;background-color:#fffa}"
"button:hover div{opacity:1}"
"button{border:none;width:22px;height:22px}"
}
}
body {
a[href=&target_url,target="_blank"] { img[src=&image_url, width=728, height=90]; }
p {
"Ad by meta "
a[href="/", target="_blank"]{ button {
"🛈"
div {
"advertisement by meta adservices." br;
"meta adservices is a non-profit non-registered organisation" br;
"eager to flooding the internet with useless ads." br;
i{"(click for more information)"}
}
} }
}
}
}
}))
}
#[get("/v1/image?<k>")]
pub async fn r_image(state: &State<Arc<Logic>>, k: &str) -> MyResult<CachedFile> {
let info = state
.config
.ads
.get(&k.to_owned())
.ok_or(anyhow!("ad does not exist"))?;
Ok(CachedFile(
File::open(state.config.image_base.join(&info.image)).await?,
))
}
pub struct CachedFile(File);
impl<'r> Responder<'r, 'static> for CachedFile {
fn respond_to(self, _req: &'r Request<'_>) -> response::Result<'static> {
Response::build()
.status(Status::Ok)
.header(Header::new("cache-control", "max-age=3600, public"))
.streamed_body(self.0)
.ok()
}
}
|