pub mod discovery; pub mod error; pub mod models; pub mod server; pub mod transfer; use std::{ collections::HashMap, net::{Ipv4Addr, SocketAddr, SocketAddrV4}, sync::Arc, }; use tokio::{net::UdpSocket, sync::Mutex, task::JoinHandle}; use transfer::session::Session; use crate::models::device::DeviceInfo; #[derive(Clone)] pub struct Client { pub device: DeviceInfo, pub socket: Arc, pub multicast_addr: SocketAddrV4, pub port: u16, pub peers: Arc>>, pub sessions: Arc>>, // Session ID to Session pub http_client: reqwest::Client, pub download_dir: String, } #[derive(Clone)] pub struct JoecalState { pub device: DeviceInfo, pub peers: Arc>>, pub sessions: Arc>>, // Session ID to Session } impl Client { pub async fn default() -> crate::error::Result { let device = DeviceInfo::default(); let socket = UdpSocket::bind("0.0.0.0:53317").await?; socket.set_multicast_loop_v4(true)?; socket.set_multicast_ttl_v4(255)?; socket.join_multicast_v4(Ipv4Addr::new(224, 0, 0, 167), Ipv4Addr::new(0, 0, 0, 0))?; let multicast_addr = SocketAddrV4::new(Ipv4Addr::new(224, 0, 0, 167), 53317); let port = 53317; let peers = Arc::new(Mutex::new(HashMap::new())); let http_client = reqwest::Client::new(); let sessions = Arc::new(Mutex::new(HashMap::new())); let download_dir = "/home/localsend".to_string(); Ok(Self { device, socket: socket.into(), multicast_addr, port, peers, http_client, sessions, download_dir, }) } pub async fn with_config( info: DeviceInfo, port: u16, download_dir: String, ) -> crate::error::Result { let socket = UdpSocket::bind(format!("0.0.0.0:{}", port.clone())).await?; socket.set_multicast_loop_v4(true)?; socket.set_multicast_ttl_v4(255)?; socket.join_multicast_v4(Ipv4Addr::new(224, 0, 0, 167), Ipv4Addr::new(0, 0, 0, 0))?; let multicast_addr = SocketAddrV4::new(Ipv4Addr::new(224, 0, 0, 167), port); let peers = Arc::new(Mutex::new(HashMap::new())); let http_client = reqwest::Client::new(); let sessions = Arc::new(Mutex::new(HashMap::new())); Ok(Self { device: info, socket: socket.into(), multicast_addr, port, peers, http_client, sessions, download_dir, }) } pub async fn start( &self, ) -> crate::error::Result<(JoinHandle<()>, JoinHandle<()>, JoinHandle<()>)> { let server_handle = { let client = self.clone(); tokio::spawn(async move { if let Err(e) = client.start_http_server().await { eprintln!("HTTP server error: {e}"); } }) }; let udp_handle = { let client = self.clone(); tokio::spawn(async move { if let Err(e) = client.listen_multicast().await { eprintln!("UDP listener error: {}", e); } }) }; let announcement_handle = { let client = self.clone(); tokio::spawn(async move { loop { if let Err(e) = client.announce(None).await { eprintln!("Announcement error: {}", e); } tokio::time::sleep(std::time::Duration::from_secs(5)).await; } }) }; Ok((server_handle, udp_handle, announcement_handle)) } pub async fn refresh_peers(&self) { let mut peers = self.peers.lock().await; peers.clear(); } }