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/// IcBoundaryNodeDataCentersRequest
179///
180/// Request accepted by the official Dashboard boundary-node data-center builder.
181///
182
183#[derive(Clone, Debug, Eq, PartialEq)]
184pub struct IcBoundaryNodeDataCentersRequest {
185 /// Dashboard API v4 base endpoint.
186 pub source_endpoint: String,
187 /// Collection time as Unix seconds.
188 pub now_unix_secs: u64,
189}
190
191impl IcBoundaryNodeDataCentersRequest {
192 /// Construct one live Dashboard boundary-node data-center request.
193 #[must_use]
194 pub fn new(source_endpoint: impl Into<String>, now_unix_secs: u64) -> Self {
195 Self {
196 source_endpoint: source_endpoint.into(),
197 now_unix_secs,
198 }
199 }
200}
201
202///
203/// IcCanisterRequest
204///
205/// Request accepted by the official Dashboard canister report builder.
206///
207
208#[derive(Clone, Debug, Eq, PartialEq)]
209pub struct IcCanisterRequest {
210 /// Dashboard API base endpoint.
211 pub source_endpoint: String,
212 /// Collection time as Unix seconds.
213 pub now_unix_secs: u64,
214 /// Canister principal to inspect.
215 pub canister_id: String,
216}
217
218impl IcCanisterRequest {
219 /// Construct a live Dashboard canister request.
220 #[must_use]
221 pub fn new(
222 source_endpoint: impl Into<String>,
223 now_unix_secs: u64,
224 canister_id: impl Into<String>,
225 ) -> Self {
226 Self {
227 source_endpoint: source_endpoint.into(),
228 now_unix_secs,
229 canister_id: canister_id.into(),
230 }
231 }
232}
233
234///
235/// IcCanisterFilters
236///
237/// Official Dashboard filters shared by canister count and page requests.
238///
239
240#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
241pub struct IcCanisterFilters {
242 /// Select canisters according to whether the Dashboard records a name.
243 pub has_name: Option<bool>,
244 /// Select canisters assigned to this Subnet principal.
245 pub subnet_id: Option<String>,
246 /// Select canisters controlled by this principal.
247 pub controller_id: Option<String>,
248 /// Raw Dashboard language labels to include.
249 pub languages: Vec<String>,
250 /// Raw Dashboard canister classifications to include.
251 pub canister_types: Vec<String>,
252 /// Raw Dashboard text search, between two and one hundred characters.
253 pub query: Option<String>,
254}
255
256///
257/// IcCanisterCountRequest
258///
259/// Request for one bounded official Dashboard canister-count lookup.
260///
261
262#[derive(Clone, Debug, Eq, PartialEq)]
263pub struct IcCanisterCountRequest {
264 /// Dashboard API v4 base endpoint.
265 pub source_endpoint: String,
266 /// Collection time as Unix seconds.
267 pub now_unix_secs: u64,
268 /// Filters applied by the Dashboard.
269 pub filters: IcCanisterFilters,
270}
271
272impl IcCanisterCountRequest {
273 /// Construct a live Dashboard canister-count request without filters.
274 #[must_use]
275 pub fn new(source_endpoint: impl Into<String>, now_unix_secs: u64) -> Self {
276 Self {
277 source_endpoint: source_endpoint.into(),
278 now_unix_secs,
279 filters: IcCanisterFilters::default(),
280 }
281 }
282
283 /// Set the Dashboard filters used by this request.
284 #[must_use]
285 pub fn with_filters(mut self, filters: IcCanisterFilters) -> Self {
286 self.filters = filters;
287 self
288 }
289}
290
291///
292/// IcCanisterPageRequest
293///
294/// Request for one bounded official Dashboard canister page.
295///
296
297#[derive(Clone, Debug, Eq, PartialEq)]
298pub struct IcCanisterPageRequest {
299 /// Dashboard API v4 base endpoint.
300 pub source_endpoint: String,
301 /// Collection time as Unix seconds.
302 pub now_unix_secs: u64,
303 /// Filters applied by the Dashboard.
304 pub filters: IcCanisterFilters,
305 /// Maximum rows requested from the API.
306 pub limit: u16,
307 /// Exclusive forward cursor returned by an earlier page.
308 pub after: Option<String>,
309 /// Exclusive backward cursor returned by an earlier page.
310 pub before: Option<String>,
311}
312
313impl IcCanisterPageRequest {
314 /// Construct a live Dashboard page request with the default bounded limit.
315 #[must_use]
316 pub fn new(source_endpoint: impl Into<String>, now_unix_secs: u64) -> Self {
317 Self {
318 source_endpoint: source_endpoint.into(),
319 now_unix_secs,
320 filters: IcCanisterFilters::default(),
321 limit: super::DEFAULT_IC_CANISTER_PAGE_LIMIT,
322 after: None,
323 before: None,
324 }
325 }
326
327 /// Set the Dashboard filters used by this request.
328 #[must_use]
329 pub fn with_filters(mut self, filters: IcCanisterFilters) -> Self {
330 self.filters = filters;
331 self
332 }
333
334 /// Set the maximum number of returned rows.
335 #[must_use]
336 pub const fn with_limit(mut self, limit: u16) -> Self {
337 self.limit = limit;
338 self
339 }
340
341 /// Set an exclusive forward cursor.
342 #[must_use]
343 pub fn with_after(mut self, after: impl Into<String>) -> Self {
344 self.after = Some(after.into());
345 self
346 }
347
348 /// Set an exclusive backward cursor.
349 #[must_use]
350 pub fn with_before(mut self, before: impl Into<String>) -> Self {
351 self.before = Some(before.into());
352 self
353 }
354}
355
356///
357/// IcCanisterUpgrade
358///
359/// One proposal-linked canister upgrade recorded by the Dashboard API.
360///
361
362#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
363pub struct IcCanisterUpgrade {
364 /// Proposal execution time as raw Unix seconds.
365 pub executed_timestamp_seconds: u64,
366 /// Wasm module hash as raw lowercase hexadecimal text.
367 pub module_hash: String,
368 /// NNS proposal that installed this module.
369 pub proposal_id: u64,
370}
371
372///
373/// IcDashboardReportProvenance
374///
375/// Shared off-chain provenance and authority guarantees for Dashboard reports.
376///
377
378#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
379pub struct IcDashboardReportProvenance {
380 /// Report schema version.
381 pub schema_version: u32,
382 /// Network represented by the official Dashboard API.
383 pub network: String,
384 /// Authority that supplied the report fields.
385 pub authority: String,
386 /// Dashboard API base endpoint queried by the source.
387 pub source_endpoint: String,
388 /// Time this report was collected.
389 pub fetched_at: String,
390 /// Collector identity.
391 pub fetched_by: String,
392 /// Whether the API response is cryptographically certified IC state.
393 pub certified: bool,
394 /// Whether every returned value is guaranteed to describe one point in time.
395 pub point_in_time_guaranteed: bool,
396}
397
398///
399/// IcMetricObservation
400///
401/// One raw timestamp and value returned by the Dashboard Metrics API.
402///
403
404#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
405pub struct IcMetricObservation {
406 /// Observation timestamp as Unix seconds.
407 pub timestamp_unix_secs: u64,
408 /// Raw value string returned by the Dashboard.
409 pub value: String,
410}
411
412///
413/// IcMetricSeries
414///
415/// One named raw series in a Dashboard metric response.
416///
417
418#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
419pub struct IcMetricSeries {
420 /// Raw Dashboard response field that names this series.
421 pub name: String,
422 /// Observations in strictly increasing timestamp order.
423 pub observations: Vec<IcMetricObservation>,
424}
425
426///
427/// IcMetricReport
428///
429/// One bounded time-series response from the official Dashboard Metrics API.
430///
431
432#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
433pub struct IcMetricReport {
434 /// Shared Dashboard provenance, flattened in serialized report JSON.
435 #[serde(flatten)]
436 pub provenance: IcDashboardReportProvenance,
437 /// Metric and explicit time-series bounds, flattened in report JSON.
438 #[serde(flatten)]
439 pub query: IcMetricQuery,
440 /// Number of named series returned by the API.
441 pub returned_series_count: usize,
442 /// Total number of observations across all returned series.
443 pub returned_observation_count: usize,
444 /// Raw named time series in canonical series-name order.
445 pub series: Vec<IcMetricSeries>,
446}
447
448///
449/// IcBoundaryNodeDataCenterRow
450///
451/// One raw data-center aggregate returned by the boundary-node API.
452///
453
454#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
455pub struct IcBoundaryNodeDataCenterRow {
456 /// Dashboard data-center identifier.
457 pub dc_id: String,
458 /// Raw data-center display name.
459 pub name: String,
460 /// Raw infrastructure-owner label.
461 pub owner: String,
462 /// Raw Dashboard region label.
463 pub region: String,
464 /// Raw decimal latitude.
465 pub latitude: String,
466 /// Raw decimal longitude.
467 pub longitude: String,
468 /// Raw decimal count of boundary nodes assigned to this data center.
469 pub total_nodes: String,
470}
471
472///
473/// IcBoundaryNodeDataCentersReport
474///
475/// One complete response from the official boundary-node data-center resource.
476///
477
478#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
479pub struct IcBoundaryNodeDataCentersReport {
480 /// Shared Dashboard provenance, flattened in serialized report JSON.
481 #[serde(flatten)]
482 pub provenance: IcDashboardReportProvenance,
483 /// Number of data-center rows returned by the API.
484 pub data_center_count: usize,
485 /// Sum of the raw per-data-center boundary-node counts.
486 pub total_node_count: u64,
487 /// Rows in canonical data-center-id order, including zero-node locations.
488 pub rows: Vec<IcBoundaryNodeDataCenterRow>,
489}
490
491///
492/// IcCanisterReport
493///
494/// One live canister metadata report from the official Dashboard API.
495///
496
497#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
498pub struct IcCanisterReport {
499 /// Shared Dashboard provenance, flattened in serialized report JSON.
500 #[serde(flatten)]
501 pub provenance: IcDashboardReportProvenance,
502 /// Canonical canister principal.
503 pub canister_id: String,
504 /// Dashboard database row identifier.
505 pub dashboard_id: u64,
506 /// Raw optional Dashboard canister classification.
507 pub canister_type: Option<String>,
508 /// Raw Dashboard canister name; an empty string means no name was recorded.
509 pub name: String,
510 /// Canonical Subnet principal recorded by the Dashboard.
511 pub subnet_id: String,
512 /// Canonically ordered controller principals recorded by the Dashboard.
513 pub controllers: Vec<String>,
514 /// Raw Dashboard language label; an empty string means no language was recorded.
515 pub language: String,
516 /// Raw current module hash; an empty string means no hash was recorded.
517 pub module_hash: String,
518 /// Raw Dashboard row update timestamp.
519 pub dashboard_updated_at: String,
520 /// Number of proposal-linked upgrades when history is available.
521 pub upgrade_count: Option<usize>,
522 /// Proposal-linked upgrade history, or `None` when the Dashboard returned `null`.
523 pub upgrades: Option<Vec<IcCanisterUpgrade>>,
524}
525
526///
527/// IcCanisterCountReport
528///
529/// One filtered canister count from the official Dashboard API.
530///
531
532#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
533pub struct IcCanisterCountReport {
534 /// Shared Dashboard provenance, flattened in serialized report JSON.
535 #[serde(flatten)]
536 pub provenance: IcDashboardReportProvenance,
537 /// Filters applied by the Dashboard.
538 pub filters: IcCanisterFilters,
539 /// Number of matching Dashboard canister records.
540 pub total: u64,
541}
542
543///
544/// IcCanisterPageController
545///
546/// One controller entry returned by the Dashboard canister collection API.
547///
548
549#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
550pub struct IcCanisterPageController {
551 /// Canonical controller principal.
552 pub principal_id: String,
553 /// Raw optional Dashboard metadata associated with the controller.
554 pub raw_metadata: Option<String>,
555}
556
557///
558/// IcCanisterPageRow
559///
560/// One discovery row from a bounded Dashboard canister page.
561///
562
563#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
564pub struct IcCanisterPageRow {
565 /// Canonical canister principal.
566 pub canister_id: String,
567 /// Dashboard database row identifier.
568 pub dashboard_id: u64,
569 /// Raw optional Dashboard canister classification.
570 pub canister_type: Option<String>,
571 /// Raw Dashboard canister name.
572 pub name: String,
573 /// Canonical Subnet principal recorded by the Dashboard.
574 pub subnet_id: String,
575 /// Canonically ordered controller entries recorded by the Dashboard.
576 pub controllers: Vec<IcCanisterPageController>,
577 /// Raw Dashboard language label.
578 pub language: String,
579 /// Raw current module hash.
580 pub module_hash: String,
581 /// Raw Dashboard row update timestamp.
582 pub dashboard_updated_at: String,
583}
584
585///
586/// IcCanisterPageReport
587///
588/// One explicitly bounded page from the official Dashboard canister collection.
589///
590
591#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
592pub struct IcCanisterPageReport {
593 /// Shared Dashboard provenance, flattened in serialized report JSON.
594 #[serde(flatten)]
595 pub provenance: IcDashboardReportProvenance,
596 /// Filters applied by the Dashboard.
597 pub filters: IcCanisterFilters,
598 /// Maximum rows requested from the API.
599 pub requested_limit: u16,
600 /// Number of rows returned in this report.
601 pub returned_count: usize,
602 /// Exclusive forward cursor supplied to this request.
603 pub after: Option<String>,
604 /// Exclusive backward cursor supplied to this request.
605 pub before: Option<String>,
606 /// Cursor for an explicit request for the preceding page.
607 pub previous_cursor: Option<String>,
608 /// Cursor for an explicit request for the following page.
609 pub next_cursor: Option<String>,
610 /// Canister discovery rows in Dashboard canister-id order.
611 pub rows: Vec<IcCanisterPageRow>,
612}
613
614///
615/// IcSourceRequest
616///
617/// Shared endpoint and collection provenance for IC Dashboard source calls and results.
618///
619
620#[cfg(feature = "host")]
621#[derive(Clone, Debug, Eq, PartialEq)]
622pub struct IcSourceRequest {
623 /// Dashboard API base endpoint.
624 pub endpoint: String,
625 /// Collection timestamp in UTC.
626 pub fetched_at: String,
627 /// Collector identity recorded in report provenance.
628 pub fetched_by: String,
629}
630
631#[cfg(feature = "host")]
632impl IcSourceRequest {
633 /// Construct source-call provenance.
634 #[must_use]
635 pub fn new(
636 endpoint: impl Into<String>,
637 fetched_at: impl Into<String>,
638 fetched_by: impl Into<String>,
639 ) -> Self {
640 Self {
641 endpoint: endpoint.into(),
642 fetched_at: fetched_at.into(),
643 fetched_by: fetched_by.into(),
644 }
645 }
646}
647
648///
649/// IcCanisterSourceData
650///
651/// Raw canister metadata and provenance returned by an IC Dashboard source.
652///
653
654#[cfg(feature = "host")]
655#[derive(Clone, Debug, Eq, PartialEq)]
656pub struct IcCanisterSourceData {
657 /// Source request and provenance preserved by the source.
658 pub source: IcSourceRequest,
659 /// Canister principal returned by the Dashboard.
660 pub canister_id: String,
661 /// Dashboard database row identifier.
662 pub dashboard_id: u64,
663 /// Raw optional Dashboard canister classification.
664 pub canister_type: Option<String>,
665 /// Raw Dashboard canister name.
666 pub name: String,
667 /// Subnet principal returned by the Dashboard.
668 pub subnet_id: String,
669 /// Controller principals returned by the Dashboard.
670 pub controllers: Vec<String>,
671 /// Raw Dashboard language label.
672 pub language: String,
673 /// Raw current module hash.
674 pub module_hash: String,
675 /// Raw Dashboard row update timestamp.
676 pub dashboard_updated_at: String,
677 /// Proposal-linked upgrades, or `None` when the Dashboard returned `null`.
678 pub upgrades: Option<Vec<IcCanisterUpgrade>>,
679}
680
681///
682/// IcCanisterCountSourceData
683///
684/// Raw filtered count and provenance returned by a Dashboard source.
685///
686
687#[cfg(feature = "host")]
688#[derive(Clone, Debug, Eq, PartialEq)]
689pub struct IcCanisterCountSourceData {
690 /// Source request and provenance preserved by the source.
691 pub source: IcSourceRequest,
692 /// Filters applied by the source.
693 pub filters: IcCanisterFilters,
694 /// Number of matching Dashboard canister records.
695 pub total: u64,
696}
697
698///
699/// IcCanisterPageSourceData
700///
701/// Raw bounded canister page and provenance returned by a Dashboard source.
702///
703
704#[cfg(feature = "host")]
705#[derive(Clone, Debug, Eq, PartialEq)]
706pub struct IcCanisterPageSourceData {
707 /// Source request and provenance preserved by the source.
708 pub source: IcSourceRequest,
709 /// Filters applied by the source.
710 pub filters: IcCanisterFilters,
711 /// Maximum rows requested from the source.
712 pub requested_limit: u16,
713 /// Exclusive forward cursor supplied to the source.
714 pub after: Option<String>,
715 /// Exclusive backward cursor supplied to the source.
716 pub before: Option<String>,
717 /// Cursor for an explicit request for the preceding page.
718 pub previous_cursor: Option<String>,
719 /// Cursor for an explicit request for the following page.
720 pub next_cursor: Option<String>,
721 /// Canister discovery rows returned by the source.
722 pub rows: Vec<IcCanisterPageRow>,
723}
724
725///
726/// IcMetricSourceData
727///
728/// Raw bounded metric series and provenance returned by a Dashboard source.
729///
730
731#[cfg(feature = "host")]
732#[derive(Clone, Debug, Eq, PartialEq)]
733pub struct IcMetricSourceData {
734 /// Source request and provenance preserved by the source.
735 pub source: IcSourceRequest,
736 /// Metric query applied by the source.
737 pub query: IcMetricQuery,
738 /// Raw named time series returned by the source.
739 pub series: Vec<IcMetricSeries>,
740}
741
742///
743/// IcBoundaryNodeDataCentersSourceData
744///
745/// Raw boundary-node data-center rows and provenance returned by a Dashboard source.
746///
747
748#[cfg(feature = "host")]
749#[derive(Clone, Debug, Eq, PartialEq)]
750pub struct IcBoundaryNodeDataCentersSourceData {
751 /// Source request and provenance preserved by the source.
752 pub source: IcSourceRequest,
753 /// Raw data-center rows returned by the source.
754 pub rows: Vec<IcBoundaryNodeDataCenterRow>,
755}
756
757///
758/// IcHostError
759///
760/// Typed error returned by IC Dashboard report builders and live sources.
761///
762
763#[cfg(feature = "host")]
764#[derive(Debug, ThisError)]
765pub enum IcHostError {
766 /// The synchronous adapter could not create its local async runtime.
767 #[error("failed to run IC Dashboard query: {0}")]
768 Runtime(#[from] RuntimeError),
769
770 /// A request supplied an invalid canister principal.
771 #[error("invalid {field}: {reason}")]
772 InvalidPrincipal {
773 /// Principal field being validated.
774 field: &'static str,
775 /// Principal parser diagnostic.
776 reason: String,
777 },
778
779 /// A request violates the bounded Dashboard query contract.
780 #[error("invalid {field}: {reason}")]
781 InvalidRequest {
782 /// Request field being validated.
783 field: &'static str,
784 /// Deterministic validation diagnostic.
785 reason: String,
786 },
787
788 /// The Dashboard API base endpoint is malformed or unsupported.
789 #[error("invalid IC Dashboard endpoint {endpoint}: {reason}")]
790 InvalidEndpoint {
791 /// Rejected endpoint.
792 endpoint: String,
793 /// URL validation diagnostic.
794 reason: String,
795 },
796
797 /// The HTTP client could not be constructed.
798 #[error("failed to build IC Dashboard HTTP client: {reason}")]
799 HttpClientBuild {
800 /// HTTP client construction diagnostic.
801 reason: String,
802 },
803
804 /// The live Dashboard request failed before a response was received.
805 #[error("IC Dashboard request to {url} failed: {reason}")]
806 HttpRequest {
807 /// Fully resolved request URL.
808 url: String,
809 /// HTTP transport error.
810 reason: String,
811 },
812
813 /// The Dashboard returned a non-success HTTP status.
814 #[error("IC Dashboard request to {url} returned HTTP status {status}")]
815 HttpStatus {
816 /// Fully resolved request URL.
817 url: String,
818 /// Numeric HTTP status.
819 status: u16,
820 },
821
822 /// The Dashboard response did not match the expected JSON shape.
823 #[error("failed to decode IC Dashboard response from {url}: {reason}")]
824 JsonDecode {
825 /// Fully resolved request URL.
826 url: String,
827 /// JSON response decoding error.
828 reason: String,
829 },
830
831 /// A source capability returned data that violates its public result contract.
832 #[error("invalid IC Dashboard source data: {reason}")]
833 InvalidSourceData {
834 /// Deterministic invariant failure.
835 reason: String,
836 },
837}