canic_host/replica_query/
mod.rs1mod cbor;
8mod status;
9mod transport;
10mod wire;
11
12use self::{
13 transport::local_query,
14 wire::{decode_cycle_balance_response, decode_subnet_registry_response},
15};
16use crate::registry::{RegistryEntry, RegistryParseError, registry_entries_from_response};
17use std::path::Path;
18
19use candid::Decode;
20use canic_core::dto::error::Error as CanicError;
21use thiserror::Error as ThisError;
22
23pub use self::status::local_replica_status_reachable_from_root;
24pub(crate) use self::{
25 status::local_replica_root_key_from_root, transport::local_replica_endpoint_from_root,
26};
27
28fn nonempty_text(text: &str) -> Option<String> {
29 let trimmed = text.trim();
30 (!trimmed.is_empty()).then(|| trimmed.to_string())
31}
32
33#[derive(Debug, ThisError)]
38pub enum ReplicaQueryError {
39 #[error(transparent)]
40 Candid(candid::Error),
41
42 #[error("{0}")]
43 Canister(CanicError),
44
45 #[error("{0}")]
46 Cbor(String),
47
48 #[error(transparent)]
49 Io(#[from] std::io::Error),
50
51 #[error("{0}")]
52 Query(String),
53
54 #[error(transparent)]
55 Registry(#[from] RegistryParseError),
56
57 #[error("local replica rejected query: code={code} message={message}")]
58 Rejected { code: u64, message: String },
59}
60
61impl From<cbor::CborError> for ReplicaQueryError {
62 fn from(err: cbor::CborError) -> Self {
64 Self::Cbor(err.to_string())
65 }
66}
67
68#[must_use]
70pub fn should_use_local_replica_query(environment: Option<&str>) -> bool {
71 environment
72 .is_none_or(|environment| environment == "local" || environment.starts_with("http://"))
73}
74
75pub(crate) fn query_ready(
77 environment: Option<&str>,
78 canister: &str,
79 icp_root: Option<&Path>,
80) -> Result<bool, ReplicaQueryError> {
81 let bytes = local_query(environment, canister, "canic_ready", icp_root)?;
82 Decode!(&bytes, bool).map_err(ReplicaQueryError::Candid)
83}
84
85pub(crate) fn query_cycle_balance(
87 environment: Option<&str>,
88 canister: &str,
89 icp_root: Option<&Path>,
90) -> Result<u128, ReplicaQueryError> {
91 let bytes = local_query(environment, canister, "canic_cycle_balance", icp_root)?;
92 decode_cycle_balance_response(&bytes)
93}
94
95pub(crate) fn query_subnet_registry_entries(
97 environment: Option<&str>,
98 root: &str,
99 icp_root: Option<&Path>,
100) -> Result<Vec<RegistryEntry>, ReplicaQueryError> {
101 let bytes = local_query(environment, root, "canic_subnet_registry", icp_root)?;
102 let response = decode_subnet_registry_response(&bytes)?;
103 registry_entries_from_response(response).map_err(Into::into)
104}