Improve error handling & feedback.

Change default path to minetest.exe on Windows.
This commit is contained in:
David 2018-12-05 14:32:43 -06:00
parent 169c8ac7e3
commit 89d6f908c4
2 changed files with 41 additions and 10 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
/target /target
**/*.rs.bk **/*.rs.bk
debug.txt

View File

@ -3,15 +3,15 @@ extern crate regex;
use mumble_link::*; use mumble_link::*;
use regex::Regex; use regex::Regex;
use std::io::{BufRead, BufReader}; use std::io::{BufRead, BufReader, Read, Write};
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
fn get_data(captures: &regex::Captures) -> Result<([f32; 3], char, char), String> { // Function to convert errors to error strings so we can return that as a result.
// Function to convert float parsing errors to error strings so we can return that as a result. fn errstr<T>(e: T) -> String where T: ToString {
fn errstr(e: std::num::ParseFloatError) -> String {
e.to_string() e.to_string()
} }
fn get_data(captures: &regex::Captures) -> Result<([f32; 3], char, char), String> {
// Get all the named captures. // Get all the named captures.
Ok(([captures["x"].parse().map_err(errstr)?, captures["y"].parse().map_err(errstr)?, captures["z"].parse().map_err(errstr)?,], Ok(([captures["x"].parse().map_err(errstr)?, captures["y"].parse().map_err(errstr)?, captures["z"].parse().map_err(errstr)?,],
captures["subject"].chars().next().ok_or("unable to get vec subject")?, captures["subject"].chars().next().ok_or("unable to get vec subject")?,
@ -19,12 +19,38 @@ fn get_data(captures: &regex::Captures) -> Result<([f32; 3], char, char), String
)) ))
} }
fn main() { fn main() {
match try_main() {
Ok(_) => {},
Err(err) => {
println!("Error: {}", err);
// print without a newline and flush to keep the cursor on the same line.
print!("Press ENTER to continue...");
std::io::stdout().flush().unwrap();
// Read a single byte and discard.
let _ = std::io::stdin().read(&mut [0u8]);
}
}
}
fn try_main() -> Result<(), String> {
println!("Starting...");
// Hook into Mumble using the very handy crate somebody made. // Hook into Mumble using the very handy crate somebody made.
let mut link = MumbleLink::new("Minetest", "Minetest positional audio using a mod and wrapper.").expect("Unable to link to Mumble. Is it running?"); let mut link = MumbleLink::new("Minetest", "Minetest positional audio using a mod and wrapper.")
.map_err(|e| { format!("Unable to connect to Mumble. Is it running? ({})", e) })?;
println!("Connected to Mumble successfully.");
// Default command to launch. // Default command to launch.
let mut minetest_command = "/usr/bin/minetest".to_owned(); let mut minetest_command = if cfg!(windows) {
"C:\\Program Files\\minetest\\bin\\minetest.exe"
} else {
"/usr/bin/minetest"
}.to_owned();
// Look for an argument containing "minetest" to replace default command. (But make sure it isn't this exe because that just leads to crazy recursion...) // Look for an argument containing "minetest" to replace default command. (But make sure it isn't this exe because that just leads to crazy recursion...)
for argument in std::env::args() { for argument in std::env::args() {
@ -33,9 +59,11 @@ fn main() {
} }
} }
println!("Launching Minetest at {}", minetest_command);
let mut child = Command::new(minetest_command) let mut child = Command::new(minetest_command)
.stderr(Stdio::piped()) // We need the output to be piped. For some reason Minetest lua's print function goes to stderr... .stderr(Stdio::piped()) // We need the output to be piped. For some reason Minetest lua's print function goes to stderr...
.spawn().unwrap(); // Spawn the process, panic if it fails. .spawn().map_err(|e| { format!("Unable to start Minetest executable: {}", e) })?; // Spawn the process, return an error if it fails.
// This regex parses lines like "p l [1.0 1.0 1.0]". // This regex parses lines like "p l [1.0 1.0 1.0]".
// the first letter (the subject) is either 'p' or 'c' denoting whether this is a player or camera vector. // the first letter (the subject) is either 'p' or 'c' denoting whether this is a player or camera vector.
@ -51,7 +79,7 @@ fn main() {
let mut camera = Position::default(); let mut camera = Position::default();
// Run as long as the child proccess is running. // Run as long as the child proccess is running.
while child.try_wait().unwrap().is_none() { while child.try_wait().map_err(errstr)?.is_none() {
// Get the output from the child process. // Get the output from the child process.
if let Some(ref mut child_output) = child.stderr { if let Some(ref mut child_output) = child.stderr {
// Using a BufReader allows us to go through all the lines in a loop. // Using a BufReader allows us to go through all the lines in a loop.
@ -106,4 +134,6 @@ fn main() {
} }
} }
} }
Ok(())
} }