technitium 0.4.0

Typed async Rust client for the Technitium DNS Server API
Documentation
use serde::Deserialize;

/// Time range for dashboard statistics.
#[derive(Debug, Clone)]
pub enum StatsType {
    LastHour,
    LastDay,
    LastWeek,
    LastMonth,
    LastYear,
    /// Custom date range.
    ///
    /// Dates should be in ISO 8601 format: `"YYYY-MM-DD"` or
    /// `"YYYY-MM-DDTHH:mm:ss"` (e.g., `"2026-03-18"` or
    /// `"2026-03-18T14:30:00"`).
    Custom {
        start: String,
        end: String,
    },
}

/// Category for top-stats queries.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TopStatsType {
    /// Top querying clients.
    Clients,
    /// Most queried domains.
    Domains,
    /// Most blocked domains.
    BlockedDomains,
}

impl std::fmt::Display for TopStatsType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Clients => write!(f, "TopClients"),
            Self::Domains => write!(f, "TopDomains"),
            Self::BlockedDomains => write!(f, "TopBlockedDomains"),
        }
    }
}

impl StatsType {
    pub(crate) fn as_str(&self) -> &str {
        match self {
            Self::LastHour => "LastHour",
            Self::LastDay => "LastDay",
            Self::LastWeek => "LastWeek",
            Self::LastMonth => "LastMonth",
            Self::LastYear => "LastYear",
            Self::Custom { .. } => "Custom",
        }
    }
}

/// A data point in the statistics time series.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct StatEntry {
    /// Timestamp label.
    #[serde(default)]
    pub label: Option<String>,
    /// Total queries.
    #[serde(default)]
    pub total_queries: u64,
    /// Total no-error responses.
    #[serde(default)]
    pub total_no_error: u64,
    /// Total blocked queries.
    #[serde(default)]
    pub total_blocked: u64,
}

/// Dashboard statistics response.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DashboardStats {
    /// Aggregate statistics.
    #[serde(default)]
    pub stats: Option<StatEntry>,
    /// All other fields (chart data, etc.).
    #[serde(flatten)]
    pub extra: serde_json::Value,
}

/// Top statistics (top clients, domains, etc.).
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TopStats {
    /// All fields returned by the top stats endpoint.
    #[serde(flatten)]
    pub data: serde_json::Value,
}