Skip to main content

meerkat_comms/runtime/
comms_bootstrap.rs

1//! CommsBootstrap - Unified comms setup for all agents.
2
3use super::comms_config::CoreCommsConfig;
4use super::comms_runtime::CommsRuntime;
5#[cfg(not(target_arch = "wasm32"))]
6use std::path::PathBuf;
7use thiserror::Error;
8
9#[derive(Debug, Error)]
10pub enum CommsBootstrapError {
11    #[error("Runtime error: {0}")]
12    RuntimeError(String),
13}
14
15pub enum CommsBootstrapMode {
16    #[cfg(not(target_arch = "wasm32"))]
17    Standalone,
18    ChildInproc,
19}
20
21pub struct CommsAdvertise {
22    pub name: String,
23    pub pubkey: [u8; 32],
24    pub addr: String,
25}
26
27pub struct CommsBootstrap {
28    config: CoreCommsConfig,
29    #[cfg(not(target_arch = "wasm32"))]
30    base_dir: PathBuf,
31    mode: CommsBootstrapMode,
32    parent_context: Option<ParentCommsContext>,
33}
34
35impl CommsBootstrap {
36    #[cfg(not(target_arch = "wasm32"))]
37    pub fn from_config(config: CoreCommsConfig, base_dir: PathBuf) -> Self {
38        Self {
39            config,
40            base_dir,
41            mode: CommsBootstrapMode::Standalone,
42            parent_context: None,
43        }
44    }
45
46    pub fn for_child_inproc(name: String, parent_context: ParentCommsContext) -> Self {
47        let mut config = CoreCommsConfig::with_name(&name);
48        config.enabled = true;
49        config
50            .inproc_namespace
51            .clone_from(&parent_context.inproc_namespace);
52        Self {
53            config,
54            #[cfg(not(target_arch = "wasm32"))]
55            base_dir: parent_context.comms_base_dir.clone(),
56            mode: CommsBootstrapMode::ChildInproc,
57            parent_context: Some(parent_context),
58        }
59    }
60
61    pub async fn prepare(self) -> Result<Option<PreparedComms>, CommsBootstrapError> {
62        match self.mode {
63            #[cfg(not(target_arch = "wasm32"))]
64            CommsBootstrapMode::Standalone => {
65                let resolved = self.config.resolve_paths(&self.base_dir);
66                let runtime = CommsRuntime::new(resolved)
67                    .await
68                    .map_err(|e| CommsBootstrapError::RuntimeError(e.to_string()))?;
69                Ok(Some(PreparedComms {
70                    runtime,
71                    advertise: None,
72                }))
73            }
74            CommsBootstrapMode::ChildInproc => {
75                let _parent = self.parent_context.ok_or_else(|| {
76                    CommsBootstrapError::RuntimeError(
77                        "ChildInproc mode requires parent_context".to_string(),
78                    )
79                })?;
80                let runtime = CommsRuntime::inproc_only_scoped(
81                    &self.config.name,
82                    self.config.inproc_namespace.clone(),
83                )
84                .map_err(|e| CommsBootstrapError::RuntimeError(e.to_string()))?;
85
86                let advertise = CommsAdvertise {
87                    name: self.config.name,
88                    pubkey: *runtime.public_key().as_bytes(),
89                    addr: format!("inproc://{}", runtime.public_key().to_peer_id()),
90                };
91
92                Ok(Some(PreparedComms {
93                    runtime,
94                    advertise: Some(advertise),
95                }))
96            }
97        }
98    }
99}
100
101#[derive(Debug, Clone)]
102pub struct ParentCommsContext {
103    pub parent_name: String,
104    pub parent_pubkey: [u8; 32],
105    pub parent_addr: String,
106    #[cfg(not(target_arch = "wasm32"))]
107    pub comms_base_dir: PathBuf,
108    pub inproc_namespace: Option<String>,
109}
110
111pub struct PreparedComms {
112    pub runtime: CommsRuntime,
113    pub advertise: Option<CommsAdvertise>,
114}
115
116pub fn create_child_comms_config(name: &str) -> CoreCommsConfig {
117    CoreCommsConfig::with_name(name)
118}