ic_query/ic/model.rs
1//! Module: ic::model
2//!
3//! Responsibility: public IC Dashboard requests, source data, reports, and errors.
4//! Does not own: HTTP transport, source validation, report assembly, or rendering.
5//! Boundary: preserves raw Dashboard values and explicit off-chain provenance.
6
7#[cfg(feature = "host")]
8use crate::runtime::RuntimeError;
9use serde::Serialize;
10use std::{fmt, str::FromStr};
11#[cfg(feature = "host")]
12use thiserror::Error as ThisError;
13
14///
15/// IcMetricKind
16///
17/// One bounded network metric exposed by the official Dashboard Metrics API.
18///
19
20#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize)]
21#[serde(rename_all = "kebab-case")]
22pub enum IcMetricKind {
23 /// Network instruction execution rate.
24 InstructionRate,
25 /// Network message execution rate.
26 MessageExecutionRate,
27 /// Network cycle burn rate.
28 CycleBurnRate,
29 /// Network block ingestion rate.
30 BlockRate,
31 /// Total and currently up node counts.
32 IcNodeCount,
33 /// Total Subnet count.
34 IcSubnetTotal,
35 /// Running and stopped canister counts.
36 RegisteredCanistersCount,
37 /// Total estimated IC energy-consumption rate in kWh.
38 TotalIcEnergyConsumptionRateKwh,
39 /// Active boundary-node count.
40 BoundaryNodesCount,
41}
42
43impl IcMetricKind {
44 /// Return every metric supported by the bounded report adapter.
45 #[must_use]
46 pub const fn all() -> [Self; 9] {
47 [
48 Self::InstructionRate,
49 Self::MessageExecutionRate,
50 Self::CycleBurnRate,
51 Self::BlockRate,
52 Self::IcNodeCount,
53 Self::IcSubnetTotal,
54 Self::RegisteredCanistersCount,
55 Self::TotalIcEnergyConsumptionRateKwh,
56 Self::BoundaryNodesCount,
57 ]
58 }
59
60 /// Return the official Dashboard Metrics API path name.
61 #[must_use]
62 pub const fn as_str(self) -> &'static str {
63 match self {
64 Self::InstructionRate => "instruction-rate",
65 Self::MessageExecutionRate => "message-execution-rate",
66 Self::CycleBurnRate => "cycle-burn-rate",
67 Self::BlockRate => "block-rate",
68 Self::IcNodeCount => "ic-node-count",
69 Self::IcSubnetTotal => "ic-subnet-total",
70 Self::RegisteredCanistersCount => "registered-canisters-count",
71 Self::TotalIcEnergyConsumptionRateKwh => "total-ic-energy-consumption-rate-kwh",
72 Self::BoundaryNodesCount => "boundary-nodes-count",
73 }
74 }
75
76 #[cfg(feature = "host")]
77 pub(crate) const fn series_names(self) -> &'static [&'static str] {
78 match self {
79 Self::InstructionRate => &["instruction_rate"],
80 Self::MessageExecutionRate => &["message_execution_rate"],
81 Self::CycleBurnRate => &["cycle_burn_rate"],
82 Self::BlockRate => &["block_rate"],
83 Self::IcNodeCount => &["total_nodes", "up_nodes"],
84 Self::IcSubnetTotal => &["ic_subnet_total"],
85 Self::RegisteredCanistersCount => &["running_canisters", "stopped_canisters"],
86 Self::TotalIcEnergyConsumptionRateKwh => &["energy_consumption_rate"],
87 Self::BoundaryNodesCount => &["boundary_nodes_count"],
88 }
89 }
90}
91
92impl fmt::Display for IcMetricKind {
93 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
94 formatter.write_str(self.as_str())
95 }
96}
97
98impl FromStr for IcMetricKind {
99 type Err = String;
100
101 fn from_str(value: &str) -> Result<Self, Self::Err> {
102 Self::all()
103 .into_iter()
104 .find(|metric| metric.as_str() == value)
105 .ok_or_else(|| format!("unsupported IC Dashboard metric {value:?}"))
106 }
107}
108
109///
110/// IcMetricQuery
111///
112/// One explicitly bounded official Dashboard metric time-series query.
113///
114
115#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
116pub struct IcMetricQuery {
117 /// Official Dashboard metric to retrieve.
118 pub metric: IcMetricKind,
119 /// Inclusive query start as Unix seconds.
120 pub start_unix_secs: u64,
121 /// Inclusive query end as Unix seconds.
122 pub end_unix_secs: u64,
123 /// Requested observation interval in seconds.
124 pub step_secs: u32,
125}
126
127impl IcMetricQuery {
128 /// Construct one explicit metric query window.
129 #[must_use]
130 pub const fn new(
131 metric: IcMetricKind,
132 start_unix_secs: u64,
133 end_unix_secs: u64,
134 step_secs: u32,
135 ) -> Self {
136 Self {
137 metric,
138 start_unix_secs,
139 end_unix_secs,
140 step_secs,
141 }
142 }
143}
144
145///
146/// IcMetricRequest
147///
148/// Request accepted by the bounded official Dashboard metric report builder.
149///
150
151#[derive(Clone, Debug, Eq, PartialEq)]
152pub struct IcMetricRequest {
153 /// Dashboard Metrics API base endpoint.
154 pub source_endpoint: String,
155 /// Collection time as Unix seconds.
156 pub now_unix_secs: u64,
157 /// Explicitly bounded metric query.
158 pub query: IcMetricQuery,
159}
160
161impl IcMetricRequest {
162 /// Construct one bounded live Dashboard metric request.
163 #[must_use]
164 pub fn new(
165 source_endpoint: impl Into<String>,
166 now_unix_secs: u64,
167 query: IcMetricQuery,
168 ) -> Self {
169 Self {
170 source_endpoint: source_endpoint.into(),
171 now_unix_secs,
172 query,
173 }
174 }
175}
176
177///
178/// IcDailyStatsQuery
179///
180/// One explicitly bounded official Dashboard daily-statistics query.
181///
182
183#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
184pub struct IcDailyStatsQuery {
185 /// Inclusive query start as Unix seconds.
186 pub start_unix_secs: u64,
187 /// Inclusive query end as Unix seconds.
188 pub end_unix_secs: u64,
189}
190
191impl IcDailyStatsQuery {
192 /// Construct one explicit daily-statistics query window.
193 #[must_use]
194 pub const fn new(start_unix_secs: u64, end_unix_secs: u64) -> Self {
195 Self {
196 start_unix_secs,
197 end_unix_secs,
198 }
199 }
200}
201
202///
203/// IcDailyStatsRequest
204///
205/// Request accepted by the bounded official Dashboard daily-statistics builder.
206///
207
208#[derive(Clone, Debug, Eq, PartialEq)]
209pub struct IcDailyStatsRequest {
210 /// Dashboard API v3 base endpoint.
211 pub source_endpoint: String,
212 /// Collection time as Unix seconds.
213 pub now_unix_secs: u64,
214 /// Explicitly bounded daily-statistics query.
215 pub query: IcDailyStatsQuery,
216}
217
218impl IcDailyStatsRequest {
219 /// Construct one bounded live Dashboard daily-statistics request.
220 #[must_use]
221 pub fn new(
222 source_endpoint: impl Into<String>,
223 now_unix_secs: u64,
224 query: IcDailyStatsQuery,
225 ) -> Self {
226 Self {
227 source_endpoint: source_endpoint.into(),
228 now_unix_secs,
229 query,
230 }
231 }
232}
233
234///
235/// IcBoundaryNodeDataCentersRequest
236///
237/// Request accepted by the official Dashboard boundary-node data-center builder.
238///
239
240#[derive(Clone, Debug, Eq, PartialEq)]
241pub struct IcBoundaryNodeDataCentersRequest {
242 /// Dashboard API v4 base endpoint.
243 pub source_endpoint: String,
244 /// Collection time as Unix seconds.
245 pub now_unix_secs: u64,
246}
247
248impl IcBoundaryNodeDataCentersRequest {
249 /// Construct one live Dashboard boundary-node data-center request.
250 #[must_use]
251 pub fn new(source_endpoint: impl Into<String>, now_unix_secs: u64) -> Self {
252 Self {
253 source_endpoint: source_endpoint.into(),
254 now_unix_secs,
255 }
256 }
257}
258
259///
260/// IcCanisterRequest
261///
262/// Request accepted by the official Dashboard canister report builder.
263///
264
265#[derive(Clone, Debug, Eq, PartialEq)]
266pub struct IcCanisterRequest {
267 /// Dashboard API base endpoint.
268 pub source_endpoint: String,
269 /// Collection time as Unix seconds.
270 pub now_unix_secs: u64,
271 /// Canister principal to inspect.
272 pub canister_id: String,
273}
274
275impl IcCanisterRequest {
276 /// Construct a live Dashboard canister request.
277 #[must_use]
278 pub fn new(
279 source_endpoint: impl Into<String>,
280 now_unix_secs: u64,
281 canister_id: impl Into<String>,
282 ) -> Self {
283 Self {
284 source_endpoint: source_endpoint.into(),
285 now_unix_secs,
286 canister_id: canister_id.into(),
287 }
288 }
289}
290
291///
292/// IcCanisterFilters
293///
294/// Official Dashboard filters shared by canister count and page requests.
295///
296
297#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
298pub struct IcCanisterFilters {
299 /// Select canisters according to whether the Dashboard records a name.
300 pub has_name: Option<bool>,
301 /// Select canisters assigned to this Subnet principal.
302 pub subnet_id: Option<String>,
303 /// Select canisters controlled by this principal.
304 pub controller_id: Option<String>,
305 /// Raw Dashboard language labels to include.
306 pub languages: Vec<String>,
307 /// Raw Dashboard canister classifications to include.
308 pub canister_types: Vec<String>,
309 /// Raw Dashboard text search, between two and one hundred characters.
310 pub query: Option<String>,
311}
312
313///
314/// IcCanisterCountRequest
315///
316/// Request for one bounded official Dashboard canister-count lookup.
317///
318
319#[derive(Clone, Debug, Eq, PartialEq)]
320pub struct IcCanisterCountRequest {
321 /// Dashboard API v4 base endpoint.
322 pub source_endpoint: String,
323 /// Collection time as Unix seconds.
324 pub now_unix_secs: u64,
325 /// Filters applied by the Dashboard.
326 pub filters: IcCanisterFilters,
327}
328
329impl IcCanisterCountRequest {
330 /// Construct a live Dashboard canister-count request without filters.
331 #[must_use]
332 pub fn new(source_endpoint: impl Into<String>, now_unix_secs: u64) -> Self {
333 Self {
334 source_endpoint: source_endpoint.into(),
335 now_unix_secs,
336 filters: IcCanisterFilters::default(),
337 }
338 }
339
340 /// Set the Dashboard filters used by this request.
341 #[must_use]
342 pub fn with_filters(mut self, filters: IcCanisterFilters) -> Self {
343 self.filters = filters;
344 self
345 }
346}
347
348///
349/// IcCanisterPageRequest
350///
351/// Request for one bounded official Dashboard canister page.
352///
353
354#[derive(Clone, Debug, Eq, PartialEq)]
355pub struct IcCanisterPageRequest {
356 /// Dashboard API v4 base endpoint.
357 pub source_endpoint: String,
358 /// Collection time as Unix seconds.
359 pub now_unix_secs: u64,
360 /// Filters applied by the Dashboard.
361 pub filters: IcCanisterFilters,
362 /// Maximum rows requested from the API.
363 pub limit: u16,
364 /// Exclusive forward cursor returned by an earlier page.
365 pub after: Option<String>,
366 /// Exclusive backward cursor returned by an earlier page.
367 pub before: Option<String>,
368}
369
370impl IcCanisterPageRequest {
371 /// Construct a live Dashboard page request with the default bounded limit.
372 #[must_use]
373 pub fn new(source_endpoint: impl Into<String>, now_unix_secs: u64) -> Self {
374 Self {
375 source_endpoint: source_endpoint.into(),
376 now_unix_secs,
377 filters: IcCanisterFilters::default(),
378 limit: super::DEFAULT_IC_CANISTER_PAGE_LIMIT,
379 after: None,
380 before: None,
381 }
382 }
383
384 /// Set the Dashboard filters used by this request.
385 #[must_use]
386 pub fn with_filters(mut self, filters: IcCanisterFilters) -> Self {
387 self.filters = filters;
388 self
389 }
390
391 /// Set the maximum number of returned rows.
392 #[must_use]
393 pub const fn with_limit(mut self, limit: u16) -> Self {
394 self.limit = limit;
395 self
396 }
397
398 /// Set an exclusive forward cursor.
399 #[must_use]
400 pub fn with_after(mut self, after: impl Into<String>) -> Self {
401 self.after = Some(after.into());
402 self
403 }
404
405 /// Set an exclusive backward cursor.
406 #[must_use]
407 pub fn with_before(mut self, before: impl Into<String>) -> Self {
408 self.before = Some(before.into());
409 self
410 }
411}
412
413///
414/// IcCanisterUpgrade
415///
416/// One proposal-linked canister upgrade recorded by the Dashboard API.
417///
418
419#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
420pub struct IcCanisterUpgrade {
421 /// Proposal execution time as raw Unix seconds.
422 pub executed_timestamp_seconds: u64,
423 /// Wasm module hash as raw lowercase hexadecimal text.
424 pub module_hash: String,
425 /// NNS proposal that installed this module.
426 pub proposal_id: u64,
427}
428
429///
430/// IcDashboardReportProvenance
431///
432/// Shared off-chain provenance and authority guarantees for Dashboard reports.
433///
434
435#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
436pub struct IcDashboardReportProvenance {
437 /// Report schema version.
438 pub schema_version: u32,
439 /// Network represented by the official Dashboard API.
440 pub network: String,
441 /// Authority that supplied the report fields.
442 pub authority: String,
443 /// Dashboard API base endpoint queried by the source.
444 pub source_endpoint: String,
445 /// Time this report was collected.
446 pub fetched_at: String,
447 /// Collector identity.
448 pub fetched_by: String,
449 /// Whether the API response is cryptographically certified IC state.
450 pub certified: bool,
451 /// Whether every returned value is guaranteed to describe one point in time.
452 pub point_in_time_guaranteed: bool,
453}
454
455///
456/// IcMetricObservation
457///
458/// One raw timestamp and value returned by the Dashboard Metrics API.
459///
460
461#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
462pub struct IcMetricObservation {
463 /// Observation timestamp as Unix seconds.
464 pub timestamp_unix_secs: u64,
465 /// Raw value string returned by the Dashboard.
466 pub value: String,
467}
468
469///
470/// IcMetricSeries
471///
472/// One named raw series in a Dashboard metric response.
473///
474
475#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
476pub struct IcMetricSeries {
477 /// Raw Dashboard response field that names this series.
478 pub name: String,
479 /// Observations in strictly increasing timestamp order.
480 pub observations: Vec<IcMetricObservation>,
481}
482
483///
484/// IcMetricReport
485///
486/// One bounded time-series response from the official Dashboard Metrics API.
487///
488
489#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
490pub struct IcMetricReport {
491 /// Shared Dashboard provenance, flattened in serialized report JSON.
492 #[serde(flatten)]
493 pub provenance: IcDashboardReportProvenance,
494 /// Metric and explicit time-series bounds, flattened in report JSON.
495 #[serde(flatten)]
496 pub query: IcMetricQuery,
497 /// Number of named series returned by the API.
498 pub returned_series_count: usize,
499 /// Total number of observations across all returned series.
500 pub returned_observation_count: usize,
501 /// Raw named time series in canonical series-name order.
502 pub series: Vec<IcMetricSeries>,
503}
504
505///
506/// IcDailyStatsRow
507///
508/// Selected raw daily network-activity values returned by the Dashboard API.
509///
510
511#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
512pub struct IcDailyStatsRow {
513 /// Raw UTC calendar day returned by the Dashboard.
514 pub day: String,
515 /// Observation timestamp as Unix seconds.
516 pub timestamp_unix_secs: u64,
517 /// Raw average query-transaction rate.
518 pub average_query_transactions_per_second: String,
519 /// Raw average update-transaction rate.
520 pub average_update_transactions_per_second: String,
521 /// Raw average total-transaction rate.
522 pub average_transactions_per_second: String,
523 /// Raw maximum query-transaction rate.
524 pub max_query_transactions_per_second: String,
525 /// Raw maximum update-transaction rate.
526 pub max_update_transactions_per_second: String,
527 /// Raw maximum total-transaction rate.
528 pub max_total_transactions_per_second: String,
529 /// Raw average block-production rate.
530 pub blocks_per_second_average: String,
531}
532
533///
534/// IcDailyStatsReport
535///
536/// One bounded daily network-activity response from the official Dashboard API.
537///
538
539#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
540pub struct IcDailyStatsReport {
541 /// Shared Dashboard provenance, flattened in serialized report JSON.
542 #[serde(flatten)]
543 pub provenance: IcDashboardReportProvenance,
544 /// Exact requested time bounds, flattened in report JSON.
545 #[serde(flatten)]
546 pub query: IcDailyStatsQuery,
547 /// Number of daily rows returned by the API.
548 pub returned_day_count: usize,
549 /// Rows in strictly increasing timestamp order.
550 pub rows: Vec<IcDailyStatsRow>,
551}
552
553///
554/// IcBoundaryNodeDataCenterRow
555///
556/// One raw data-center aggregate returned by the boundary-node API.
557///
558
559#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
560pub struct IcBoundaryNodeDataCenterRow {
561 /// Dashboard data-center identifier.
562 pub dc_id: String,
563 /// Raw data-center display name.
564 pub name: String,
565 /// Raw infrastructure-owner label.
566 pub owner: String,
567 /// Raw Dashboard region label.
568 pub region: String,
569 /// Raw decimal latitude.
570 pub latitude: String,
571 /// Raw decimal longitude.
572 pub longitude: String,
573 /// Raw decimal count of boundary nodes assigned to this data center.
574 pub total_nodes: String,
575}
576
577///
578/// IcBoundaryNodeDataCentersReport
579///
580/// One complete response from the official boundary-node data-center resource.
581///
582
583#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
584pub struct IcBoundaryNodeDataCentersReport {
585 /// Shared Dashboard provenance, flattened in serialized report JSON.
586 #[serde(flatten)]
587 pub provenance: IcDashboardReportProvenance,
588 /// Number of data-center rows returned by the API.
589 pub data_center_count: usize,
590 /// Sum of the raw per-data-center boundary-node counts.
591 pub total_node_count: u64,
592 /// Rows in canonical data-center-id order, including zero-node locations.
593 pub rows: Vec<IcBoundaryNodeDataCenterRow>,
594}
595
596///
597/// IcCanisterReport
598///
599/// One live canister metadata report from the official Dashboard API.
600///
601
602#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
603pub struct IcCanisterReport {
604 /// Shared Dashboard provenance, flattened in serialized report JSON.
605 #[serde(flatten)]
606 pub provenance: IcDashboardReportProvenance,
607 /// Canonical canister principal.
608 pub canister_id: String,
609 /// Dashboard database row identifier.
610 pub dashboard_id: u64,
611 /// Raw optional Dashboard canister classification.
612 pub canister_type: Option<String>,
613 /// Raw Dashboard canister name; an empty string means no name was recorded.
614 pub name: String,
615 /// Canonical Subnet principal recorded by the Dashboard.
616 pub subnet_id: String,
617 /// Canonically ordered controller principals recorded by the Dashboard.
618 pub controllers: Vec<String>,
619 /// Raw Dashboard language label; an empty string means no language was recorded.
620 pub language: String,
621 /// Raw current module hash; an empty string means no hash was recorded.
622 pub module_hash: String,
623 /// Raw Dashboard row update timestamp.
624 pub dashboard_updated_at: String,
625 /// Number of proposal-linked upgrades when history is available.
626 pub upgrade_count: Option<usize>,
627 /// Proposal-linked upgrade history, or `None` when the Dashboard returned `null`.
628 pub upgrades: Option<Vec<IcCanisterUpgrade>>,
629}
630
631///
632/// IcCanisterCountReport
633///
634/// One filtered canister count from the official Dashboard API.
635///
636
637#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
638pub struct IcCanisterCountReport {
639 /// Shared Dashboard provenance, flattened in serialized report JSON.
640 #[serde(flatten)]
641 pub provenance: IcDashboardReportProvenance,
642 /// Filters applied by the Dashboard.
643 pub filters: IcCanisterFilters,
644 /// Number of matching Dashboard canister records.
645 pub total: u64,
646}
647
648///
649/// IcCanisterPageController
650///
651/// One controller entry returned by the Dashboard canister collection API.
652///
653
654#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
655pub struct IcCanisterPageController {
656 /// Canonical controller principal.
657 pub principal_id: String,
658 /// Raw optional Dashboard metadata associated with the controller.
659 pub raw_metadata: Option<String>,
660}
661
662///
663/// IcCanisterPageRow
664///
665/// One discovery row from a bounded Dashboard canister page.
666///
667
668#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
669pub struct IcCanisterPageRow {
670 /// Canonical canister principal.
671 pub canister_id: String,
672 /// Dashboard database row identifier.
673 pub dashboard_id: u64,
674 /// Raw optional Dashboard canister classification.
675 pub canister_type: Option<String>,
676 /// Raw Dashboard canister name.
677 pub name: String,
678 /// Canonical Subnet principal recorded by the Dashboard.
679 pub subnet_id: String,
680 /// Canonically ordered controller entries recorded by the Dashboard.
681 pub controllers: Vec<IcCanisterPageController>,
682 /// Raw Dashboard language label.
683 pub language: String,
684 /// Raw current module hash.
685 pub module_hash: String,
686 /// Raw Dashboard row update timestamp.
687 pub dashboard_updated_at: String,
688}
689
690///
691/// IcCanisterPageReport
692///
693/// One explicitly bounded page from the official Dashboard canister collection.
694///
695
696#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
697pub struct IcCanisterPageReport {
698 /// Shared Dashboard provenance, flattened in serialized report JSON.
699 #[serde(flatten)]
700 pub provenance: IcDashboardReportProvenance,
701 /// Filters applied by the Dashboard.
702 pub filters: IcCanisterFilters,
703 /// Maximum rows requested from the API.
704 pub requested_limit: u16,
705 /// Number of rows returned in this report.
706 pub returned_count: usize,
707 /// Exclusive forward cursor supplied to this request.
708 pub after: Option<String>,
709 /// Exclusive backward cursor supplied to this request.
710 pub before: Option<String>,
711 /// Cursor for an explicit request for the preceding page.
712 pub previous_cursor: Option<String>,
713 /// Cursor for an explicit request for the following page.
714 pub next_cursor: Option<String>,
715 /// Canister discovery rows in Dashboard canister-id order.
716 pub rows: Vec<IcCanisterPageRow>,
717}
718
719///
720/// IcSourceRequest
721///
722/// Shared endpoint and collection provenance for IC Dashboard source calls and results.
723///
724
725#[cfg(feature = "host")]
726#[derive(Clone, Debug, Eq, PartialEq)]
727pub struct IcSourceRequest {
728 /// Dashboard API base endpoint.
729 pub endpoint: String,
730 /// Collection timestamp in UTC.
731 pub fetched_at: String,
732 /// Collector identity recorded in report provenance.
733 pub fetched_by: String,
734}
735
736#[cfg(feature = "host")]
737impl IcSourceRequest {
738 /// Construct source-call provenance.
739 #[must_use]
740 pub fn new(
741 endpoint: impl Into<String>,
742 fetched_at: impl Into<String>,
743 fetched_by: impl Into<String>,
744 ) -> Self {
745 Self {
746 endpoint: endpoint.into(),
747 fetched_at: fetched_at.into(),
748 fetched_by: fetched_by.into(),
749 }
750 }
751}
752
753///
754/// IcCanisterSourceData
755///
756/// Raw canister metadata and provenance returned by an IC Dashboard source.
757///
758
759#[cfg(feature = "host")]
760#[derive(Clone, Debug, Eq, PartialEq)]
761pub struct IcCanisterSourceData {
762 /// Source request and provenance preserved by the source.
763 pub source: IcSourceRequest,
764 /// Canister principal returned by the Dashboard.
765 pub canister_id: String,
766 /// Dashboard database row identifier.
767 pub dashboard_id: u64,
768 /// Raw optional Dashboard canister classification.
769 pub canister_type: Option<String>,
770 /// Raw Dashboard canister name.
771 pub name: String,
772 /// Subnet principal returned by the Dashboard.
773 pub subnet_id: String,
774 /// Controller principals returned by the Dashboard.
775 pub controllers: Vec<String>,
776 /// Raw Dashboard language label.
777 pub language: String,
778 /// Raw current module hash.
779 pub module_hash: String,
780 /// Raw Dashboard row update timestamp.
781 pub dashboard_updated_at: String,
782 /// Proposal-linked upgrades, or `None` when the Dashboard returned `null`.
783 pub upgrades: Option<Vec<IcCanisterUpgrade>>,
784}
785
786///
787/// IcCanisterCountSourceData
788///
789/// Raw filtered count and provenance returned by a Dashboard source.
790///
791
792#[cfg(feature = "host")]
793#[derive(Clone, Debug, Eq, PartialEq)]
794pub struct IcCanisterCountSourceData {
795 /// Source request and provenance preserved by the source.
796 pub source: IcSourceRequest,
797 /// Filters applied by the source.
798 pub filters: IcCanisterFilters,
799 /// Number of matching Dashboard canister records.
800 pub total: u64,
801}
802
803///
804/// IcCanisterPageSourceData
805///
806/// Raw bounded canister page and provenance returned by a Dashboard source.
807///
808
809#[cfg(feature = "host")]
810#[derive(Clone, Debug, Eq, PartialEq)]
811pub struct IcCanisterPageSourceData {
812 /// Source request and provenance preserved by the source.
813 pub source: IcSourceRequest,
814 /// Filters applied by the source.
815 pub filters: IcCanisterFilters,
816 /// Maximum rows requested from the source.
817 pub requested_limit: u16,
818 /// Exclusive forward cursor supplied to the source.
819 pub after: Option<String>,
820 /// Exclusive backward cursor supplied to the source.
821 pub before: Option<String>,
822 /// Cursor for an explicit request for the preceding page.
823 pub previous_cursor: Option<String>,
824 /// Cursor for an explicit request for the following page.
825 pub next_cursor: Option<String>,
826 /// Canister discovery rows returned by the source.
827 pub rows: Vec<IcCanisterPageRow>,
828}
829
830///
831/// IcMetricSourceData
832///
833/// Raw bounded metric series and provenance returned by a Dashboard source.
834///
835
836#[cfg(feature = "host")]
837#[derive(Clone, Debug, Eq, PartialEq)]
838pub struct IcMetricSourceData {
839 /// Source request and provenance preserved by the source.
840 pub source: IcSourceRequest,
841 /// Metric query applied by the source.
842 pub query: IcMetricQuery,
843 /// Raw named time series returned by the source.
844 pub series: Vec<IcMetricSeries>,
845}
846
847///
848/// IcDailyStatsSourceData
849///
850/// Raw bounded daily network-activity rows and provenance returned by a source.
851///
852
853#[cfg(feature = "host")]
854#[derive(Clone, Debug, Eq, PartialEq)]
855pub struct IcDailyStatsSourceData {
856 /// Source request and provenance preserved by the source.
857 pub source: IcSourceRequest,
858 /// Daily-statistics query applied by the source.
859 pub query: IcDailyStatsQuery,
860 /// Selected raw daily rows returned by the source.
861 pub rows: Vec<IcDailyStatsRow>,
862}
863
864///
865/// IcBoundaryNodeDataCentersSourceData
866///
867/// Raw boundary-node data-center rows and provenance returned by a Dashboard source.
868///
869
870#[cfg(feature = "host")]
871#[derive(Clone, Debug, Eq, PartialEq)]
872pub struct IcBoundaryNodeDataCentersSourceData {
873 /// Source request and provenance preserved by the source.
874 pub source: IcSourceRequest,
875 /// Raw data-center rows returned by the source.
876 pub rows: Vec<IcBoundaryNodeDataCenterRow>,
877}
878
879///
880/// IcHostError
881///
882/// Typed error returned by IC Dashboard report builders and live sources.
883///
884
885#[cfg(feature = "host")]
886#[derive(Debug, ThisError)]
887pub enum IcHostError {
888 /// The synchronous adapter could not create its local async runtime.
889 #[error("failed to run IC Dashboard query: {0}")]
890 Runtime(#[from] RuntimeError),
891
892 /// A request supplied an invalid canister principal.
893 #[error("invalid {field}: {reason}")]
894 InvalidPrincipal {
895 /// Principal field being validated.
896 field: &'static str,
897 /// Principal parser diagnostic.
898 reason: String,
899 },
900
901 /// A request violates the bounded Dashboard query contract.
902 #[error("invalid {field}: {reason}")]
903 InvalidRequest {
904 /// Request field being validated.
905 field: &'static str,
906 /// Deterministic validation diagnostic.
907 reason: String,
908 },
909
910 /// The Dashboard API base endpoint is malformed or unsupported.
911 #[error("invalid IC Dashboard endpoint {endpoint}: {reason}")]
912 InvalidEndpoint {
913 /// Rejected endpoint.
914 endpoint: String,
915 /// URL validation diagnostic.
916 reason: String,
917 },
918
919 /// The HTTP client could not be constructed.
920 #[error("failed to build IC Dashboard HTTP client: {reason}")]
921 HttpClientBuild {
922 /// HTTP client construction diagnostic.
923 reason: String,
924 },
925
926 /// The live Dashboard request failed before a response was received.
927 #[error("IC Dashboard request to {url} failed: {reason}")]
928 HttpRequest {
929 /// Fully resolved request URL.
930 url: String,
931 /// HTTP transport error.
932 reason: String,
933 },
934
935 /// The Dashboard returned a non-success HTTP status.
936 #[error("IC Dashboard request to {url} returned HTTP status {status}")]
937 HttpStatus {
938 /// Fully resolved request URL.
939 url: String,
940 /// Numeric HTTP status.
941 status: u16,
942 },
943
944 /// The Dashboard response did not match the expected JSON shape.
945 #[error("failed to decode IC Dashboard response from {url}: {reason}")]
946 JsonDecode {
947 /// Fully resolved request URL.
948 url: String,
949 /// JSON response decoding error.
950 reason: String,
951 },
952
953 /// A source capability returned data that violates its public result contract.
954 #[error("invalid IC Dashboard source data: {reason}")]
955 InvalidSourceData {
956 /// Deterministic invariant failure.
957 reason: String,
958 },
959}