canic_host/registry/
mod.rs1#[cfg(test)]
8mod tests;
9
10use crate::icp::{IcpJsonResponseError, decode_json_result_response};
11use canic_core::{
12 cdk::utils::hash::hex_bytes,
13 dto::topology::{SubnetRegistryEntry, SubnetRegistryResponse},
14};
15use thiserror::Error as ThisError;
16
17#[derive(Clone, Debug, Eq, PartialEq)]
22pub struct RegistryEntry {
23 pub pid: String,
24 pub role: Option<String>,
25 pub parent_pid: Option<String>,
26 pub module_hash: Option<String>,
27}
28
29#[derive(Debug, ThisError)]
34pub enum RegistryParseError {
35 #[error("registry entry principal mismatch: entry={entry_pid} record={record_pid}")]
36 PrincipalMismatch {
37 entry_pid: String,
38 record_pid: String,
39 },
40
41 #[error(transparent)]
42 Response(#[from] IcpJsonResponseError),
43
44 #[error("registry entry role mismatch for {pid}: entry={entry_role} record={record_role}")]
45 RoleMismatch {
46 pid: String,
47 entry_role: String,
48 record_role: String,
49 },
50}
51
52pub fn parse_registry_entries(
54 registry_json: &str,
55) -> Result<Vec<RegistryEntry>, RegistryParseError> {
56 let response = decode_json_result_response::<SubnetRegistryResponse>(registry_json)?;
57 registry_entries_from_response(response)
58}
59
60pub(crate) fn registry_entries_from_response(
62 response: SubnetRegistryResponse,
63) -> Result<Vec<RegistryEntry>, RegistryParseError> {
64 response.0.into_iter().map(registry_entry).collect()
65}
66
67fn registry_entry(entry: SubnetRegistryEntry) -> Result<RegistryEntry, RegistryParseError> {
68 let pid = entry.pid.to_text();
69 let record_pid = entry.record.pid.to_text();
70 if pid != record_pid {
71 return Err(RegistryParseError::PrincipalMismatch {
72 entry_pid: pid,
73 record_pid,
74 });
75 }
76
77 let role = entry.role.into_string();
78 let record_role = entry.record.role.into_string();
79 if role != record_role {
80 return Err(RegistryParseError::RoleMismatch {
81 pid,
82 entry_role: role,
83 record_role,
84 });
85 }
86
87 Ok(RegistryEntry {
88 pid,
89 role: Some(role),
90 parent_pid: entry.record.parent_pid.map(|pid| pid.to_text()),
91 module_hash: entry.record.module_hash.map(hex_bytes),
92 })
93}