feat: Refactor mesh server to use Arc<Node>, introduce JoinAcceptance for mesh joins, and enhance store listing with prefix filtering and deleted entry inclusion.
This commit is contained in:
+4
-14
@@ -10,7 +10,6 @@ use lattice_core::{NodeBuilder, StoreHandle};
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::DefaultEditor;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
@@ -18,7 +17,7 @@ async fn main() {
|
||||
println!("Type 'help' for commands, 'quit' to exit.\n");
|
||||
|
||||
let node = match NodeBuilder::new().build() {
|
||||
Ok(n) => n,
|
||||
Ok(n) => Arc::new(n),
|
||||
Err(e) => {
|
||||
eprintln!("Failed to initialize: {}", e);
|
||||
return;
|
||||
@@ -37,12 +36,9 @@ async fn main() {
|
||||
}
|
||||
};
|
||||
|
||||
// Shared store handle for accept loop (updated when store is opened/changed)
|
||||
let shared_store: Arc<RwLock<Option<StoreHandle>>> = Arc::new(RwLock::new(None));
|
||||
|
||||
// Spawn accept loop for incoming connections
|
||||
if let Some(ref ep) = endpoint {
|
||||
spawn_accept_loop(ep.endpoint().clone(), shared_store.clone());
|
||||
spawn_accept_loop(node.clone(), ep.endpoint().clone());
|
||||
}
|
||||
|
||||
let info = node.info();
|
||||
@@ -53,18 +49,14 @@ async fn main() {
|
||||
println!("Stores: {}", info.stores.len());
|
||||
}
|
||||
|
||||
let mut current_store: Option<StoreHandle> = match node.open_root_store() {
|
||||
let mut current_store: Option<StoreHandle> = match node.open_root_store().await {
|
||||
Ok(Some(open_info)) => {
|
||||
if open_info.entries_replayed > 0 {
|
||||
println!("Root: {} (replayed {})", open_info.store_id, open_info.entries_replayed);
|
||||
} else {
|
||||
println!("Root: {}", open_info.store_id);
|
||||
}
|
||||
let h = node.root_store().as_ref().cloned();
|
||||
if let Some(ref handle) = h {
|
||||
*shared_store.write().await = Some(handle.clone());
|
||||
}
|
||||
h
|
||||
node.root_store().await.as_ref().cloned()
|
||||
}
|
||||
Ok(None) => {
|
||||
println!("Status: Not initialized (use 'init')");
|
||||
@@ -111,8 +103,6 @@ async fn main() {
|
||||
match (cmd.handler)(&node, current_store.as_ref(), endpoint.as_ref(), cmd_args) {
|
||||
CommandResult::Ok => {}
|
||||
CommandResult::SwitchTo(h) => {
|
||||
// Update shared store for accept loop
|
||||
*shared_store.write().await = Some(h.clone());
|
||||
current_store = Some(h);
|
||||
}
|
||||
CommandResult::Quit => break,
|
||||
|
||||
@@ -31,7 +31,7 @@ fn cmd_init(node: &Node, _store: Option<&StoreHandle>, _endpoint: Option<&Lattic
|
||||
Ok(store_id) => {
|
||||
println!("Initialized with root store: {}", store_id);
|
||||
println!("Node info stored in /nodes/{}/*", hex::encode(node.node_id()));
|
||||
match node.root_store().as_ref() {
|
||||
match block_async(node.root_store()).as_ref() {
|
||||
Some(h) => CommandResult::SwitchTo(h.clone()),
|
||||
None => CommandResult::Ok,
|
||||
}
|
||||
@@ -179,8 +179,8 @@ fn cmd_peers(node: &Node, _store: Option<&StoreHandle>, _endpoint: Option<&Latti
|
||||
by_status.entry(peer.status).or_default().push(peer);
|
||||
}
|
||||
|
||||
// Print grouped by status in order: active, invited, removed
|
||||
let status_order = [PeerStatus::Active, PeerStatus::Invited, PeerStatus::Removed];
|
||||
// Print grouped by status in order: active, invited, dormant
|
||||
let status_order = [PeerStatus::Active, PeerStatus::Invited, PeerStatus::Dormant];
|
||||
for status in &status_order {
|
||||
if let Some(peer_list) = by_status.get(status) {
|
||||
println!("\n[{}] ({}):", status.as_str(), peer_list.len());
|
||||
|
||||
@@ -11,7 +11,7 @@ pub fn store_commands() -> Vec<Command> {
|
||||
Command { name: "put", args: "<key> <value>", desc: "Store a key-value pair", group: "store", min_args: 2, max_args: 2, handler: cmd_put as Handler },
|
||||
Command { name: "get", args: "<key> [-v]", desc: "Get value for key", group: "store", min_args: 1, max_args: 2, handler: cmd_get as Handler },
|
||||
Command { name: "delete", args: "<key>", desc: "Delete a key", group: "store", min_args: 1, max_args: 1, handler: cmd_delete as Handler },
|
||||
Command { name: "list", args: "[-v]", desc: "List all keys", group: "store", min_args: 0, max_args: 1, handler: cmd_list as Handler },
|
||||
Command { name: "list", args: "[prefix] [-v]", desc: "List keys (optionally filtered by prefix)", group: "store", min_args: 0, max_args: 2, handler: cmd_list as Handler },
|
||||
Command { name: "author-state", args: "[pubkey]", desc: "Show author sync state", group: "store", min_args: 0, max_args: 1, handler: cmd_author_state as Handler },
|
||||
]
|
||||
}
|
||||
@@ -26,7 +26,7 @@ fn cmd_store_status(_node: &Node, store: Option<&StoreHandle>, _endpoint: Option
|
||||
println!("Log Seq: {}", block_async(h.log_seq()));
|
||||
println!("Applied: {}", block_async(h.applied_seq()).unwrap_or(0));
|
||||
|
||||
let all = block_async(h.list()).unwrap_or_default();
|
||||
let all = block_async(h.list(false)).unwrap_or_default();
|
||||
println!("Keys: {}", all.len());
|
||||
|
||||
// Show log directory size
|
||||
@@ -120,9 +120,19 @@ fn cmd_list(_node: &Node, store: Option<&StoreHandle>, _endpoint: Option<&Lattic
|
||||
println!("No store selected. Use 'init' or 'use <uuid>'");
|
||||
return CommandResult::Ok;
|
||||
};
|
||||
let verbose = args.first().map(|a| a == "-v").unwrap_or(false);
|
||||
|
||||
// Parse args: [prefix] [-v]
|
||||
let verbose = args.iter().any(|a| a == "-v");
|
||||
let prefix = args.iter().find(|a| *a != "-v").cloned();
|
||||
|
||||
let start = Instant::now();
|
||||
match block_async(h.list()) {
|
||||
let result = if let Some(p) = &prefix {
|
||||
block_async(h.list_by_prefix(p.as_bytes(), verbose))
|
||||
} else {
|
||||
block_async(h.list(verbose))
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok(entries) => {
|
||||
if entries.is_empty() {
|
||||
println!("(empty)");
|
||||
@@ -154,7 +164,8 @@ fn cmd_list(_node: &Node, store: Option<&StoreHandle>, _endpoint: Option<&Lattic
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("({} keys, {:.2?})", entries.len(), start.elapsed());
|
||||
let prefix_str = prefix.as_ref().map(|p| format!(" (prefix: {})", p)).unwrap_or_default();
|
||||
println!("({} keys{}, {:.2?})", entries.len(), prefix_str, start.elapsed());
|
||||
}
|
||||
}
|
||||
Err(e) => eprintln!("Error: {}", e),
|
||||
|
||||
Reference in New Issue
Block a user