adguardian/fetch/
fetch_stats.rs1use reqwest::{
6 header::{HeaderValue, CONTENT_LENGTH, AUTHORIZATION},
7};
8use serde::Deserialize;
9use std::collections::HashMap;
10
11#[derive(Debug, Deserialize, Clone)]
12pub struct DomainData {
13 pub name: String,
14 pub count: i32,
15}
16
17#[derive(Debug, Deserialize, Clone)]
18pub struct StatsResponse {
19 pub num_dns_queries: u64,
20 pub num_blocked_filtering: u64,
21 pub num_replaced_safebrowsing: u64,
22 pub num_replaced_safesearch: u64,
23 pub num_replaced_parental: u64,
24 pub avg_processing_time: f64,
25 pub dns_queries: Vec<u64>,
26 pub blocked_filtering: Vec<u64>,
27 pub replaced_safebrowsing: Vec<u64>,
28 pub replaced_parental: Vec<u64>,
29
30 #[serde(default, skip_deserializing)]
31 pub dns_queries_chart: Vec<(f64, f64)>,
32 #[serde(default, skip_deserializing)]
33 pub blocked_filtering_chart: Vec<(f64, f64)>,
34
35 #[serde(rename = "top_queried_domains", deserialize_with = "deserialize_domains")]
36 pub top_queried_domains: Vec<DomainData>,
37 #[serde(rename = "top_blocked_domains", deserialize_with = "deserialize_domains")]
38 pub top_blocked_domains: Vec<DomainData>,
39 #[serde(rename = "top_clients", deserialize_with = "deserialize_domains")]
40 pub top_clients: Vec<DomainData>,
41}
42
43pub async fn fetch_adguard_stats(
44 client: &reqwest::Client,
45 endpoint: &str,
46 username: &str,
47 password: &str,
48) -> Result<StatsResponse, anyhow::Error> {
49 let auth_string = format!("{}:{}", username, password);
50 let auth_header_value = format!("Basic {}", base64::encode(&auth_string));
51 let mut headers = reqwest::header::HeaderMap::new();
52 headers.insert(AUTHORIZATION, auth_header_value.parse()?);
53 headers.insert(CONTENT_LENGTH, HeaderValue::from_static("0"));
54
55 let url = format!("{}/control/stats", endpoint);
56 let response = client.get(&url).headers(headers).send().await?;
57 if !response.status().is_success() {
58 return Err(anyhow::anyhow!("Request failed with status code {}", response.status()));
59 }
60
61 let data = response.json().await?;
62 Ok(data)
63}
64
65fn deserialize_domains<'de, D>(deserializer: D) -> Result<Vec<DomainData>, D::Error>
67where
68 D: serde::Deserializer<'de>,
69{
70 let raw_vec: Vec<HashMap<String, i32>> = serde::Deserialize::deserialize(deserializer)?;
71 Ok(raw_vec
72 .into_iter()
73 .flat_map(|mut map| {
74 map.drain().map(|(name, count)| DomainData { name, count }).collect::<Vec<_>>()
75 })
76 .collect())
77}
78