aboutsummaryrefslogtreecommitdiff
path: root/src/embed.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/embed.rs')
-rw-r--r--src/embed.rs90
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()
+ }
+}