Skip to main content

ic_query/ic/model/
requests.rs

1//! Module: ic::model::requests
2//!
3//! Responsibility: public IC Dashboard request, query, filter, and selector contracts.
4//! Does not own: reports, host source data, errors, transport, or projection.
5//! Boundary: defines bounded caller intent without performing live work.
6
7use serde::Serialize;
8use std::{fmt, str::FromStr};
9
10///
11/// IcMetricKind
12///
13/// One bounded network metric exposed by the official Dashboard Metrics API.
14///
15
16#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize)]
17#[serde(rename_all = "kebab-case")]
18pub enum IcMetricKind {
19    /// Network instruction execution rate.
20    InstructionRate,
21    /// Network message execution rate.
22    MessageExecutionRate,
23    /// Network cycle burn rate.
24    CycleBurnRate,
25    /// Network block ingestion rate.
26    BlockRate,
27    /// Total and currently up node counts.
28    IcNodeCount,
29    /// Total Subnet count.
30    IcSubnetTotal,
31    /// Running and stopped canister counts.
32    RegisteredCanistersCount,
33    /// Total estimated IC energy-consumption rate in kWh.
34    TotalIcEnergyConsumptionRateKwh,
35    /// Active boundary-node count.
36    BoundaryNodesCount,
37}
38
39impl IcMetricKind {
40    /// Return every metric supported by the bounded report adapter.
41    #[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    /// Return the official Dashboard Metrics API path name.
57    #[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///
106/// IcMetricQuery
107///
108/// One explicitly bounded official Dashboard metric time-series query.
109///
110
111#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
112pub struct IcMetricQuery {
113    /// Official Dashboard metric to retrieve.
114    pub metric: IcMetricKind,
115    /// Inclusive query start as Unix seconds.
116    pub start_unix_secs: u64,
117    /// Inclusive query end as Unix seconds.
118    pub end_unix_secs: u64,
119    /// Requested observation interval in seconds.
120    pub step_secs: u32,
121}
122
123impl IcMetricQuery {
124    /// Construct one explicit metric query window.
125    #[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///
142/// IcMetricRequest
143///
144/// Request accepted by the bounded official Dashboard metric report builder.
145///
146
147#[derive(Clone, Debug, Eq, PartialEq)]
148pub struct IcMetricRequest {
149    /// Dashboard Metrics API base endpoint.
150    pub source_endpoint: String,
151    /// Collection time as Unix seconds.
152    pub now_unix_secs: u64,
153    /// Explicitly bounded metric query.
154    pub query: IcMetricQuery,
155}
156
157impl IcMetricRequest {
158    /// Construct one bounded live Dashboard metric request.
159    #[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///
174/// IcDailyStatsQuery
175///
176/// One explicitly bounded official Dashboard daily-statistics query.
177///
178
179#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
180pub struct IcDailyStatsQuery {
181    /// Inclusive query start as Unix seconds.
182    pub start_unix_secs: u64,
183    /// Inclusive query end as Unix seconds.
184    pub end_unix_secs: u64,
185}
186
187impl IcDailyStatsQuery {
188    /// Construct one explicit daily-statistics query window.
189    #[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///
199/// IcDailyStatsRequest
200///
201/// Request accepted by the bounded official Dashboard daily-statistics builder.
202///
203
204#[derive(Clone, Debug, Eq, PartialEq)]
205pub struct IcDailyStatsRequest {
206    /// Dashboard API v3 base endpoint.
207    pub source_endpoint: String,
208    /// Collection time as Unix seconds.
209    pub now_unix_secs: u64,
210    /// Explicitly bounded daily-statistics query.
211    pub query: IcDailyStatsQuery,
212}
213
214impl IcDailyStatsRequest {
215    /// Construct one bounded live Dashboard daily-statistics request.
216    #[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///
231/// IcBoundaryNodeDataCentersRequest
232///
233/// Request accepted by the official Dashboard boundary-node data-center builder.
234///
235
236#[derive(Clone, Debug, Eq, PartialEq)]
237pub struct IcBoundaryNodeDataCentersRequest {
238    /// Dashboard API v4 base endpoint.
239    pub source_endpoint: String,
240    /// Collection time as Unix seconds.
241    pub now_unix_secs: u64,
242}
243
244impl IcBoundaryNodeDataCentersRequest {
245    /// Construct one live Dashboard boundary-node data-center request.
246    #[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///
256/// IcCanisterRequest
257///
258/// Request accepted by the official Dashboard canister report builder.
259///
260
261#[derive(Clone, Debug, Eq, PartialEq)]
262pub struct IcCanisterRequest {
263    /// Dashboard API base endpoint.
264    pub source_endpoint: String,
265    /// Collection time as Unix seconds.
266    pub now_unix_secs: u64,
267    /// Canister principal to inspect.
268    pub canister_id: String,
269}
270
271impl IcCanisterRequest {
272    /// Construct a live Dashboard canister request.
273    #[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///
288/// IcCanisterFilters
289///
290/// Official Dashboard filters shared by canister count and page requests.
291///
292
293#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
294pub struct IcCanisterFilters {
295    /// Select canisters according to whether the Dashboard records a name.
296    pub has_name: Option<bool>,
297    /// Select canisters assigned to this Subnet principal.
298    pub subnet_id: Option<String>,
299    /// Select canisters controlled by this principal.
300    pub controller_id: Option<String>,
301    /// Raw Dashboard language labels to include.
302    pub languages: Vec<String>,
303    /// Raw Dashboard canister classifications to include.
304    pub canister_types: Vec<String>,
305    /// Raw Dashboard text search, between two and one hundred characters.
306    pub query: Option<String>,
307}
308
309///
310/// IcCanisterCountRequest
311///
312/// Request for one bounded official Dashboard canister-count lookup.
313///
314
315#[derive(Clone, Debug, Eq, PartialEq)]
316pub struct IcCanisterCountRequest {
317    /// Dashboard API v4 base endpoint.
318    pub source_endpoint: String,
319    /// Collection time as Unix seconds.
320    pub now_unix_secs: u64,
321    /// Filters applied by the Dashboard.
322    pub filters: IcCanisterFilters,
323}
324
325impl IcCanisterCountRequest {
326    /// Construct a live Dashboard canister-count request without filters.
327    #[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    /// Set the Dashboard filters used by this request.
337    #[must_use]
338    pub fn with_filters(mut self, filters: IcCanisterFilters) -> Self {
339        self.filters = filters;
340        self
341    }
342}
343
344///
345/// IcCanisterPageRequest
346///
347/// Request for one bounded official Dashboard canister page.
348///
349
350#[derive(Clone, Debug, Eq, PartialEq)]
351pub struct IcCanisterPageRequest {
352    /// Dashboard API v4 base endpoint.
353    pub source_endpoint: String,
354    /// Collection time as Unix seconds.
355    pub now_unix_secs: u64,
356    /// Filters applied by the Dashboard.
357    pub filters: IcCanisterFilters,
358    /// Maximum rows requested from the API.
359    pub limit: u16,
360    /// Exclusive forward cursor returned by an earlier page.
361    pub after: Option<String>,
362    /// Exclusive backward cursor returned by an earlier page.
363    pub before: Option<String>,
364}
365
366impl IcCanisterPageRequest {
367    /// Construct a live Dashboard page request with the default bounded limit.
368    #[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    /// Set the Dashboard filters used by this request.
381    #[must_use]
382    pub fn with_filters(mut self, filters: IcCanisterFilters) -> Self {
383        self.filters = filters;
384        self
385    }
386
387    /// Set the maximum number of returned rows.
388    #[must_use]
389    pub const fn with_limit(mut self, limit: u16) -> Self {
390        self.limit = limit;
391        self
392    }
393
394    /// Set an exclusive forward cursor.
395    #[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    /// Set an exclusive backward cursor.
402    #[must_use]
403    pub fn with_before(mut self, before: impl Into<String>) -> Self {
404        self.before = Some(before.into());
405        self
406    }
407}