canic_host/replica_query/
mod.rs1mod cbor;
8mod status;
9mod transport;
10mod wire;
11
12use self::{
13 transport::local_query,
14 wire::{
15 decode_bootstrap_status_response, decode_cycle_balance_response,
16 decode_subnet_registry_response,
17 },
18};
19use crate::registry::{RegistryEntry, RegistryParseError, registry_entries_from_response};
20use std::path::Path;
21
22use candid::Decode;
23use canic_core::dto::{error::Error as CanicError, state::BootstrapStatusResponse};
24use thiserror::Error as ThisError;
25
26pub use self::status::local_replica_status_reachable_from_root;
27pub(crate) use self::{
28 status::local_replica_root_key_from_root, transport::local_replica_endpoint_from_root,
29};
30
31#[derive(Debug, ThisError)]
36pub enum ReplicaQueryError {
37 #[error(transparent)]
38 Candid(candid::Error),
39
40 #[error("{0}")]
41 Canister(CanicError),
42
43 #[error("{0}")]
44 Cbor(String),
45
46 #[error(transparent)]
47 Io(#[from] std::io::Error),
48
49 #[error("{0}")]
50 Query(String),
51
52 #[error(transparent)]
53 Registry(#[from] RegistryParseError),
54
55 #[error("local replica rejected query: code={code} message={message}")]
56 Rejected { code: u64, message: String },
57}
58
59impl From<cbor::CborError> for ReplicaQueryError {
60 fn from(err: cbor::CborError) -> Self {
62 Self::Cbor(err.to_string())
63 }
64}
65
66#[must_use]
68pub fn should_use_local_replica_query(environment: Option<&str>) -> bool {
69 environment
70 .is_none_or(|environment| environment == "local" || environment.starts_with("http://"))
71}
72
73pub(crate) fn query_ready(
75 environment: Option<&str>,
76 canister: &str,
77 icp_root: Option<&Path>,
78) -> Result<bool, ReplicaQueryError> {
79 let bytes = local_query(environment, canister, "canic_ready", icp_root)?;
80 Decode!(&bytes, bool).map_err(ReplicaQueryError::Candid)
81}
82
83pub(crate) fn query_bootstrap_status_from_root(
85 environment: Option<&str>,
86 canister: &str,
87 icp_root: &Path,
88) -> Result<BootstrapStatusResponse, ReplicaQueryError> {
89 let bytes = local_query(
90 environment,
91 canister,
92 "canic_bootstrap_status",
93 Some(icp_root),
94 )?;
95 decode_bootstrap_status_response(&bytes)
96}
97
98pub(crate) fn query_cycle_balance(
100 environment: Option<&str>,
101 canister: &str,
102 icp_root: Option<&Path>,
103) -> Result<u128, ReplicaQueryError> {
104 let bytes = local_query(environment, canister, "canic_cycle_balance", icp_root)?;
105 decode_cycle_balance_response(&bytes)
106}
107
108pub(crate) fn query_subnet_registry_entries(
110 environment: Option<&str>,
111 root: &str,
112 icp_root: Option<&Path>,
113) -> Result<Vec<RegistryEntry>, ReplicaQueryError> {
114 let bytes = local_query(environment, root, "canic_subnet_registry", icp_root)?;
115 let response = decode_subnet_registry_response(&bytes)?;
116 registry_entries_from_response(response).map_err(Into::into)
117}
118
119pub(crate) fn query_subnet_registry_roles_from_root(
121 environment: Option<&str>,
122 root: &str,
123 icp_root: &Path,
124) -> Result<Vec<String>, ReplicaQueryError> {
125 Ok(
126 query_subnet_registry_entries(environment, root, Some(icp_root))?
127 .into_iter()
128 .filter_map(|entry| entry.role)
129 .collect(),
130 )
131}