creddy/src-tauri/src/http/mod.rs

106 lines
3.4 KiB
Rust
Raw Normal View History

2022-08-14 20:27:41 +00:00
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}");
2022-08-14 20:27:41 +00:00
}
}
}
}
// it doesn't really return a String, we just need to placate the compiler
async fn stall(stream: &mut TcpStream) -> Result<String, tokio::io::Error> {
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;
2022-08-14 20:27:41 +00:00
async fn get_creds(app_handle: &AppHandle) -> io::Result<String> {
{
let state_guard = app_handle.state::<Mutex<crate::AppState>>();
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
}
2022-08-14 20:27:41 +00:00
let (tx, rx) = oneshot::channel();
app_handle.once_global("request-response", |event| {
let response = event.payload().unwrap_or("").to_string();
tx.send(response).unwrap();
2022-08-14 20:27:41 +00:00
});
// 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::<Mutex<crate::AppState>>();
let state = state_guard.lock().unwrap();
Ok(state.current_session.clone().unwrap())
2022-08-14 20:27:41 +00:00
}