interstice_cli/
node_utils.rs1use crate::{
2 data_directory::nodes_dir,
3 node_client::{fetch_node_schema, handshake_with_node},
4 node_registry::{NodeRecord, NodeRegistry},
5 start::start,
6};
7use interstice_core::{IntersticeError, Node};
8use std::path::Path;
9
10pub fn remove_node_with_data(
12 registry: &mut NodeRegistry,
13 name_or_id: &str,
14) -> Result<(), IntersticeError> {
15 let removed = registry.remove(name_or_id)?;
16 if removed.local {
17 if let Some(node_id) = removed.node_id {
18 let node_path = nodes_dir().join(node_id);
19 if node_path.exists() {
20 std::fs::remove_dir_all(&node_path).map_err(|err| {
21 IntersticeError::Internal(format!(
22 "Failed to remove node data at {}. \
23 Is another instance still running? Error: {err}",
24 node_path.display()
25 ))
26 })?;
27 }
28 }
29 }
30 Ok(())
31}
32
33pub async fn handle_node_command(args: &[String]) -> Result<(), IntersticeError> {
34 if args.len() < 3 {
35 print_node_help();
36 return Ok(());
37 }
38
39 let mut registry = NodeRegistry::load()?;
40 match args[2].as_str() {
41 "add" => {
42 if args.len() < 5 {
43 print_node_help();
44 return Ok(());
45 }
46 let name = args[3].clone();
47 let address = args[4].clone();
48 registry.add(NodeRecord {
49 name,
50 address,
51 node_id: None,
52 local: false,
53 last_seen: None,
54 })?;
55 println!("Node added.");
56 }
57 "create" => {
58 if args.len() < 5 {
59 print_node_help();
60 return Ok(());
61 }
62 let name = args[3].clone();
63 let port: u32 = args[4]
64 .trim()
65 .parse()
66 .map_err(|err| IntersticeError::Internal(format!("Failed to parse port: {err}")))?;
67 let address = format!("127.0.0.1:{}", port);
68 let node = Node::new(&nodes_dir(), port)?;
69 registry.add(NodeRecord {
70 name,
71 address,
72 node_id: Some(node.id.to_string()),
73 local: true,
74 last_seen: None,
75 })?;
76 println!("Local node created.");
77 }
78 "list" => {
79 for node in registry.list_sorted() {
80 let id = node.node_id.clone().unwrap_or_else(|| "-".into());
81 let last_seen = node
82 .last_seen
83 .map(|t| t.to_string())
84 .unwrap_or_else(|| "-".into());
85 println!("{} | {} | {} | {}", node.name, node.address, id, last_seen);
86 }
87 }
88 "remove" => {
89 if args.len() < 4 {
90 print_node_help();
91 return Ok(());
92 }
93 remove_node_with_data(&mut registry, &args[3])?;
94 println!("Node removed.");
95 }
96 "rename" => {
97 if args.len() < 5 {
98 print_node_help();
99 return Ok(());
100 }
101 registry.rename(&args[3], &args[4])?;
102 println!("Node renamed.");
103 }
104 "show" => {
105 if args.len() < 4 {
106 print_node_help();
107 return Ok(());
108 }
109 let node = registry
110 .get(&args[3])
111 .ok_or_else(|| IntersticeError::Internal("Node not found".into()))?;
112 println!("name: {}", node.name);
113 println!("address: {}", node.address);
114 println!(
115 "node_id: {}",
116 node.node_id.clone().unwrap_or_else(|| "-".into())
117 );
118 println!("local: {}", node.local);
119 println!(
120 "last_seen: {}",
121 node.last_seen
122 .map(|t| t.to_string())
123 .unwrap_or_else(|| "-".into())
124 );
125 }
126 "start" => {
127 if args.len() < 4 {
128 print_node_help();
129 return Ok(());
130 }
131 let node = registry
132 .get(&args[3])
133 .ok_or_else(|| IntersticeError::Internal("Node not found".into()))?;
134 let port = node
135 .address
136 .split(':')
137 .next_back()
138 .ok_or_else(|| IntersticeError::Internal("Invalid address".into()))?
139 .parse()
140 .map_err(|_| IntersticeError::Internal("Invalid port".into()))?;
141
142 let node_id = node
143 .node_id
144 .clone()
145 .ok_or_else(|| IntersticeError::Internal("Missing node id".into()))?;
146 let parsed_node_id = node_id
147 .parse()
148 .map_err(|_| IntersticeError::Internal("Invalid node id".into()))?;
149 start(parsed_node_id, port).await?;
150 }
151 "ping" => {
152 if args.len() < 4 {
153 print_node_help();
154 return Ok(());
155 }
156 let address = registry
157 .resolve_address(&args[3])
158 .ok_or_else(|| IntersticeError::Internal("Unknown node".into()))?;
159 let (_stream, handshake) = handshake_with_node(&address).await?;
160 registry.set_last_seen(&args[3]);
161 registry.set_node_id(&args[3], handshake.node_id);
162 registry.save()?;
163 println!("Node reachable.");
164 }
165 "schema" => {
166 if args.len() < 4 {
167 print_node_help();
168 return Ok(());
169 }
170 let node_ref = &args[3];
171 let out_path = args
172 .get(4)
173 .map(Path::new)
174 .unwrap_or_else(|| Path::new("node_schema.toml"));
175 let address = registry
176 .resolve_address(node_ref)
177 .ok_or_else(|| IntersticeError::Internal("Unknown node".into()))?;
178 let node_name = registry
179 .get(node_ref)
180 .map(|node| node.name.clone())
181 .unwrap_or_else(|| node_ref.clone());
182 let (schema, handshake) = fetch_node_schema(&address, &node_name).await?;
183 registry.set_last_seen(node_ref);
184 registry.set_node_id(node_ref, handshake.node_id);
185 registry.save()?;
186 let contents = schema.to_toml_string().map_err(|err| {
187 IntersticeError::Internal(format!("Failed to serialize schema: {err}"))
188 })?;
189 std::fs::write(out_path, contents).map_err(|err| {
190 IntersticeError::Internal(format!("Failed to write schema: {err}"))
191 })?;
192 println!("Schema written to {}", out_path.display());
193 }
194 _ => print_node_help(),
195 }
196
197 Ok(())
198}
199
200fn print_node_help() {
201 println!("USAGE:");
202 println!(" interstice node add <name> <address>");
203 println!(" interstice node create <name> <port>");
204 println!(" interstice node list");
205 println!(" interstice node remove <name|id>");
206 println!(" interstice node rename <old> <new>");
207 println!(" interstice node show <name|id>");
208 println!(" interstice node start <name|id>");
209 println!(" interstice node ping <name|id>");
210 println!(" interstice node schema <name|id> [out]");
211}