Skip to main content

shadow_client/
api.rs

1//! High-level Shadow Network API
2
3use crate::node::{ShadowNode, NodeHandle};
4use shadow_core::{PeerId, PeerInfo};
5use shadow_core::error::Result;
6use bytes::Bytes;
7use tokio::sync::mpsc;
8use steganography::{ImageSteganography, LSBConfig};
9
10/// Message event
11#[derive(Debug, Clone)]
12pub enum MessageEvent {
13    /// Text message received
14    TextMessage {
15        from: PeerId,
16        content: String,
17    },
18    /// Binary data received
19    BinaryData {
20        from: PeerId,
21        data: Bytes,
22    },
23    /// File transfer started
24    FileTransfer {
25        from: PeerId,
26        filename: String,
27        size: usize,
28    },
29    /// Peer connected
30    PeerConnected(PeerInfo),
31    /// Peer disconnected
32    PeerDisconnected(PeerId),
33}
34
35/// High-level Shadow Network API
36pub struct ShadowApi {
37    node: NodeHandle,
38    event_tx: mpsc::UnboundedSender<MessageEvent>,
39    event_rx: mpsc::UnboundedReceiver<MessageEvent>,
40}
41
42impl ShadowApi {
43    /// Create new API instance
44    pub fn new(node: ShadowNode) -> Self {
45        let (event_tx, event_rx) = mpsc::unbounded_channel();
46        
47        Self {
48            node: NodeHandle::new(node),
49            event_tx,
50            event_rx,
51        }
52    }
53
54    /// Start the network node
55    pub async fn start(&mut self) -> Result<()> {
56        self.node.start().await
57    }
58
59    /// Stop the network node
60    pub async fn stop(&self) -> Result<()> {
61        self.node.stop().await
62    }
63
64    /// Send text message to peer (placeholder - requires full transport impl)
65    pub async fn send_text(&self, _peer_id: &PeerId, _message: &str) -> Result<()> {
66        // TODO: Implement with full transport layer
67        Ok(())
68    }
69
70    /// Send binary data to peer (placeholder - requires full transport impl)
71    pub async fn send_data(&self, _peer_id: &PeerId, _data: &[u8]) -> Result<()> {
72        // TODO: Implement with full transport layer
73        Ok(())
74    }
75
76    /// Send file with steganography
77    pub async fn send_file_steganographic(
78        &self,
79        peer_id: &PeerId,
80        file_data: &[u8],
81        cover_image_path: &str,
82    ) -> Result<String> {
83        // Embed file data in cover image
84        let stego = ImageSteganography::new(LSBConfig::default());
85        
86        let cover = ImageSteganography::load_image(cover_image_path)?;
87        let stego_image = stego.embed(&cover, file_data)?;
88        
89        // Save temporary stego image
90        let output_path = format!("/tmp/stego_{}.png", uuid::Uuid::new_v4());
91        ImageSteganography::save_image(&stego_image, &output_path, steganography::ImageFormat::PNG)?;
92        
93        // Send image path to peer (in real impl, transfer the image)
94        self.send_text(peer_id, &format!("FILE:{}", output_path)).await?;
95        
96        Ok(output_path)
97    }
98
99    /// Receive file with steganography
100    pub async fn receive_file_steganographic(&self, stego_image_path: &str) -> Result<Vec<u8>> {
101        let stego = ImageSteganography::new(LSBConfig::default());
102        stego.extract_file(stego_image_path)
103    }
104
105    /// Get next event
106    pub async fn next_event(&mut self) -> Option<MessageEvent> {
107        self.event_rx.recv().await
108    }
109
110    /// Add peer to network
111    pub async fn add_peer(&self, peer: PeerInfo) -> Result<()> {
112        // Clone once at the start
113        let peer_clone = peer.clone();
114        
115        self.node.node().add_peer(peer).await?;
116        
117        // Emit event with cloned peer
118        self.event_tx.send(MessageEvent::PeerConnected(peer_clone)).ok();
119        
120        Ok(())
121    }
122
123    /// Get list of connected peers
124    pub fn get_peers(&self) -> Vec<PeerInfo> {
125        self.node.node().get_peers()
126    }
127
128    /// Get node peer ID
129    pub fn peer_id(&self) -> PeerId {
130        self.node.node().peer_id()
131    }
132
133    /// Store data in DHT
134    pub async fn store(&self, key: [u8; 32], data: Bytes) -> Result<()> {
135        self.node.node().store_data(key, data).await
136    }
137
138    /// Retrieve data from DHT
139    pub async fn retrieve(&self, key: &[u8; 32]) -> Option<Bytes> {
140        self.node.node().get_data(key).await
141    }
142
143    /// Get node statistics
144    pub fn stats(&self) -> NodeStats {
145        let node_stats = self.node.node().stats();
146        
147        NodeStats {
148            peer_id: node_stats.peer_id,
149            peers: node_stats.connected_peers,
150            stored: node_stats.stored_values,
151            storage_mb: node_stats.storage_bytes / (1024 * 1024),
152        }
153    }
154}
155
156/// Public node statistics
157#[derive(Debug, Clone)]
158pub struct NodeStats {
159    pub peer_id: PeerId,
160    pub peers: usize,
161    pub stored: usize,
162    pub storage_mb: usize,
163}
164
165#[cfg(test)]
166mod tests {
167    use super::*;
168    use crypto::Keypair;
169
170    #[test]
171    fn test_api_creation() {
172        let keypair = Keypair::generate();
173        let node = ShadowNode::new(keypair);
174        let _api = ShadowApi::new(node);
175    }
176
177    #[tokio::test]
178    async fn test_api_lifecycle() {
179        let keypair = Keypair::generate();
180        let node = ShadowNode::new(keypair);
181        let mut api = ShadowApi::new(node);
182        
183        api.start().await.ok();
184        api.stop().await.ok();
185    }
186}