joecalsend/src/lib.rs
2025-07-04 15:15:52 -07:00

129 lines
3.9 KiB
Rust

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<UdpSocket>,
pub multicast_addr: SocketAddrV4,
pub port: u16,
pub peers: Arc<Mutex<HashMap<String, (SocketAddr, DeviceInfo)>>>,
pub sessions: Arc<Mutex<HashMap<String, Session>>>, // Session ID to Session
pub http_client: reqwest::Client,
pub download_dir: String,
}
#[derive(Clone)]
pub struct JoecalState {
pub device: DeviceInfo,
pub peers: Arc<Mutex<HashMap<String, (SocketAddr, DeviceInfo)>>>,
pub sessions: Arc<Mutex<HashMap<String, Session>>>, // Session ID to Session
}
impl Client {
pub async fn default() -> crate::error::Result<Self> {
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<Self> {
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();
}
}