use serde::Serialize;
use std::{fmt, str::FromStr};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum IcMetricKind {
InstructionRate,
MessageExecutionRate,
CycleBurnRate,
BlockRate,
IcNodeCount,
IcSubnetTotal,
RegisteredCanistersCount,
TotalIcEnergyConsumptionRateKwh,
BoundaryNodesCount,
}
impl IcMetricKind {
#[must_use]
pub const fn all() -> [Self; 9] {
[
Self::InstructionRate,
Self::MessageExecutionRate,
Self::CycleBurnRate,
Self::BlockRate,
Self::IcNodeCount,
Self::IcSubnetTotal,
Self::RegisteredCanistersCount,
Self::TotalIcEnergyConsumptionRateKwh,
Self::BoundaryNodesCount,
]
}
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::InstructionRate => "instruction-rate",
Self::MessageExecutionRate => "message-execution-rate",
Self::CycleBurnRate => "cycle-burn-rate",
Self::BlockRate => "block-rate",
Self::IcNodeCount => "ic-node-count",
Self::IcSubnetTotal => "ic-subnet-total",
Self::RegisteredCanistersCount => "registered-canisters-count",
Self::TotalIcEnergyConsumptionRateKwh => "total-ic-energy-consumption-rate-kwh",
Self::BoundaryNodesCount => "boundary-nodes-count",
}
}
#[cfg(feature = "host")]
pub(crate) const fn series_names(self) -> &'static [&'static str] {
match self {
Self::InstructionRate => &["instruction_rate"],
Self::MessageExecutionRate => &["message_execution_rate"],
Self::CycleBurnRate => &["cycle_burn_rate"],
Self::BlockRate => &["block_rate"],
Self::IcNodeCount => &["total_nodes", "up_nodes"],
Self::IcSubnetTotal => &["ic_subnet_total"],
Self::RegisteredCanistersCount => &["running_canisters", "stopped_canisters"],
Self::TotalIcEnergyConsumptionRateKwh => &["energy_consumption_rate"],
Self::BoundaryNodesCount => &["boundary_nodes_count"],
}
}
}
impl fmt::Display for IcMetricKind {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
impl FromStr for IcMetricKind {
type Err = String;
fn from_str(value: &str) -> Result<Self, Self::Err> {
Self::all()
.into_iter()
.find(|metric| metric.as_str() == value)
.ok_or_else(|| format!("unsupported IC Dashboard metric {value:?}"))
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct IcMetricQuery {
pub metric: IcMetricKind,
pub start_unix_secs: u64,
pub end_unix_secs: u64,
pub step_secs: u32,
}
impl IcMetricQuery {
#[must_use]
pub const fn new(
metric: IcMetricKind,
start_unix_secs: u64,
end_unix_secs: u64,
step_secs: u32,
) -> Self {
Self {
metric,
start_unix_secs,
end_unix_secs,
step_secs,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct IcMetricRequest {
pub source_endpoint: String,
pub now_unix_secs: u64,
pub query: IcMetricQuery,
}
impl IcMetricRequest {
#[must_use]
pub fn new(
source_endpoint: impl Into<String>,
now_unix_secs: u64,
query: IcMetricQuery,
) -> Self {
Self {
source_endpoint: source_endpoint.into(),
now_unix_secs,
query,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct IcDailyStatsQuery {
pub start_unix_secs: u64,
pub end_unix_secs: u64,
}
impl IcDailyStatsQuery {
#[must_use]
pub const fn new(start_unix_secs: u64, end_unix_secs: u64) -> Self {
Self {
start_unix_secs,
end_unix_secs,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct IcDailyStatsRequest {
pub source_endpoint: String,
pub now_unix_secs: u64,
pub query: IcDailyStatsQuery,
}
impl IcDailyStatsRequest {
#[must_use]
pub fn new(
source_endpoint: impl Into<String>,
now_unix_secs: u64,
query: IcDailyStatsQuery,
) -> Self {
Self {
source_endpoint: source_endpoint.into(),
now_unix_secs,
query,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct IcBoundaryNodeDataCentersRequest {
pub source_endpoint: String,
pub now_unix_secs: u64,
}
impl IcBoundaryNodeDataCentersRequest {
#[must_use]
pub fn new(source_endpoint: impl Into<String>, now_unix_secs: u64) -> Self {
Self {
source_endpoint: source_endpoint.into(),
now_unix_secs,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct IcCanisterRequest {
pub source_endpoint: String,
pub now_unix_secs: u64,
pub canister_id: String,
}
impl IcCanisterRequest {
#[must_use]
pub fn new(
source_endpoint: impl Into<String>,
now_unix_secs: u64,
canister_id: impl Into<String>,
) -> Self {
Self {
source_endpoint: source_endpoint.into(),
now_unix_secs,
canister_id: canister_id.into(),
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
pub struct IcCanisterFilters {
pub has_name: Option<bool>,
pub subnet_id: Option<String>,
pub controller_id: Option<String>,
pub languages: Vec<String>,
pub canister_types: Vec<String>,
pub query: Option<String>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct IcCanisterCountRequest {
pub source_endpoint: String,
pub now_unix_secs: u64,
pub filters: IcCanisterFilters,
}
impl IcCanisterCountRequest {
#[must_use]
pub fn new(source_endpoint: impl Into<String>, now_unix_secs: u64) -> Self {
Self {
source_endpoint: source_endpoint.into(),
now_unix_secs,
filters: IcCanisterFilters::default(),
}
}
#[must_use]
pub fn with_filters(mut self, filters: IcCanisterFilters) -> Self {
self.filters = filters;
self
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct IcCanisterPageRequest {
pub source_endpoint: String,
pub now_unix_secs: u64,
pub filters: IcCanisterFilters,
pub limit: u16,
pub after: Option<String>,
pub before: Option<String>,
}
impl IcCanisterPageRequest {
#[must_use]
pub fn new(source_endpoint: impl Into<String>, now_unix_secs: u64) -> Self {
Self {
source_endpoint: source_endpoint.into(),
now_unix_secs,
filters: IcCanisterFilters::default(),
limit: crate::ic::DEFAULT_IC_CANISTER_PAGE_LIMIT,
after: None,
before: None,
}
}
#[must_use]
pub fn with_filters(mut self, filters: IcCanisterFilters) -> Self {
self.filters = filters;
self
}
#[must_use]
pub const fn with_limit(mut self, limit: u16) -> Self {
self.limit = limit;
self
}
#[must_use]
pub fn with_after(mut self, after: impl Into<String>) -> Self {
self.after = Some(after.into());
self
}
#[must_use]
pub fn with_before(mut self, before: impl Into<String>) -> Self {
self.before = Some(before.into());
self
}
}