diff options
Diffstat (limited to 'src/embed.rs')
-rw-r--r-- | src/embed.rs | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/src/embed.rs b/src/embed.rs new file mode 100644 index 0000000..02dea2f --- /dev/null +++ b/src/embed.rs @@ -0,0 +1,90 @@ +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; + +#[get("/v1/embed?<s>")] +pub async fn r_embed<'a>( + state: &State<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<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() + } +} |