use crate::{ client::{AppHandle, ClientEvent}, net::{ ClientMsg, SERVER_NAME, ServerMsg, no_cert::SkipServerVerification, transfer::{RecvHandler, recv_uni, send_uni}, }, }; use quinn::{ ClientConfig, Connection, Endpoint, IdleTimeout, TransportConfig, crypto::rustls::QuicClientConfig, }; use std::{ net::{Ipv6Addr, SocketAddr, SocketAddrV6, ToSocketAddrs}, sync::Arc, time::Duration, }; use tokio::sync::mpsc::UnboundedSender; pub const CLIENT_SOCKET: SocketAddr = SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 0, 0, 0)); pub struct ConnectInfo { pub ip: String, pub username: String, } pub fn connect(handle: AppHandle, info: ConnectInfo) { std::thread::spawn(move || { if let Err(msg) = connect_the(handle.clone(), info) { handle.send(ClientEvent::Err(msg)); } }); } type NetResult = Result; type MsgPayload = ClientMsg; pub struct NetSender { send: UnboundedSender, } impl NetSender { pub fn send(&self, msg: ClientMsg) { let _ = self.send.send(msg); } } // async fn connection_cert(addr: SocketAddr) -> NetResult { // let dirs = directories_next::ProjectDirs::from("", "", "openworm").unwrap(); // let mut roots = quinn::rustls::RootCertStore::empty(); // match fs::read(dirs.data_local_dir().join("cert.der")) { // Ok(cert) => { // roots.add(CertificateDer::from(cert))?; // } // Err(ref e) if e.kind() == ErrorKind::NotFound => { // eprintln!("local server certificate not found"); // } // Err(e) => { // eprintln!("failed to open local server certificate: {}", e); // } // } // let client_crypto = quinn::rustls::ClientConfig::builder() // .with_root_certificates(roots) // .with_no_client_auth(); // let client_config = ClientConfig::new(Arc::new(QuicClientConfig::try_from(client_crypto)?)); // let mut endpoint = quinn::Endpoint::client(SocketAddr::from_str("[::]:0").unwrap())?; // endpoint.set_default_client_config(client_config); // endpoint // .connect(addr, SERVER_NAME)? // .await // .map_err(|e| format!("failed to connect: {}", e)) // } async fn connection_no_cert(addr: SocketAddr) -> NetResult { let mut endpoint = Endpoint::client(CLIENT_SOCKET).map_err(|e| e.to_string())?; let quic = QuicClientConfig::try_from( quinn::rustls::ClientConfig::builder() .dangerous() .with_custom_certificate_verifier(SkipServerVerification::new()) .with_no_client_auth(), ) .map_err(|e| e.to_string())?; let mut config = ClientConfig::new(Arc::new(quic)); let mut transport = TransportConfig::default(); transport.keep_alive_interval(Some(Duration::from_secs(5))); transport.max_idle_timeout(Some( IdleTimeout::try_from(Duration::from_secs(10)).unwrap(), )); config.transport_config(transport.into()); endpoint.set_default_client_config(config); // connect to server endpoint .connect(addr, SERVER_NAME) .map_err(|e| e.to_string())? .await .map_err(|e| e.to_string()) } #[tokio::main] async fn connect_the(handle: AppHandle, info: ConnectInfo) -> NetResult<()> { let (send, mut ui_recv) = tokio::sync::mpsc::unbounded_channel::(); let addr = info .ip .to_socket_addrs() .map_err(|e| e.to_string())? .next() .ok_or("no addresses found".to_string())?; let conn = connection_no_cert(addr).await?; let conn_ = conn.clone(); handle.send(ClientEvent::Connect { username: info.username, send: NetSender { send }, }); let recv = ServerRecv { handle }; tokio::spawn(recv_uni(conn_, recv.into())); while let Some(msg) = ui_recv.recv().await { if send_uni(&conn, msg).await.is_err() { println!("disconnected from server"); break; } } Ok(()) } struct ServerRecv { handle: AppHandle, } impl RecvHandler for ServerRecv { async fn msg(&self, msg: ServerMsg) { self.handle.send(ClientEvent::ServerMsg(msg)); } }