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?")] pub async fn r_embed<'a>( state: &State>, addr: IpAddr, s: &str, ) -> MyResult>> { 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?")] pub async fn r_image(state: &State>, k: &str) -> MyResult { let info = state .config .ads .get(&k.to_owned()) .ok_or(anyhow!("ad does not exist"))?; Ok(CachedImage( File::open(state.config.ad_dir.join(&info.image)).await?, )) } pub struct CachedImage(File); impl<'r> Responder<'r, 'static> for CachedImage { fn respond_to(self, _req: &'r Request<'_>) -> response::Result<'static> { Response::build() .status(Status::Ok) .header(Header::new("cache-control", "max-age=3600, public")) .header(Header::new("content-type", "image/webp")) .streamed_body(self.0) .ok() } }