Skip to main content

interstice_cli/
bindings.rs

1use crate::{node_client::fetch_node_schema, node_registry::NodeRegistry};
2use interstice_core::IntersticeError;
3use std::path::{Path, PathBuf};
4
5pub async fn add_module_binding(
6    node_ref: &str,
7    module_name: &str,
8    project_path: &Path,
9) -> Result<PathBuf, IntersticeError> {
10    let mut registry = NodeRegistry::load()?;
11    let address = registry
12        .resolve_address(node_ref)
13        .ok_or_else(|| IntersticeError::Internal(format!("Unknown node '{}'", node_ref)))?;
14    let node_name = registry
15        .get(node_ref)
16        .map(|n| n.name.clone())
17        .unwrap_or_else(|| node_ref.to_string());
18    let (schema, handshake) = fetch_node_schema(&address, &node_name).await?;
19    registry.set_last_seen(node_ref);
20    registry.set_node_id(node_ref, handshake.node_id);
21    registry.save()?;
22
23    let module = schema
24        .modules
25        .into_iter()
26        .find(|m| m.name == module_name)
27        .ok_or_else(|| {
28            IntersticeError::Internal(format!("Module '{}' not found in node schema", module_name))
29        })?;
30
31    let bindings_dir = project_path.join("src").join("bindings");
32    std::fs::create_dir_all(&bindings_dir).map_err(|err| {
33        IntersticeError::Internal(format!("Failed to create bindings directory: {err}"))
34    })?;
35    let out_path = bindings_dir.join(format!("{}.toml", module_name));
36    let contents = module.to_public().to_toml_string().map_err(|err| {
37        IntersticeError::Internal(format!("Failed to serialize module schema: {err}"))
38    })?;
39    std::fs::write(&out_path, contents).map_err(|err| {
40        IntersticeError::Internal(format!("Failed to write module binding: {err}"))
41    })?;
42    Ok(out_path)
43}
44
45pub async fn add_node_binding(
46    node_ref: &str,
47    project_path: &Path,
48) -> Result<PathBuf, IntersticeError> {
49    let mut registry = NodeRegistry::load()?;
50    let address = registry
51        .resolve_address(node_ref)
52        .ok_or_else(|| IntersticeError::Internal(format!("Unknown node '{}'", node_ref)))?;
53    let node_name = registry
54        .get(node_ref)
55        .map(|n| n.name.clone())
56        .unwrap_or_else(|| node_ref.to_string());
57    let (schema, handshake) = fetch_node_schema(&address, &node_name).await?;
58    registry.set_last_seen(node_ref);
59    registry.set_node_id(node_ref, handshake.node_id);
60    registry.save()?;
61
62    let bindings_dir = project_path.join("src").join("bindings");
63    std::fs::create_dir_all(&bindings_dir).map_err(|err| {
64        IntersticeError::Internal(format!("Failed to create bindings directory: {err}"))
65    })?;
66    let file_name = sanitize_filename(&node_name);
67    let out_path = bindings_dir.join(format!("node_{}.toml", file_name));
68    let contents = schema.to_toml_string().map_err(|err| {
69        IntersticeError::Internal(format!("Failed to serialize node schema: {err}"))
70    })?;
71    std::fs::write(&out_path, contents)
72        .map_err(|err| IntersticeError::Internal(format!("Failed to write node binding: {err}")))?;
73    Ok(out_path)
74}
75
76fn sanitize_filename(value: &str) -> String {
77    value
78        .chars()
79        .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' })
80        .collect()
81}