1use serde::Serialize;
8use std::{fmt, str::FromStr};
9
10#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize)]
17#[serde(rename_all = "kebab-case")]
18pub enum IcMetricKind {
19 InstructionRate,
21 MessageExecutionRate,
23 CycleBurnRate,
25 BlockRate,
27 IcNodeCount,
29 IcSubnetTotal,
31 RegisteredCanistersCount,
33 TotalIcEnergyConsumptionRateKwh,
35 BoundaryNodesCount,
37}
38
39impl IcMetricKind {
40 #[must_use]
42 pub const fn all() -> [Self; 9] {
43 [
44 Self::InstructionRate,
45 Self::MessageExecutionRate,
46 Self::CycleBurnRate,
47 Self::BlockRate,
48 Self::IcNodeCount,
49 Self::IcSubnetTotal,
50 Self::RegisteredCanistersCount,
51 Self::TotalIcEnergyConsumptionRateKwh,
52 Self::BoundaryNodesCount,
53 ]
54 }
55
56 #[must_use]
58 pub const fn as_str(self) -> &'static str {
59 match self {
60 Self::InstructionRate => "instruction-rate",
61 Self::MessageExecutionRate => "message-execution-rate",
62 Self::CycleBurnRate => "cycle-burn-rate",
63 Self::BlockRate => "block-rate",
64 Self::IcNodeCount => "ic-node-count",
65 Self::IcSubnetTotal => "ic-subnet-total",
66 Self::RegisteredCanistersCount => "registered-canisters-count",
67 Self::TotalIcEnergyConsumptionRateKwh => "total-ic-energy-consumption-rate-kwh",
68 Self::BoundaryNodesCount => "boundary-nodes-count",
69 }
70 }
71
72 #[cfg(feature = "host")]
73 pub(crate) const fn series_names(self) -> &'static [&'static str] {
74 match self {
75 Self::InstructionRate => &["instruction_rate"],
76 Self::MessageExecutionRate => &["message_execution_rate"],
77 Self::CycleBurnRate => &["cycle_burn_rate"],
78 Self::BlockRate => &["block_rate"],
79 Self::IcNodeCount => &["total_nodes", "up_nodes"],
80 Self::IcSubnetTotal => &["ic_subnet_total"],
81 Self::RegisteredCanistersCount => &["running_canisters", "stopped_canisters"],
82 Self::TotalIcEnergyConsumptionRateKwh => &["energy_consumption_rate"],
83 Self::BoundaryNodesCount => &["boundary_nodes_count"],
84 }
85 }
86}
87
88impl fmt::Display for IcMetricKind {
89 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
90 formatter.write_str(self.as_str())
91 }
92}
93
94impl FromStr for IcMetricKind {
95 type Err = String;
96
97 fn from_str(value: &str) -> Result<Self, Self::Err> {
98 Self::all()
99 .into_iter()
100 .find(|metric| metric.as_str() == value)
101 .ok_or_else(|| format!("unsupported IC Dashboard metric {value:?}"))
102 }
103}
104
105#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
112pub struct IcMetricQuery {
113 pub metric: IcMetricKind,
115 pub start_unix_secs: u64,
117 pub end_unix_secs: u64,
119 pub step_secs: u32,
121}
122
123impl IcMetricQuery {
124 #[must_use]
126 pub const fn new(
127 metric: IcMetricKind,
128 start_unix_secs: u64,
129 end_unix_secs: u64,
130 step_secs: u32,
131 ) -> Self {
132 Self {
133 metric,
134 start_unix_secs,
135 end_unix_secs,
136 step_secs,
137 }
138 }
139}
140
141#[derive(Clone, Debug, Eq, PartialEq)]
148pub struct IcMetricRequest {
149 pub source_endpoint: String,
151 pub now_unix_secs: u64,
153 pub query: IcMetricQuery,
155}
156
157impl IcMetricRequest {
158 #[must_use]
160 pub fn new(
161 source_endpoint: impl Into<String>,
162 now_unix_secs: u64,
163 query: IcMetricQuery,
164 ) -> Self {
165 Self {
166 source_endpoint: source_endpoint.into(),
167 now_unix_secs,
168 query,
169 }
170 }
171}
172
173#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
180pub struct IcDailyStatsQuery {
181 pub start_unix_secs: u64,
183 pub end_unix_secs: u64,
185}
186
187impl IcDailyStatsQuery {
188 #[must_use]
190 pub const fn new(start_unix_secs: u64, end_unix_secs: u64) -> Self {
191 Self {
192 start_unix_secs,
193 end_unix_secs,
194 }
195 }
196}
197
198#[derive(Clone, Debug, Eq, PartialEq)]
205pub struct IcDailyStatsRequest {
206 pub source_endpoint: String,
208 pub now_unix_secs: u64,
210 pub query: IcDailyStatsQuery,
212}
213
214impl IcDailyStatsRequest {
215 #[must_use]
217 pub fn new(
218 source_endpoint: impl Into<String>,
219 now_unix_secs: u64,
220 query: IcDailyStatsQuery,
221 ) -> Self {
222 Self {
223 source_endpoint: source_endpoint.into(),
224 now_unix_secs,
225 query,
226 }
227 }
228}
229
230#[derive(Clone, Debug, Eq, PartialEq)]
237pub struct IcBoundaryNodeDataCentersRequest {
238 pub source_endpoint: String,
240 pub now_unix_secs: u64,
242}
243
244impl IcBoundaryNodeDataCentersRequest {
245 #[must_use]
247 pub fn new(source_endpoint: impl Into<String>, now_unix_secs: u64) -> Self {
248 Self {
249 source_endpoint: source_endpoint.into(),
250 now_unix_secs,
251 }
252 }
253}
254
255#[derive(Clone, Debug, Eq, PartialEq)]
262pub struct IcCanisterRequest {
263 pub source_endpoint: String,
265 pub now_unix_secs: u64,
267 pub canister_id: String,
269}
270
271impl IcCanisterRequest {
272 #[must_use]
274 pub fn new(
275 source_endpoint: impl Into<String>,
276 now_unix_secs: u64,
277 canister_id: impl Into<String>,
278 ) -> Self {
279 Self {
280 source_endpoint: source_endpoint.into(),
281 now_unix_secs,
282 canister_id: canister_id.into(),
283 }
284 }
285}
286
287#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
294pub struct IcCanisterFilters {
295 pub has_name: Option<bool>,
297 pub subnet_id: Option<String>,
299 pub controller_id: Option<String>,
301 pub languages: Vec<String>,
303 pub canister_types: Vec<String>,
305 pub query: Option<String>,
307}
308
309#[derive(Clone, Debug, Eq, PartialEq)]
316pub struct IcCanisterCountRequest {
317 pub source_endpoint: String,
319 pub now_unix_secs: u64,
321 pub filters: IcCanisterFilters,
323}
324
325impl IcCanisterCountRequest {
326 #[must_use]
328 pub fn new(source_endpoint: impl Into<String>, now_unix_secs: u64) -> Self {
329 Self {
330 source_endpoint: source_endpoint.into(),
331 now_unix_secs,
332 filters: IcCanisterFilters::default(),
333 }
334 }
335
336 #[must_use]
338 pub fn with_filters(mut self, filters: IcCanisterFilters) -> Self {
339 self.filters = filters;
340 self
341 }
342}
343
344#[derive(Clone, Debug, Eq, PartialEq)]
351pub struct IcCanisterPageRequest {
352 pub source_endpoint: String,
354 pub now_unix_secs: u64,
356 pub filters: IcCanisterFilters,
358 pub limit: u16,
360 pub after: Option<String>,
362 pub before: Option<String>,
364}
365
366impl IcCanisterPageRequest {
367 #[must_use]
369 pub fn new(source_endpoint: impl Into<String>, now_unix_secs: u64) -> Self {
370 Self {
371 source_endpoint: source_endpoint.into(),
372 now_unix_secs,
373 filters: IcCanisterFilters::default(),
374 limit: crate::ic::DEFAULT_IC_CANISTER_PAGE_LIMIT,
375 after: None,
376 before: None,
377 }
378 }
379
380 #[must_use]
382 pub fn with_filters(mut self, filters: IcCanisterFilters) -> Self {
383 self.filters = filters;
384 self
385 }
386
387 #[must_use]
389 pub const fn with_limit(mut self, limit: u16) -> Self {
390 self.limit = limit;
391 self
392 }
393
394 #[must_use]
396 pub fn with_after(mut self, after: impl Into<String>) -> Self {
397 self.after = Some(after.into());
398 self
399 }
400
401 #[must_use]
403 pub fn with_before(mut self, before: impl Into<String>) -> Self {
404 self.before = Some(before.into());
405 self
406 }
407}