aboutsummaryrefslogtreecommitdiff
path: root/src/embed.rs
blob: b3342cdaf684829fd961d9ee6cfa2453b9d13192 (plain)
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
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<CachedImage> {
    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()
    }
}