webserver_base/
axum_plausible_analytics.rs1use axum::http::{HeaderMap, StatusCode};
2use plausible_rs::{EventHeaders, EventPayload, PAGEVIEW_EVENT, Plausible};
3use reqwest::Client;
4use serde::{Deserialize, Serialize};
5use std::net::SocketAddr;
6use std::sync::Arc;
7use tracing::{error, info, instrument, warn};
8
9use crate::{
10 base_settings::{BaseSettings, Environment},
11 ip::resolve_true_client_ip_address,
12};
13
14#[derive(Debug, Serialize, Deserialize)]
15pub struct RequestPayload {
16 pub user_agent: String,
17 pub url: String,
18 pub referrer: String,
19 pub screen_width: usize,
20}
21
22pub struct AxumPlausibleAnalyticsHandler {
23 plausible_client: Plausible,
24}
25
26impl AxumPlausibleAnalyticsHandler {
27 #[must_use]
28 #[instrument(skip_all)]
29 pub fn new_with_client(http_client: Client) -> Self {
30 Self {
31 plausible_client: Plausible::new_with_client(http_client),
32 }
33 }
34
35 #[instrument(skip_all)]
36 pub async fn handle(
37 self: Arc<Self>,
38 headers: HeaderMap,
39 settings: BaseSettings,
40 addr: SocketAddr,
41 incoming_payload: RequestPayload,
42 ) -> StatusCode {
43 let domain: String = if settings.environment == Environment::Production {
45 settings.analytics_domain.clone()
46 } else {
47 String::from("test.toddgriffin.me")
48 };
49 let outgoing_payload: EventPayload = EventPayload::builder(
50 domain,
51 PAGEVIEW_EVENT.to_string(),
52 incoming_payload.url.clone(),
53 )
54 .referrer(incoming_payload.referrer.clone())
55 .screen_width(incoming_payload.screen_width)
56 .build();
57
58 let real_client_ip: String = resolve_true_client_ip_address(addr, headers);
60 let headers: EventHeaders =
61 EventHeaders::new(incoming_payload.user_agent.clone(), real_client_ip);
62
63 info!(
64 "Making Plausible Analytics calls with headers={:?} and body={:?}",
65 headers.clone(),
66 outgoing_payload.clone()
67 );
68 match self.plausible_client.event(headers, outgoing_payload).await {
70 Ok(bytes) => {
71 info!(
72 "Plausible Analytics call was a success: {}",
73 String::from_utf8_lossy(&bytes)
74 );
75 StatusCode::OK
76 }
77 Err(e) => {
78 error!("Failed Plausible Analytics call: {}", e);
79 StatusCode::INTERNAL_SERVER_ERROR
80 }
81 }
82 }
83}