Changed the data_to_send to be a stack so many lines of code can
be pre-processed before the user interacts. When the /happening api is called it just dequeues the front item
This commit is contained in:
+18
-16
@@ -1,6 +1,12 @@
|
||||
import requests
|
||||
import os
|
||||
import time
|
||||
import sys
|
||||
debug = False
|
||||
try:
|
||||
if sys.argv[1] == "debug": debug = True
|
||||
except:
|
||||
debug = False
|
||||
|
||||
# Loop and get new api
|
||||
def main():
|
||||
@@ -9,22 +15,18 @@ def main():
|
||||
while True:
|
||||
try:
|
||||
response = api_get()
|
||||
if response["id"] != id:
|
||||
id = response["id"]
|
||||
print(response)
|
||||
match response["action_type"]:
|
||||
case "output":
|
||||
character = get_character(response["character"])
|
||||
output(character, response["content"])
|
||||
case "choice":
|
||||
user_choice = choice(response["choices"])
|
||||
time.sleep(0.5)
|
||||
continue
|
||||
case "end":
|
||||
print("Exitting successfully")
|
||||
os._exit(0)
|
||||
else:
|
||||
continue
|
||||
if debug: print(response)
|
||||
match response["action_type"]:
|
||||
case "output":
|
||||
character = get_character(response["character"])
|
||||
output(character, response["content"])
|
||||
case "choice":
|
||||
user_choice = choice(response["choices"])
|
||||
time.sleep(0.5)
|
||||
continue
|
||||
case "end":
|
||||
print("Exitting successfully")
|
||||
os._exit(0)
|
||||
except:
|
||||
print("Server not up or cannot be reached")
|
||||
input() # Enter to go to next loop (testing)
|
||||
|
||||
+24
-22
@@ -9,6 +9,7 @@ use crate::
|
||||
HashMap,
|
||||
Arc,
|
||||
Mutex,
|
||||
VecDeque,
|
||||
config,
|
||||
mpsc::Sender,
|
||||
info,
|
||||
@@ -18,9 +19,8 @@ use crate::
|
||||
Deserialize,
|
||||
};
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, Default)]
|
||||
pub struct DataToSend {
|
||||
pub id: u32,
|
||||
pub action_type: String,
|
||||
pub content: String,
|
||||
pub character: String,
|
||||
@@ -32,13 +32,13 @@ pub struct DataToSend {
|
||||
// tx to allow the program executor to move onto the next bit of code
|
||||
pub async fn api_process
|
||||
(
|
||||
data_to_send: Arc<Mutex<DataToSend>>,
|
||||
happening_queue: Arc<Mutex<VecDeque<DataToSend>>>,
|
||||
characters: Arc<Mutex<HashMap::<String,character::Character>>>,
|
||||
tx: Sender<(bool, usize, String)>,
|
||||
tx: Sender<(usize, String)>,
|
||||
)
|
||||
{
|
||||
// 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 happening_queue_filter = warp::any().map(move || Arc::clone(&happening_queue));
|
||||
let characters_filter = warp::any().map(move || Arc::clone(&characters));
|
||||
let tx_filter = warp::any().map(move || tx.clone());
|
||||
let tx_filter2 = tx_filter.clone();
|
||||
@@ -49,14 +49,14 @@ pub async fn api_process
|
||||
// The server route is loaded at address:port/happening
|
||||
let main = warp::path("happening")
|
||||
.and(warp::get())
|
||||
.and(data_filter)
|
||||
.and(happening_queue_filter)
|
||||
.and(tx_filter)
|
||||
// Perform this code on a GET request
|
||||
.map(|state: Arc<Mutex<DataToSend>>, tx_handle: Sender<(bool,usize,String)>|
|
||||
.map(|queue: Arc<Mutex<VecDeque<DataToSend>>>, tx_handle: Sender<(usize,String)>|
|
||||
{
|
||||
//debug!("GET: {state:?}");
|
||||
let reply = state.as_ref();
|
||||
let _ = tx_handle.send((true,0,String::new()));
|
||||
let mut queue = queue.lock().unwrap();
|
||||
let reply = queue.pop_front().unwrap_or_default();
|
||||
warp::reply::json(&reply) // Send the reply data (data_to_send formatted as JSON)
|
||||
}).boxed();
|
||||
let characters = warp::path("character")
|
||||
@@ -91,9 +91,9 @@ pub async fn api_process
|
||||
.and(warp::post())
|
||||
.and(warp::body::json())
|
||||
.and(tx_filter2)
|
||||
.map(|index: usize, tx_handle: Sender<(bool,usize,String)>| {
|
||||
.map(|index: usize, tx_handle: Sender<(usize,String)>| {
|
||||
debug!("Choice: {index}");
|
||||
let _ = tx_handle.send((true,index,String::new()));
|
||||
let _ = tx_handle.send((index,String::new()));
|
||||
let reply = "ack";
|
||||
warp::reply::json(&reply)
|
||||
}).boxed();
|
||||
@@ -101,9 +101,9 @@ pub async fn api_process
|
||||
.and(warp::post())
|
||||
.and(warp::body::json())
|
||||
.and(tx_filter3)
|
||||
.map(|input: String, tx_handle: Sender<(bool, usize, String)>|
|
||||
.map(|input: String, tx_handle: Sender<(usize, String)>|
|
||||
{
|
||||
let _ = tx_handle.send((true,0,input));
|
||||
let _ = tx_handle.send((0,input));
|
||||
let reply = "ack";
|
||||
warp::reply::json(&reply)
|
||||
}).boxed();
|
||||
@@ -117,20 +117,22 @@ pub async fn api_process
|
||||
|
||||
// On fail, quit safely
|
||||
// If successful, return nothing
|
||||
pub fn modify_data
|
||||
pub fn modify_data // TODO rename
|
||||
(
|
||||
data_to_send: &Arc<Mutex<DataToSend>>,
|
||||
happening_queue: &Arc<Mutex<VecDeque<DataToSend>>>,
|
||||
action_type: String,
|
||||
content: String,
|
||||
character_name: String,
|
||||
choices: Vec<String>,
|
||||
)
|
||||
{
|
||||
let mut data = data_to_send.lock().unwrap_or_exit("Data to send Mutex was poisoned",2);
|
||||
data.id += 1;
|
||||
data.action_type = action_type;
|
||||
data.content = content;
|
||||
data.character = character_name;
|
||||
data.choices = choices;
|
||||
drop(data);
|
||||
let mut queue = happening_queue.lock().unwrap_or_exit("Data to send Mutex was poisoned",2);
|
||||
let new_data = DataToSend {
|
||||
action_type: action_type,
|
||||
content: content,
|
||||
character: character_name,
|
||||
choices: choices,
|
||||
};
|
||||
queue.push_back(new_data);
|
||||
drop(queue);
|
||||
}
|
||||
|
||||
+19
-14
@@ -11,7 +11,11 @@ use std::
|
||||
env::args,
|
||||
fs::File,
|
||||
io::Read,
|
||||
collections::HashMap,
|
||||
collections::
|
||||
{
|
||||
HashMap,
|
||||
VecDeque,
|
||||
},
|
||||
sync::{Arc, Mutex, mpsc},
|
||||
};
|
||||
use log::
|
||||
@@ -70,25 +74,26 @@ async fn main()
|
||||
},
|
||||
};
|
||||
// Initialise the data strcut that will be sent out during API GET requests
|
||||
let data_to_send = Arc::new(Mutex::new(api::DataToSend
|
||||
{
|
||||
id: 0,
|
||||
action_type: "begin".to_owned(),
|
||||
content: String::new(), // TODO send title and description
|
||||
character: String::new(),
|
||||
choices: vec![],
|
||||
}));
|
||||
let happening_stack = Arc::new(Mutex::new(
|
||||
VecDeque::from([api::DataToSend{
|
||||
action_type: "begin".to_owned(),
|
||||
content: String::new(), // TODO send title and description
|
||||
character: String::new(),
|
||||
choices: vec![],
|
||||
}])
|
||||
));
|
||||
|
||||
// setup the api stuff //
|
||||
|
||||
// Make clones of the data Arc for the two processes
|
||||
let data_clone1 = Arc::clone(&data_to_send);
|
||||
//let data_clone1 = Arc::clone(&data_to_send);
|
||||
let happening_stack1 = Arc::clone(&happening_stack);
|
||||
let characters_clone1 = Arc::clone(&characters);
|
||||
let tx_clone = tx;
|
||||
// Spawn a thread for warp api server
|
||||
tokio::spawn(
|
||||
async move {
|
||||
api::api_process(data_clone1, characters_clone1, tx_clone).await;
|
||||
api::api_process(happening_stack1, characters_clone1, tx_clone).await;
|
||||
});
|
||||
|
||||
// setup the parsing stuff //
|
||||
@@ -106,16 +111,16 @@ async fn main()
|
||||
let (tokens, labels) = tokenise::tokenise(&file_contents)
|
||||
.unwrap_or_exit("Unable to tokenise data", 15);
|
||||
debug!("{tokens:?}\n{labels:?}");
|
||||
let data_clone2 = Arc::clone(&data_to_send);
|
||||
let characters_clone2 = Arc::clone(&characters);
|
||||
let happening_stack2 = Arc::clone(&happening_stack);
|
||||
// Run the parsing process for the DSL
|
||||
info!("DSL parsing begun");
|
||||
match parsing::token_parse(&tokens, &labels, &characters_clone2, &data_clone2, &rx)
|
||||
match parsing::token_parse(&tokens, &labels, &characters_clone2, &happening_stack2, &rx)
|
||||
{
|
||||
// Exit with error or success
|
||||
Ok(()) =>
|
||||
{
|
||||
api::modify_data(&data_to_send, "end".to_string(), String::new(), String::new(), vec![]);
|
||||
api::modify_data(&happening_stack, "end".to_string(), String::new(), String::new(), vec![]);
|
||||
// TODO fix quitting instantly
|
||||
let _ = rx.recv(); // Wait for the client to respond
|
||||
info!("Program exited successfully");
|
||||
|
||||
+11
-92
@@ -10,12 +10,14 @@ use crate::
|
||||
mpsc::Receiver,
|
||||
Arc,
|
||||
Mutex,
|
||||
VecDeque,
|
||||
info,
|
||||
debug,
|
||||
warn,
|
||||
};
|
||||
|
||||
mod character_parse;
|
||||
mod keyword_parse;
|
||||
|
||||
// Parse the tokens in a file
|
||||
// Returns success or an error string
|
||||
@@ -23,16 +25,11 @@ pub fn token_parse(
|
||||
tokens: &[tokenise::Token],
|
||||
labels: &HashMap<String,usize>,
|
||||
characters: &Arc<Mutex<HashMap::<String, character::Character>>>,
|
||||
data_to_send: &Arc<Mutex<api::DataToSend>>,
|
||||
rx: &Receiver<(bool,usize,String)>,
|
||||
happening_queue: &Arc<Mutex<VecDeque<api::DataToSend>>>,
|
||||
rx: &Receiver<(usize,String)>,
|
||||
) -> Result<(),String>
|
||||
{
|
||||
let mut index: usize = 0;
|
||||
if rx.recv().is_err()
|
||||
{
|
||||
warn!("Some issue with api");
|
||||
// TODO eh?
|
||||
}
|
||||
info!("Client has connected");
|
||||
// Run an infinite loop
|
||||
'parse_loop: loop
|
||||
@@ -41,7 +38,12 @@ pub fn token_parse(
|
||||
// Get the next token
|
||||
let token: String = match tokens.get(index)
|
||||
{
|
||||
Some(tokenise::Token::Keyword(s)) => s.clone(),
|
||||
Some(tokenise::Token::Keyword(token)) =>
|
||||
{
|
||||
if token.to_lowercase().as_str() == "end" { return Ok(()); };
|
||||
index = keyword_parse::keyword_parse(tokens, token.to_string(), index, characters, happening_queue, labels, rx).unwrap();
|
||||
continue 'parse_loop;
|
||||
},
|
||||
// Ignore closing braces and jump over opening brace blocks
|
||||
Some(tokenise::Token::Bracket((bracket,new_index))) =>
|
||||
{
|
||||
@@ -56,7 +58,7 @@ pub fn token_parse(
|
||||
// Handle a character
|
||||
Some(tokenise::Token::Character(character_name)) => // TODO add support for narrator
|
||||
{
|
||||
index = match character_parse::character_parse(index+1,tokens,character_name.clone(),characters,data_to_send)
|
||||
index = match character_parse::character_parse(index+1,tokens,character_name.clone(),characters,happening_queue)
|
||||
{
|
||||
Ok(increment) => increment,
|
||||
Err((err,increment)) =>
|
||||
@@ -65,7 +67,6 @@ pub fn token_parse(
|
||||
increment
|
||||
},
|
||||
};
|
||||
if rx.recv().is_err() { warn!("Some issue with api"); }
|
||||
continue 'parse_loop
|
||||
}
|
||||
Some(_) =>
|
||||
@@ -78,88 +79,6 @@ pub fn token_parse(
|
||||
};
|
||||
debug!("{index}: {token}");
|
||||
// The instructions are related to characters
|
||||
match token.to_lowercase().as_str()
|
||||
{
|
||||
"end" =>
|
||||
{
|
||||
info!("END command, exiting");
|
||||
return Ok(()) // quit successfully
|
||||
},
|
||||
"choice" =>
|
||||
{
|
||||
let choice_indeces = choice_parse(tokens, index, data_to_send)?;
|
||||
debug!("{choice_indeces:?}");
|
||||
if rx.recv().is_err() { warn!("Error sending choices to client"); }
|
||||
let choice = match rx.recv()
|
||||
{
|
||||
Ok((_,choice,_)) => choice_indeces[choice],
|
||||
Err(err) =>
|
||||
{
|
||||
warn!("Error receiving choice from client, defaulting to choice 0 {err}");
|
||||
0
|
||||
}
|
||||
};
|
||||
index = choice;
|
||||
continue 'parse_loop
|
||||
},
|
||||
"or" =>
|
||||
{
|
||||
info!("OR command, jumping over");
|
||||
index += 2;
|
||||
let new_index = tokenise::get_closing_index(tokens, index)?;
|
||||
index = new_index;
|
||||
continue 'parse_loop
|
||||
},
|
||||
// Jump to a particular index based on a label eg GOTO character_check
|
||||
"goto" =>
|
||||
{
|
||||
index += 1;
|
||||
let label = tokenise::get_keyword_token(tokens, index)?;
|
||||
index = if let Some(label_index) = labels.get(&label) { *label_index }
|
||||
else
|
||||
{
|
||||
warn!("Label {label} does not exist");
|
||||
index + 1
|
||||
};
|
||||
debug!("Jumping to {index}");
|
||||
continue 'parse_loop
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
warn!("Invalid command: {token}");
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
if rx.recv().is_err() { warn!("Some issue with api"); }
|
||||
}
|
||||
}
|
||||
|
||||
fn choice_parse(tokens: &[tokenise::Token], mut index: usize, data_to_send: &Arc<Mutex<api::DataToSend>>,)
|
||||
-> Result<Vec<usize>, String>
|
||||
{
|
||||
let mut next_token: String = "or".to_string();
|
||||
let mut choices: Vec<String> = Vec::new();
|
||||
let mut choice_indeces: Vec<usize> = Vec::new();
|
||||
while next_token == "or"
|
||||
{
|
||||
index += 1;
|
||||
choices.push
|
||||
(
|
||||
tokenise::get_string_token(tokens, index)?
|
||||
);
|
||||
index += 1;
|
||||
choice_indeces.push(index+1);
|
||||
index = match tokenise::get_closing_index(tokens,index)
|
||||
{
|
||||
Ok(new_index) => new_index + 1,
|
||||
Err(_) => break,
|
||||
};
|
||||
next_token = match tokenise::get_keyword_token(tokens, index)
|
||||
{
|
||||
Ok(string) => string,
|
||||
Err(_) => break,
|
||||
}
|
||||
};
|
||||
api::modify_data(data_to_send, "choice".to_string(), String::new(), String::new(), choices);
|
||||
Ok(choice_indeces)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use crate::
|
||||
Mutex,
|
||||
Arc,
|
||||
HashMap,
|
||||
VecDeque,
|
||||
info,
|
||||
warn,
|
||||
debug,
|
||||
@@ -23,7 +24,7 @@ pub fn character_parse
|
||||
tokens: &[tokenise::Token],
|
||||
character_name: String,
|
||||
characters: &Arc<Mutex<HashMap::<String, character::Character>>>,
|
||||
data_to_send: &Arc<Mutex<api::DataToSend>>,
|
||||
happening_queue: &Arc<Mutex<VecDeque<api::DataToSend>>>,
|
||||
) -> Result<usize,(String,usize)>
|
||||
{
|
||||
let mut sum_index: usize = index;
|
||||
@@ -47,7 +48,7 @@ pub fn character_parse
|
||||
let output = tokenise::get_string_token(tokens, sum_index)
|
||||
.map_err(|err| (err, index))?;
|
||||
debug!("Saying {output}");
|
||||
api::modify_data(data_to_send, "output".to_string(), output, character_name, vec![]);
|
||||
api::modify_data(happening_queue, "output".to_string(), output, character_name, vec![]);
|
||||
},
|
||||
// Change the property of the selected character eg @tim CHANGE name "Bill Buffins"
|
||||
// will change the character with ID tim to "Bill Buffins"; a character's ID cannot change
|
||||
@@ -65,7 +66,7 @@ pub fn character_parse
|
||||
&& character.set_field(&feature, &string)
|
||||
.is_err() { warn!("Feature {feature} does not exist") }
|
||||
drop(characters);
|
||||
api::modify_data(data_to_send, "change".to_string(), String::new(), character_name, vec![]);
|
||||
api::modify_data(happening_queue, "change".to_string(), String::new(), character_name, vec![]);
|
||||
},
|
||||
// These two are mainly just actions performed by the frontend client, so just tell the client to move/animate
|
||||
// the character and not much other processing needed on the serverside
|
||||
@@ -74,7 +75,7 @@ pub fn character_parse
|
||||
sum_index += 1;
|
||||
let content = tokenise::get_keyword_token(tokens, sum_index)
|
||||
.map_err(|err| (err, index))?;
|
||||
api::modify_data(data_to_send, keyword.to_lowercase(), content, character_name, vec![]);
|
||||
api::modify_data(happening_queue, keyword.to_lowercase(), content, character_name, vec![]);
|
||||
},
|
||||
// Catch all condition, if the instruction is unrecognised as a
|
||||
// character command
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
use crate::
|
||||
{
|
||||
tokenise,
|
||||
character,
|
||||
api,
|
||||
|
||||
HashMap,
|
||||
Arc,
|
||||
Mutex,
|
||||
VecDeque,
|
||||
warn,
|
||||
debug,
|
||||
info,
|
||||
mpsc::Receiver,
|
||||
};
|
||||
|
||||
pub fn keyword_parse(
|
||||
tokens: &[tokenise::Token],
|
||||
token: String,
|
||||
mut index: usize,
|
||||
characters: &Arc<Mutex<HashMap::<String, character::Character>>>,
|
||||
happening_queue: &Arc<Mutex<VecDeque<api::DataToSend>>>,
|
||||
labels: &HashMap<String, usize>,
|
||||
rx: &Receiver<(usize,String)>,
|
||||
)
|
||||
-> Result<usize, String>
|
||||
{
|
||||
|
||||
match token.to_lowercase().as_str()
|
||||
{
|
||||
"choice" =>
|
||||
{
|
||||
let choice_indeces = choice_parse(tokens, index, happening_queue)?;
|
||||
debug!("{choice_indeces:?}");
|
||||
let choice = match rx.recv()
|
||||
{
|
||||
Ok((choice,_)) => choice_indeces[choice],
|
||||
Err(err) =>
|
||||
{
|
||||
warn!("Error receiving choice from client, defaulting to choice 0 {err}");
|
||||
0
|
||||
}
|
||||
};
|
||||
index = choice;
|
||||
},
|
||||
"or" =>
|
||||
{
|
||||
info!("OR command, jumping over");
|
||||
index += 2;
|
||||
let new_index = tokenise::get_closing_index(tokens, index)?;
|
||||
index = new_index;
|
||||
},
|
||||
// Jump to a particular index based on a label eg GOTO character_check
|
||||
"goto" =>
|
||||
{
|
||||
index += 1;
|
||||
let label = tokenise::get_keyword_token(tokens, index)?;
|
||||
index = if let Some(label_index) = labels.get(&label) { *label_index }
|
||||
else
|
||||
{
|
||||
warn!("Label {label} does not exist");
|
||||
index + 1
|
||||
};
|
||||
debug!("Jumping to {index}");
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
warn!("Invalid command: {token}");
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
Ok(index)
|
||||
}
|
||||
|
||||
fn choice_parse(tokens: &[tokenise::Token], mut index: usize, happening_queue: &Arc<Mutex<VecDeque<api::DataToSend>>>,)
|
||||
-> Result<Vec<usize>, String>
|
||||
{
|
||||
let mut next_token: String = "or".to_string();
|
||||
let mut choices: Vec<String> = Vec::new();
|
||||
let mut choice_indeces: Vec<usize> = Vec::new();
|
||||
while next_token == "or"
|
||||
{
|
||||
index += 1;
|
||||
choices.push
|
||||
(
|
||||
tokenise::get_string_token(tokens, index)?
|
||||
);
|
||||
index += 1;
|
||||
choice_indeces.push(index+1);
|
||||
index = match tokenise::get_closing_index(tokens,index)
|
||||
{
|
||||
Ok(new_index) => new_index + 1,
|
||||
Err(_) => break,
|
||||
};
|
||||
next_token = match tokenise::get_keyword_token(tokens, index)
|
||||
{
|
||||
Ok(string) => string,
|
||||
Err(_) => break,
|
||||
}
|
||||
};
|
||||
api::modify_data(happening_queue, "choice".to_string(), String::new(), String::new(), choices);
|
||||
Ok(choice_indeces)
|
||||
}
|
||||
Reference in New Issue
Block a user