diff --git a/client/main.py b/client/main.py index eb48167..7732871 100644 --- a/client/main.py +++ b/client/main.py @@ -31,7 +31,7 @@ def choice(choices): choice = int(input()) except: choice = 0 - print("Invalid choice") + print("Invalid choice, defaulting to 0") requests.post(api_url, json=choice); # Character outputs text to the user diff --git a/report.odt b/report.odt index adf9b53..a73a9ff 100644 Binary files a/report.odt and b/report.odt differ diff --git a/server/src/character.rs b/server/src/character.rs index adf6883..9fc4d13 100644 --- a/server/src/character.rs +++ b/server/src/character.rs @@ -63,15 +63,15 @@ pub fn character_parse(archive: &mut ZipArchive) { // Get the JSON file to a string let mut characters_file = archive.by_name("characters.json") - .map_err (|err| format!("Unable to read story file: {err}"))?; + .map_err (|err| format!("Unable to read character file: {err}"))?; let mut file_contents = String::new(); characters_file.read_to_string(&mut file_contents) - .map_err (|err| format!("Unable to read story file to string: {err}"))?; + .map_err (|err| format!("Unable to read character file to string: {err}"))?; // Serialise this to a HashMap let characters: HashMap = serde_json::from_str(&file_contents) - .expect("JSON was not well-formatted"); + .map_err (|err| format!("Invalid JSON in characters.json: {err}"))?; debug!("{characters:?}"); Ok(Arc::new(Mutex::new(characters))) } diff --git a/server/src/main.rs b/server/src/main.rs index 55a4f08..012db22 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,3 +1,9 @@ +mod parsing; +mod character; +mod config; +mod api; +mod traits; + use std:: { process::exit, @@ -24,11 +30,10 @@ use zip:: { ZipArchive, }; - -mod parsing; -mod character; -mod config; -mod api; +use crate:: +{ + traits::UnwrapOrExit, +}; #[tokio::main] async fn main() @@ -38,23 +43,23 @@ async fn main() // Tx and Rx allow you to pass data between threads let (tx,rx) = mpsc::channel(); // Unzip zip archive to get data for story - let file_name = args().nth(1) + let file_name = args().nth(1) // Get filename from arguments .unwrap_or_else (|| { error!("No filename specified"); - exit(5); + exit(10); }); - let file = File::open(format!("../stories/{file_name}")) + let file = File::open(format!("../stories/{file_name}")) // Get the file .unwrap_or_else (|err| { error!("Failed to open file: {err}"); - exit(2); + exit(11); }); - let mut archive = ZipArchive::new(file) + let mut archive = ZipArchive::new(file) // Open the archive .unwrap_or_else (|err| { error!("Failed to open archive: {err}"); - exit(3); + exit(12); }); // Setup the characters hashmap which will store each character in it as a Character struct let characters = match character::character_parse(&mut archive) @@ -67,7 +72,7 @@ async fn main() Err(error) => { error!("{error}"); - exit(3); + exit(13); }, }; // Initialise the data strcut that will be sent out during API GET requests @@ -99,14 +104,14 @@ async fn main() .unwrap_or_else (|err| { error!("Unable to read story file: {err}"); - exit(4); + exit(14); }); let mut file_contents = String::new(); story_file.read_to_string(&mut file_contents) .unwrap_or_else (|err| { error!("Unable to read story file to string: {err}"); - exit(5); + exit(14); }); // Tokenise story file let tokens: Vec<&str> = file_contents @@ -127,7 +132,7 @@ async fn main() Ok(()) => { info!("Program exited successfully"); - let mut data = data_to_send.lock().unwrap(); // TODO eh? + let mut data = data_to_send.lock().unwrap_or_exit("Data to send Mutex was poisoned",2); // TODO test data.action_type = String::from("end"); data.content = String::new(); data.character = String::new(); diff --git a/server/src/parsing.rs b/server/src/parsing.rs index 6cc2baf..b585c8e 100644 --- a/server/src/parsing.rs +++ b/server/src/parsing.rs @@ -12,6 +12,7 @@ use crate:: info, debug, warn, + UnwrapOrExit, }; mod strings; @@ -93,10 +94,10 @@ pub fn token_parse( "or" => { info!("OR command, jumping over"); - index += match strings::closing_char(&tokens[index..], '{','}') // TODO eh + index += match strings::closing_char(&tokens[index..], '{','}') { - Ok(index) => index, - Err(()) => return Err(String::from("Unable to find closing brace to OR command")), + Some(index) => index, + None => return Err(String::from("No closing brace")), }; continue }, @@ -130,12 +131,16 @@ fn choice_parse let mut choices: Vec = Vec::new(); let mut choice_indeces: Vec = Vec::new(); // Ensure the index is valid (the index is not beyond the vector) + // Get the initial choice let (choice_string, counter) = strings::extract_quoted(&tokens[sum_index..]) .ok_or_else(|| "No choice string".to_string())?; sum_index += counter; choices.push(choice_string); choice_indeces.push(sum_index+1); - sum_index += strings::closing_char(&tokens[sum_index..], '{','}').unwrap() + 1; //TODO eh + sum_index += strings::closing_char(&tokens[sum_index..], '{','}') + .ok_or_else(|| "No closing brace".to_string())? + 1; + // Find all the alternate choices labelled with OR + // Fill out the choices vector with all the choice strings while tokens[sum_index].to_lowercase() == "or" { let (choice_string, counter) = strings::extract_quoted(&tokens[sum_index+1..]) @@ -143,14 +148,17 @@ fn choice_parse sum_index += counter; choices.push(choice_string); choice_indeces.push(sum_index+2); - sum_index += strings::closing_char(&tokens[sum_index..], '{','}').unwrap() + 1; //TODO eh + sum_index += strings::closing_char(&tokens[sum_index..], '{','}') + .ok_or_else(|| "No closing brace".to_string())? + 1; } debug!("{choices:?}"); - let mut data = data_to_send.lock().unwrap(); + // Send the choices to the Client via the API + let mut data = data_to_send.lock().unwrap_or_exit("Data to send Mutex was poisoned",2); data.action_type = String::from("choice"); data.content = String::new(); data.character = String::new(); - data.choices = choices; //TODO + data.choices = choices; drop(data); + // Return the choice indeces Ok((sum_index + 1, choice_indeces)) } diff --git a/server/src/parsing/character_parse.rs b/server/src/parsing/character_parse.rs index 5067b89..68d5a94 100644 --- a/server/src/parsing/character_parse.rs +++ b/server/src/parsing/character_parse.rs @@ -4,6 +4,7 @@ use crate:: // Internal code character, api, + UnwrapOrExit, //Libs Mutex, Arc, @@ -43,7 +44,7 @@ pub fn character_parse { debug!("{output_string}"); sum_index += counter; - let mut data = data_to_send.lock().unwrap(); + let mut data = data_to_send.lock().unwrap_or_exit("Data to send Mutex was poisoned", 2); data.action_type = String::from("output"); data.content = output_string; data.character = character_name; @@ -68,12 +69,12 @@ pub fn character_parse None => return Err(("Unable to parse property to change character".to_string(),sum_index)), }; info!("CHANGE command with character {character_name} feature {feature}"); - let mut characters = characters.lock().expect("Data cannot be unlocked"); + let mut characters = characters.lock().unwrap_or_exit("Character Mutex was poisoned",3); if let Some(character) = characters.get_mut(&character_name) && character.set_field(feature, &output_string) .is_err() { warn!("Feature {feature} does not exist") } drop(characters); - let mut data = data_to_send.lock().unwrap(); // TODO eh? + let mut data = data_to_send.lock().unwrap_or_exit("Data to send Mutex was poisoned",2); // TODO eh? data.action_type = String::from("change"); data.content = String::new(); data.character = character_name; diff --git a/server/src/parsing/strings.rs b/server/src/parsing/strings.rs index 6545911..b9ed60f 100644 --- a/server/src/parsing/strings.rs +++ b/server/src/parsing/strings.rs @@ -1,5 +1,5 @@ pub fn closing_char(parts: &[&str], open: char, close: char) --> Result +-> Option { let mut indentation: usize = 0; let mut flag = false; // flag to mark you've passed open @@ -11,9 +11,9 @@ pub fn closing_char(parts: &[&str], open: char, close: char) flag = true; } if part.contains(close) { indentation -= 1; } - if indentation == 0 && flag { return Ok(index); } + if indentation == 0 && flag { return Some(index); } } - Err(()) + None } pub fn extract_quoted(parts: &[&str]) -> Option<(String, usize)> diff --git a/server/src/traits.rs b/server/src/traits.rs new file mode 100644 index 0000000..c1b42e0 --- /dev/null +++ b/server/src/traits.rs @@ -0,0 +1,23 @@ +use crate:: +{ + error, + exit, +}; + +pub trait UnwrapOrExit +{ + fn unwrap_or_exit(self, error_message: &str, error_code: i32) -> T; +} + +impl UnwrapOrExit for Result +{ + fn unwrap_or_exit(self, error_message: &str, error_code: i32) -> T + { + if let Ok(value) = self { value } + else + { + error!("{error_message}"); + exit(error_code); + } + } +} diff --git a/stories/test.zip b/stories/test.zip index a14af52..458becd 100644 Binary files a/stories/test.zip and b/stories/test.zip differ