removed unwraps and added a method to Results called .unwrap_or_exit(error_message, error_code)
This tries to unwrap and if it can't then it outputs the error message with the error!() macro (log library) and exits with the error code. This is to be used instead of expect and is for fatal errors
This commit is contained in:
+1
-1
@@ -31,7 +31,7 @@ def choice(choices):
|
|||||||
choice = int(input())
|
choice = int(input())
|
||||||
except:
|
except:
|
||||||
choice = 0
|
choice = 0
|
||||||
print("Invalid choice")
|
print("Invalid choice, defaulting to 0")
|
||||||
requests.post(api_url, json=choice);
|
requests.post(api_url, json=choice);
|
||||||
|
|
||||||
# Character outputs text to the user
|
# Character outputs text to the user
|
||||||
|
|||||||
BIN
Binary file not shown.
@@ -63,15 +63,15 @@ pub fn character_parse(archive: &mut ZipArchive<File>)
|
|||||||
{
|
{
|
||||||
// Get the JSON file to a string
|
// Get the JSON file to a string
|
||||||
let mut characters_file = archive.by_name("characters.json")
|
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();
|
let mut file_contents = String::new();
|
||||||
characters_file.read_to_string(&mut file_contents)
|
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
|
// Serialise this to a HashMap
|
||||||
let characters: HashMap<String, Character> =
|
let characters: HashMap<String, Character> =
|
||||||
serde_json::from_str(&file_contents)
|
serde_json::from_str(&file_contents)
|
||||||
.expect("JSON was not well-formatted");
|
.map_err (|err| format!("Invalid JSON in characters.json: {err}"))?;
|
||||||
debug!("{characters:?}");
|
debug!("{characters:?}");
|
||||||
Ok(Arc::new(Mutex::new(characters)))
|
Ok(Arc::new(Mutex::new(characters)))
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-15
@@ -1,3 +1,9 @@
|
|||||||
|
mod parsing;
|
||||||
|
mod character;
|
||||||
|
mod config;
|
||||||
|
mod api;
|
||||||
|
mod traits;
|
||||||
|
|
||||||
use std::
|
use std::
|
||||||
{
|
{
|
||||||
process::exit,
|
process::exit,
|
||||||
@@ -24,11 +30,10 @@ use zip::
|
|||||||
{
|
{
|
||||||
ZipArchive,
|
ZipArchive,
|
||||||
};
|
};
|
||||||
|
use crate::
|
||||||
mod parsing;
|
{
|
||||||
mod character;
|
traits::UnwrapOrExit,
|
||||||
mod config;
|
};
|
||||||
mod api;
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main()
|
async fn main()
|
||||||
@@ -38,23 +43,23 @@ async fn main()
|
|||||||
// Tx and Rx allow you to pass data between threads
|
// Tx and Rx allow you to pass data between threads
|
||||||
let (tx,rx) = mpsc::channel();
|
let (tx,rx) = mpsc::channel();
|
||||||
// Unzip zip archive to get data for story
|
// 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
|
.unwrap_or_else
|
||||||
(|| {
|
(|| {
|
||||||
error!("No filename specified");
|
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
|
.unwrap_or_else
|
||||||
(|err| {
|
(|err| {
|
||||||
error!("Failed to open file: {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
|
.unwrap_or_else
|
||||||
(|err| {
|
(|err| {
|
||||||
error!("Failed to open archive: {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
|
// Setup the characters hashmap which will store each character in it as a Character struct
|
||||||
let characters = match character::character_parse(&mut archive)
|
let characters = match character::character_parse(&mut archive)
|
||||||
@@ -67,7 +72,7 @@ async fn main()
|
|||||||
Err(error) =>
|
Err(error) =>
|
||||||
{
|
{
|
||||||
error!("{error}");
|
error!("{error}");
|
||||||
exit(3);
|
exit(13);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
// Initialise the data strcut that will be sent out during API GET requests
|
// Initialise the data strcut that will be sent out during API GET requests
|
||||||
@@ -99,14 +104,14 @@ async fn main()
|
|||||||
.unwrap_or_else
|
.unwrap_or_else
|
||||||
(|err| {
|
(|err| {
|
||||||
error!("Unable to read story file: {err}");
|
error!("Unable to read story file: {err}");
|
||||||
exit(4);
|
exit(14);
|
||||||
});
|
});
|
||||||
let mut file_contents = String::new();
|
let mut file_contents = String::new();
|
||||||
story_file.read_to_string(&mut file_contents)
|
story_file.read_to_string(&mut file_contents)
|
||||||
.unwrap_or_else
|
.unwrap_or_else
|
||||||
(|err| {
|
(|err| {
|
||||||
error!("Unable to read story file to string: {err}");
|
error!("Unable to read story file to string: {err}");
|
||||||
exit(5);
|
exit(14);
|
||||||
});
|
});
|
||||||
// Tokenise story file
|
// Tokenise story file
|
||||||
let tokens: Vec<&str> = file_contents
|
let tokens: Vec<&str> = file_contents
|
||||||
@@ -127,7 +132,7 @@ async fn main()
|
|||||||
Ok(()) =>
|
Ok(()) =>
|
||||||
{
|
{
|
||||||
info!("Program exited successfully");
|
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.action_type = String::from("end");
|
||||||
data.content = String::new();
|
data.content = String::new();
|
||||||
data.character = String::new();
|
data.character = String::new();
|
||||||
|
|||||||
+15
-7
@@ -12,6 +12,7 @@ use crate::
|
|||||||
info,
|
info,
|
||||||
debug,
|
debug,
|
||||||
warn,
|
warn,
|
||||||
|
UnwrapOrExit,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod strings;
|
mod strings;
|
||||||
@@ -93,10 +94,10 @@ pub fn token_parse(
|
|||||||
"or" =>
|
"or" =>
|
||||||
{
|
{
|
||||||
info!("OR command, jumping over");
|
info!("OR command, jumping over");
|
||||||
index += match strings::closing_char(&tokens[index..], '{','}') // TODO eh
|
index += match strings::closing_char(&tokens[index..], '{','}')
|
||||||
{
|
{
|
||||||
Ok(index) => index,
|
Some(index) => index,
|
||||||
Err(()) => return Err(String::from("Unable to find closing brace to OR command")),
|
None => return Err(String::from("No closing brace")),
|
||||||
};
|
};
|
||||||
continue
|
continue
|
||||||
},
|
},
|
||||||
@@ -130,12 +131,16 @@ fn choice_parse
|
|||||||
let mut choices: Vec<String> = Vec::new();
|
let mut choices: Vec<String> = Vec::new();
|
||||||
let mut choice_indeces: Vec<usize> = Vec::new();
|
let mut choice_indeces: Vec<usize> = Vec::new();
|
||||||
// Ensure the index is valid (the index is not beyond the vector)
|
// 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..])
|
let (choice_string, counter) = strings::extract_quoted(&tokens[sum_index..])
|
||||||
.ok_or_else(|| "No choice string".to_string())?;
|
.ok_or_else(|| "No choice string".to_string())?;
|
||||||
sum_index += counter;
|
sum_index += counter;
|
||||||
choices.push(choice_string);
|
choices.push(choice_string);
|
||||||
choice_indeces.push(sum_index+1);
|
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"
|
while tokens[sum_index].to_lowercase() == "or"
|
||||||
{
|
{
|
||||||
let (choice_string, counter) = strings::extract_quoted(&tokens[sum_index+1..])
|
let (choice_string, counter) = strings::extract_quoted(&tokens[sum_index+1..])
|
||||||
@@ -143,14 +148,17 @@ fn choice_parse
|
|||||||
sum_index += counter;
|
sum_index += counter;
|
||||||
choices.push(choice_string);
|
choices.push(choice_string);
|
||||||
choice_indeces.push(sum_index+2);
|
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:?}");
|
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.action_type = String::from("choice");
|
||||||
data.content = String::new();
|
data.content = String::new();
|
||||||
data.character = String::new();
|
data.character = String::new();
|
||||||
data.choices = choices; //TODO
|
data.choices = choices;
|
||||||
drop(data);
|
drop(data);
|
||||||
|
// Return the choice indeces
|
||||||
Ok((sum_index + 1, choice_indeces))
|
Ok((sum_index + 1, choice_indeces))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use crate::
|
|||||||
// Internal code
|
// Internal code
|
||||||
character,
|
character,
|
||||||
api,
|
api,
|
||||||
|
UnwrapOrExit,
|
||||||
//Libs
|
//Libs
|
||||||
Mutex,
|
Mutex,
|
||||||
Arc,
|
Arc,
|
||||||
@@ -43,7 +44,7 @@ pub fn character_parse
|
|||||||
{
|
{
|
||||||
debug!("{output_string}");
|
debug!("{output_string}");
|
||||||
sum_index += counter;
|
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.action_type = String::from("output");
|
||||||
data.content = output_string;
|
data.content = output_string;
|
||||||
data.character = character_name;
|
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)),
|
None => return Err(("Unable to parse property to change character".to_string(),sum_index)),
|
||||||
};
|
};
|
||||||
info!("CHANGE command with character {character_name} feature {feature}");
|
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)
|
if let Some(character) = characters.get_mut(&character_name)
|
||||||
&& character.set_field(feature, &output_string)
|
&& character.set_field(feature, &output_string)
|
||||||
.is_err() { warn!("Feature {feature} does not exist") }
|
.is_err() { warn!("Feature {feature} does not exist") }
|
||||||
drop(characters);
|
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.action_type = String::from("change");
|
||||||
data.content = String::new();
|
data.content = String::new();
|
||||||
data.character = character_name;
|
data.character = character_name;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
pub fn closing_char(parts: &[&str], open: char, close: char)
|
pub fn closing_char(parts: &[&str], open: char, close: char)
|
||||||
-> Result<usize,()>
|
-> Option<usize>
|
||||||
{
|
{
|
||||||
let mut indentation: usize = 0;
|
let mut indentation: usize = 0;
|
||||||
let mut flag = false; // flag to mark you've passed open
|
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;
|
flag = true;
|
||||||
}
|
}
|
||||||
if part.contains(close) { indentation -= 1; }
|
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])
|
pub fn extract_quoted(parts: &[&str])
|
||||||
-> Option<(String, usize)>
|
-> Option<(String, usize)>
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
use crate::
|
||||||
|
{
|
||||||
|
error,
|
||||||
|
exit,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait UnwrapOrExit<T>
|
||||||
|
{
|
||||||
|
fn unwrap_or_exit(self, error_message: &str, error_code: i32) -> T;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E> UnwrapOrExit<T> for Result<T, E>
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
Reference in New Issue
Block a user