use warp::Filter; use crate:: { // internal code character, UnwrapOrExit, // libraries json, HashMap, Arc, Mutex, VecDeque, config, mpsc::Sender, info, debug, warn, Serialize, Deserialize, }; #[derive(Debug, Deserialize, Serialize, Clone, Default)] pub struct DataToSend { pub action_type: String, pub content: String, pub character: String, pub choices: Vec, } // Async function that runs the api server in the background. // Waits for the client to load it, at which point it sends a 1 over // tx to allow the program executor to move onto the next bit of code pub async fn api_process ( happening_queue: Arc>>, characters: Arc>>, tx: Sender<(usize, String)>, ) { // This data must be passed through to the api route in order to be used let happening_queue_filter = warp::any().map(move || Arc::clone(&happening_queue)); let characters_filter = warp::any().map(move || Arc::clone(&characters)); let tx_filter1 = warp::any().map(move || tx.clone()); let tx_filter2 = tx_filter1.clone(); info!("Running server"); // The server route is loaded at address:port/happening let main = warp::path("happening") .and(warp::get()) .and(happening_queue_filter) // Perform this code on a GET request .map(|queue: Arc>>| { //debug!("GET: {state:?}"); let mut queue = queue.lock().unwrap_or_exit("Queue Mutex was poisoned", 2); let reply = queue.pop_front().unwrap_or_default(); drop(queue); warp::reply::json(&reply) // Send the reply data (data_to_send formatted as JSON) }).boxed(); let characters = warp::path("character") .and(warp::get()) .and(warp::path::param::()) .and(characters_filter) .map(|name: String, characters: Arc>>| { let reply = { let characters = match characters.lock() { Ok(data) => data, Err(poisoned) => { warn!("Character Mutex is poisoned"); poisoned.into_inner() }, }; characters.get(&name).cloned() }; let Some(reply) = reply else { warn!("Client requested character that does not exist"); return warp::reply::json(&json!({"reply": "invalid character"})); }; debug!("GET: name: {name}"); warp::reply::json(&reply) }).boxed(); let choice = warp::path("choice") .and(warp::post()) .and(warp::body::json()) .and(tx_filter1) .map(|index: usize, tx_handle: Sender<(usize,String)>| { debug!("Choice: {index}"); let _ = tx_handle.send((index,String::new())); let reply = "ack"; warp::reply::json(&reply) }).boxed(); let input = warp::path("input") .and(warp::post()) .and(warp::body::json()) .and(tx_filter2) .map(|input: String, tx_handle: Sender<(usize, String)>| { let _ = tx_handle.send((0,input)); let reply = "ack"; warp::reply::json(&reply) }).boxed(); let routes = main.or(characters).or(choice).or(input); // Start the server warp::serve(routes) .run(([127, 0, 0, 1],config::API_PORT)) .await; } // On fail, quit safely // If successful, return nothing pub fn modify_data // TODO rename ( happening_queue: &Arc>>, action_type: String, content: String, character: String, choices: Vec, ) { let mut queue = happening_queue.lock().unwrap_or_exit("Data to send Mutex was poisoned",2); let new_data = DataToSend { action_type, content, character, choices, }; queue.push_back(new_data); drop(queue); }