Skip to main content

canic_host/canister_ready/
mod.rs

1use crate::{
2    icp::{IcpCli, IcpCommandError},
3    replica_query::{self, ReplicaQueryError},
4};
5use std::{error::Error, fmt, path::Path};
6
7const CANIC_READY_METHOD: &str = "canic_ready";
8const ICP_JSON_OUTPUT: &str = "json";
9
10///
11/// CanisterReadyQueryError
12///
13
14#[derive(Debug)]
15pub enum CanisterReadyQueryError {
16    Replica(ReplicaQueryError),
17    Icp(IcpCommandError),
18    Json(serde_json::Error),
19}
20
21impl fmt::Display for CanisterReadyQueryError {
22    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
23        match self {
24            Self::Replica(err) => write!(formatter, "{err}"),
25            Self::Icp(err) => write!(formatter, "{err}"),
26            Self::Json(err) => write!(formatter, "{err}"),
27        }
28    }
29}
30
31impl Error for CanisterReadyQueryError {
32    fn source(&self) -> Option<&(dyn Error + 'static)> {
33        match self {
34            Self::Replica(err) => Some(err),
35            Self::Icp(err) => Some(err),
36            Self::Json(err) => Some(err),
37        }
38    }
39}
40
41impl From<ReplicaQueryError> for CanisterReadyQueryError {
42    fn from(err: ReplicaQueryError) -> Self {
43        Self::Replica(err)
44    }
45}
46
47impl From<IcpCommandError> for CanisterReadyQueryError {
48    fn from(err: IcpCommandError) -> Self {
49        Self::Icp(err)
50    }
51}
52
53impl From<serde_json::Error> for CanisterReadyQueryError {
54    fn from(err: serde_json::Error) -> Self {
55        Self::Json(err)
56    }
57}
58
59/// Query `canic_ready`, using the local replica API for local network targets.
60pub fn query_canister_ready(
61    icp: &IcpCli,
62    canister_id: &str,
63    network: &str,
64    icp_root: Option<&Path>,
65    candid_path: Option<&Path>,
66) -> Result<bool, CanisterReadyQueryError> {
67    if replica_query::should_use_local_replica_query(Some(network)) {
68        return query_local_canister_ready(network, canister_id, icp_root).map_err(Into::into);
69    }
70
71    query_canister_ready_with_icp(icp, canister_id, candid_path)
72}
73
74/// Query `canic_ready` directly through the local replica API.
75pub fn query_local_canister_ready(
76    network: &str,
77    canister_id: &str,
78    icp_root: Option<&Path>,
79) -> Result<bool, ReplicaQueryError> {
80    icp_root.map_or_else(
81        || replica_query::query_ready(Some(network), canister_id),
82        |root| replica_query::query_ready_from_root(Some(network), canister_id, root),
83    )
84}
85
86fn query_canister_ready_with_icp(
87    icp: &IcpCli,
88    canister_id: &str,
89    candid_path: Option<&Path>,
90) -> Result<bool, CanisterReadyQueryError> {
91    let output = icp.canister_query_output_with_candid(
92        canister_id,
93        CANIC_READY_METHOD,
94        Some(ICP_JSON_OUTPUT),
95        candid_path,
96    )?;
97    let data = serde_json::from_str::<serde_json::Value>(&output)?;
98    Ok(replica_query::parse_ready_json_value(&data))
99}