p2p_chat/ui/runner/actions/commands/
friends.rs1use anyhow::Result;
3use base64::prelude::BASE64_STANDARD;
4use base64::Engine;
5use libp2p::PeerId;
6use std::str::FromStr;
7
8use crate::types::Friend;
9
10use super::super::context::CommandContext;
11
12pub async fn add_friend(parts: &[&str], context: &CommandContext) -> Result<()> {
27 if !(3..=4).contains(&parts.len()) {
28 context.emit_chat("Usage: friend <peer_id> <e2e_key> [nickname]");
29 return Ok(());
30 }
31
32 let peer_id = match PeerId::from_str(parts[1]) {
33 Ok(id) => id,
34 Err(e) => {
35 context.emit_chat(format!("❌ Invalid peer ID: {}", e));
36 return Ok(());
37 }
38 };
39
40 let e2e_public_key = match BASE64_STANDARD.decode(parts[2]) {
41 Ok(key) => key,
42 Err(e) => {
43 context.emit_chat(format!("❌ Invalid base64 key: {}", e));
44 return Ok(());
45 }
46 };
47
48 let nickname = parts.get(3).map(|s| s.to_string());
49
50 let friend = Friend {
51 peer_id,
52 e2e_public_key,
53 nickname: nickname.clone(),
54 };
55
56 match context.node().friends.add_friend(friend).await {
57 Ok(()) => {
58 context.emit_chat(format!(
59 "✅ Added friend: {} ({})",
60 peer_id,
61 nickname.unwrap_or_else(|| "no nickname".to_string())
62 ));
63 }
64 Err(e) => {
65 context.emit_chat(format!("❌ Failed to add friend: {}", e));
66 }
67 }
68
69 Ok(())
70}
71
72pub async fn list_friends(context: &CommandContext) -> Result<()> {
84 match context.node().friends.list_friends().await {
85 Ok(friends) => {
86 if friends.is_empty() {
87 context.emit_chat("No friends added yet.");
88 } else {
89 let mut output = format!("Friends ({}):", friends.len());
90 for friend in friends {
91 let nickname = friend.nickname.as_deref().unwrap_or("(no nickname)");
92 output.push_str(&format!("\n {} - {}", friend.peer_id, nickname));
93 }
94 context.emit_chat(output);
95 }
96 }
97 Err(e) => {
98 context.emit_chat(format!("❌ Failed to list friends: {}", e));
99 }
100 }
101
102 Ok(())
103}