diff --git a/.~lock.report.odt# b/.~lock.report.odt# index 1f82241..5578e24 100644 --- a/.~lock.report.odt# +++ b/.~lock.report.odt# @@ -1 +1 @@ -,deadvey,linux-pc,07.04.2026 00:08,file:///home/deadvey/.config/libreoffice/4; \ No newline at end of file +,deadvey,linux-pc,30.04.2026 12:49,file:///home/deadvey/.config/libreoffice/4; \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 58803f2..b5899fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -248,6 +248,7 @@ dependencies = [ "env_logger", "log", "serde", + "serde_json", "tokio", "warp", ] diff --git a/Cargo.toml b/Cargo.toml index 898fe0f..755a3b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,5 +7,6 @@ edition = "2024" env_logger = "0.11.10" log = "0.4.29" serde = { version = "1.0.228", features = ["derive"] } +serde_json = "1.0.149" tokio = { version = "1.51.0", features = ["rt-multi-thread","macros"] } warp = { version = "0.4.2", features = ["server"] } diff --git a/report.odt b/report.odt index 15a4491..ea7d361 100644 Binary files a/report.odt and b/report.odt differ diff --git a/src/.main.rs.swp b/src/.api.rs.swp similarity index 77% rename from src/.main.rs.swp rename to src/.api.rs.swp index 049d79c..3d6394f 100644 Binary files a/src/.main.rs.swp and b/src/.api.rs.swp differ diff --git a/src/.character.rs.swp b/src/.character.rs.swp new file mode 100644 index 0000000..7741b8f Binary files /dev/null and b/src/.character.rs.swp differ diff --git a/src/api.rs b/src/api.rs index 2eb75eb..5d2e1cf 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,14 +1,18 @@ -use serde::{Deserialize, Serialize}; use warp::Filter; use crate:: { + // internal code + character, + // libraries + HashMap, Arc, Mutex, config, mpsc::Sender, info, - warn, debug, + Serialize, + Deserialize, }; #[derive(Debug, Deserialize, Serialize, Clone)] @@ -21,29 +25,48 @@ pub struct DataToSend { // 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(data_to_send: Arc>, tx: Sender) +pub async fn api_process +( + data_to_send: Arc>, + characters: Arc>>, + tx: Sender, +) { // This data must be passed through to the api route in order to be used let data_filter = warp::any().map(move || Arc::clone(&data_to_send)); + let characters_filter = warp::any().map(move || Arc::clone(&characters)); let tx_filter = warp::any().map(move || tx.clone()); - debug!("Running server"); + info!("Running server"); // The server route is loaded at address:port/happening - let route = warp::path("happening") + let main = warp::path("happening") .and(warp::get()) .and(data_filter) .and(tx_filter) // Perform this code on a GET request - .map(|state: Arc>, tx_handle: Sender| { + .map(|state: Arc>, tx_handle: Sender| + { info!("GET: {:?}", state); let reply = state.as_ref(); let _ = tx_handle.send(1); 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 map = characters.lock().unwrap(); // TODO remove unwrap + let reply = map.get(&name).unwrap(); + debug!("GET: name: {}, data: {:?}", name, reply); + warp::reply::json(&reply) + }).boxed(); + let routes = main.or(characters); // Start the server - warp::serve(route) + warp::serve(routes) .run(([127, 0, 0, 1],config::API_PORT)) .await; } diff --git a/src/character.rs b/src/character.rs index 50c2517..dc832a2 100644 --- a/src/character.rs +++ b/src/character.rs @@ -1,6 +1,33 @@ +use crate::{ + HashMap, + fs, + debug, + Deserialize, + Serialize, + Mutex, + Arc, +}; +#[derive(Debug, Deserialize, Serialize)] pub struct Character { name: String, + gender: String, + eye_color: String, + pronoun_subject: String, + pronoun_object: String, + pronoun_deppos: String, + pronoun_indpos: String, + pronoun_reflex: String, + animation: String, + head: String, + hair: String, + torso: String, + arm: String, + leg: String, + hair_color: String, + top_clothing: String, + bottom_clothing: String, + shoes: String, } impl Character { @@ -9,6 +36,38 @@ impl Character Character { name: new_name, + gender: "".to_string(), + eye_color: "".to_string(), + pronoun_subject: "".to_string(), + pronoun_object: "".to_string(), + pronoun_deppos: "".to_string(), + pronoun_indpos: "".to_string(), + pronoun_reflex: "".to_string(), + animation: "".to_string(), + head: "".to_string(), + hair: "".to_string(), + torso: "".to_string(), + arm: "".to_string(), + leg: "".to_string(), + hair_color: "".to_string(), + top_clothing: "".to_string(), + bottom_clothing: "".to_string(), + shoes: "".to_string(), } } } + +pub async fn character_parse() +-> Result>>,String> +{ + // Get the JSON file to a string + let file_contents: String = fs::read_to_string("stories/characters.json") + .unwrap_or_else(|err| { return err.to_string() }); + + // Serialise this to a HashMap + let characters: HashMap = + serde_json::from_str(&file_contents) + .expect("JSON was not well-formatted"); + debug!("{:?}",characters); + Ok(Arc::new(Mutex::new(characters))) +} diff --git a/src/main.rs b/src/main.rs index 3260184..4cd9999 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,8 @@ use log:: warn, debug, }; +use serde_json::from_str; +use serde::{Deserialize, Serialize}; mod parsing; mod character; @@ -30,24 +32,33 @@ async fn main() content: "".to_string(), character: "".to_string(), })); + // Setup the characters hashmap which will store each character in it as a Character struct + let mut characters: Arc>> = Default::default(); + match character::character_parse().await + { + Ok(result) => characters = result, //let mut characters = character, + Err(error) => + { + eprintln!("{}",error); + std::process::exit(3); + }, + }; // setup the api stuff // // Make clones of the data Arc for the two processes let data_clone1 = Arc::clone(&data_to_send); + let characters_clone1 = Arc::clone(&characters); let tx_clone = tx.clone(); // Spawn a thread for warp api server tokio::spawn( async move { - api::api_process(data_clone1, tx_clone).await; + api::api_process(data_clone1, characters_clone1, tx_clone).await; }); // setup the parsing stuff // - // Setup the characters hashmap which will store each character in it as a Character struct - let mut characters = HashMap::::new(); - // Read the file and split it into tokens let file_contents: String = fs::read_to_string("stories/story.ha") // TODO make this a command line argument .unwrap_or_else(|err| @@ -58,10 +69,15 @@ async fn main() let tokens: Vec<&str> = file_contents .split_whitespace() .collect(); + if ! tokens.contains(&"END") + { + warn!("No END statement, story may exit unexpectedly"); + } let data_clone2 = Arc::clone(&data_to_send); + let characters_clone2 = Arc::clone(&characters); // Run the parsing process - match parsing::token_parse(&tokens, &mut characters, data_clone2, &rx).await + match parsing::token_parse(&tokens, characters_clone2, data_clone2, &rx).await { // Exit with error or success Ok(()) => diff --git a/src/parsing.rs b/src/parsing.rs index 8c8f3a8..5647891 100644 --- a/src/parsing.rs +++ b/src/parsing.rs @@ -11,7 +11,6 @@ use crate:: Arc, Mutex, info, - warn, debug, }; @@ -20,7 +19,7 @@ use crate:: // Returns success or an error string pub async fn token_parse( tokens: &Vec<&str>, - mut characters: &mut HashMap::, + mut characters: Arc>>, data_to_send: Arc>, rx: &Receiver, ) -> Result<(),String> @@ -43,15 +42,9 @@ pub async fn token_parse( if token.starts_with('@') { let character_name: String = token.chars().skip(1).collect(); - // If the character doesn't exist, then create it - if ! characters.contains_key(&character_name) - { - let new_character = character::Character::new(character_name.clone()); - characters.insert(character_name.clone(),new_character); - } info!("Doing something with a character: {}", character_name); // The index is incremented to after the character's instructions - index += match character_parse(index+1, &tokens, character_name, &mut characters, &data_to_send, &rx).await + index += match character_parse(index+1, &tokens, character_name, &characters, &data_to_send, &rx).await { Ok(increment) => increment, Err(error) => return Err(error), @@ -73,7 +66,7 @@ async fn character_parse index: usize, tokens: &Vec<&str>, character_name: String, - characters: &mut HashMap::, + characters: &Arc>>, data_to_send: &Arc>, rx: &Receiver, ) -> Result diff --git a/stories/characters.json b/stories/characters.json new file mode 100644 index 0000000..a5ec8d4 --- /dev/null +++ b/stories/characters.json @@ -0,0 +1,23 @@ +{ + "tim": { + "name": "Timothy Sharpshooter", + "gender": "", + "skin_color": "", + "eye_color": "", + "pronoun_subject": "", + "pronoun_object": "", + "pronoun_deppos": "", + "pronoun_indpos": "", + "pronoun_reflex": "", + "animation": "", + "head": "", + "hair": "", + "torso": "", + "arm": "", + "leg": "", + "hair_color": "", + "top_clothing": "", + "bottom_clothing": "", + "shoes": "" + } +}