use std::io; use std::net::SocketAddrV4; use tokio::net::{TcpListener, TcpStream}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tauri::{AppHandle, Manager}; mod errors; use errors::RequestError; pub async fn serve(addr: SocketAddrV4, app_handle: AppHandle) -> io::Result<()> { let listener = TcpListener::bind(&addr).await?; println!("Listening on {addr}"); loop { let new_handle = app_handle.app_handle(); match listener.accept().await { Ok((stream, _)) => { tokio::spawn(async { if let Err(e) = handle(stream, new_handle).await { eprintln!("{e}"); } }); }, Err(e) => { eprintln!("Error accepting connection: {e}"); } } } } // it doesn't really return a String, we just need to placate the compiler async fn stall(stream: &mut TcpStream) -> Result { let delay = std::time::Duration::from_secs(1); loop { tokio::time::sleep(delay).await; stream.write(b"x").await?; } } async fn handle(mut stream: TcpStream, app_handle: AppHandle) -> Result<(), RequestError> { let mut buf = [0; 8192]; // it's what tokio's BufReader uses let mut n = 0; loop { n += stream.read(&mut buf[n..]).await?; if &buf[(n - 4)..n] == b"\r\n\r\n" {break;} if n == buf.len() {return Err(RequestError::RequestTooLarge);} } println!("{}", std::str::from_utf8(&buf).unwrap()); stream.write(b"HTTP/1.0 200 OK\r\n").await?; stream.write(b"Content-Type: application/json\r\n").await?; stream.write(b"X-Creddy-delaying-tactic: ").await?; let creds = tokio::select!{ r = stall(&mut stream) => r?, // this will never return Ok, just Err if it can't write to the stream c = get_creds(&app_handle) => c?, }; stream.write(b"\r\nContent-Length: ").await?; stream.write(creds.as_bytes().len().to_string().as_bytes()).await?; stream.write(b"\r\n\r\n").await?; stream.write(creds.as_bytes()).await?; stream.write(b"\r\n\r\n").await?; Ok(()) } use tokio::io::{stdin, stdout, BufReader, AsyncBufReadExt}; use crate::storage; use tokio::sync::oneshot; use std::sync::Mutex; async fn get_creds(app_handle: &AppHandle) -> io::Result { { let state_guard = app_handle.state::>(); let mut state = state_guard.lock().unwrap(); state.num_requests += 1; let req = crate::CredentialsRequest { request_id: state.num_requests }; app_handle.emit_all("credentials-request", req).unwrap(); // lock gets released here in case somebody else needs app state while we're waiting } let (tx, rx) = oneshot::channel(); app_handle.once_global("request-response", |event| { let response = event.payload().unwrap_or("").to_string(); tx.send(response).unwrap(); }); // Error is only returned if the rx is closed/dropped before receiving, which should never happen // LOL who am I kidding this happens all the time // fix it later // todo: handle "denied" response let _response = rx.await.unwrap(); let state_guard = app_handle.state::>(); let state = state_guard.lock().unwrap(); Ok(state.current_session.clone().unwrap()) }