Added a character route for requesting character data from the server
This commit is contained in:
+1
-1
@@ -1 +1 @@
|
|||||||
,deadvey,linux-pc,07.04.2026 00:08,file:///home/deadvey/.config/libreoffice/4;
|
,deadvey,linux-pc,30.04.2026 12:49,file:///home/deadvey/.config/libreoffice/4;
|
||||||
Generated
+1
@@ -248,6 +248,7 @@ dependencies = [
|
|||||||
"env_logger",
|
"env_logger",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
"warp",
|
"warp",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -7,5 +7,6 @@ edition = "2024"
|
|||||||
env_logger = "0.11.10"
|
env_logger = "0.11.10"
|
||||||
log = "0.4.29"
|
log = "0.4.29"
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
|
serde_json = "1.0.149"
|
||||||
tokio = { version = "1.51.0", features = ["rt-multi-thread","macros"] }
|
tokio = { version = "1.51.0", features = ["rt-multi-thread","macros"] }
|
||||||
warp = { version = "0.4.2", features = ["server"] }
|
warp = { version = "0.4.2", features = ["server"] }
|
||||||
|
|||||||
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
+30
-7
@@ -1,14 +1,18 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use warp::Filter;
|
use warp::Filter;
|
||||||
use crate::
|
use crate::
|
||||||
{
|
{
|
||||||
|
// internal code
|
||||||
|
character,
|
||||||
|
// libraries
|
||||||
|
HashMap,
|
||||||
Arc,
|
Arc,
|
||||||
Mutex,
|
Mutex,
|
||||||
config,
|
config,
|
||||||
mpsc::Sender,
|
mpsc::Sender,
|
||||||
info,
|
info,
|
||||||
warn,
|
|
||||||
debug,
|
debug,
|
||||||
|
Serialize,
|
||||||
|
Deserialize,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
@@ -21,29 +25,48 @@ pub struct DataToSend {
|
|||||||
// Async function that runs the api server in the background.
|
// 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
|
// 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
|
// 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>>, tx: Sender<u8>)
|
pub async fn api_process
|
||||||
|
(
|
||||||
|
data_to_send: Arc<Mutex<DataToSend>>,
|
||||||
|
characters: Arc<Mutex<HashMap::<String,character::Character>>>,
|
||||||
|
tx: Sender<u8>,
|
||||||
|
)
|
||||||
{
|
{
|
||||||
// This data must be passed through to the api route in order to be used
|
// 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 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());
|
let tx_filter = warp::any().map(move || tx.clone());
|
||||||
|
|
||||||
debug!("Running server");
|
info!("Running server");
|
||||||
|
|
||||||
// The server route is loaded at address:port/happening
|
// The server route is loaded at address:port/happening
|
||||||
let route = warp::path("happening")
|
let main = warp::path("happening")
|
||||||
.and(warp::get())
|
.and(warp::get())
|
||||||
.and(data_filter)
|
.and(data_filter)
|
||||||
.and(tx_filter)
|
.and(tx_filter)
|
||||||
// Perform this code on a GET request
|
// Perform this code on a GET request
|
||||||
.map(|state: Arc<Mutex<DataToSend>>, tx_handle: Sender<u8>| {
|
.map(|state: Arc<Mutex<DataToSend>>, tx_handle: Sender<u8>|
|
||||||
|
{
|
||||||
info!("GET: {:?}", state);
|
info!("GET: {:?}", state);
|
||||||
let reply = state.as_ref();
|
let reply = state.as_ref();
|
||||||
let _ = tx_handle.send(1);
|
let _ = tx_handle.send(1);
|
||||||
warp::reply::json(&reply) // Send the reply data (data_to_send formatted as JSON)
|
warp::reply::json(&reply) // Send the reply data (data_to_send formatted as JSON)
|
||||||
}).boxed();
|
}).boxed();
|
||||||
|
let characters = warp::path("character")
|
||||||
|
.and(warp::get())
|
||||||
|
.and(warp::path::param::<String>())
|
||||||
|
.and(characters_filter)
|
||||||
|
.map(|name: String, characters: Arc<Mutex<HashMap<String, character::Character>>>|
|
||||||
|
{
|
||||||
|
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
|
// Start the server
|
||||||
warp::serve(route)
|
warp::serve(routes)
|
||||||
.run(([127, 0, 0, 1],config::API_PORT))
|
.run(([127, 0, 0, 1],config::API_PORT))
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,33 @@
|
|||||||
|
use crate::{
|
||||||
|
HashMap,
|
||||||
|
fs,
|
||||||
|
debug,
|
||||||
|
Deserialize,
|
||||||
|
Serialize,
|
||||||
|
Mutex,
|
||||||
|
Arc,
|
||||||
|
};
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub struct Character
|
pub struct Character
|
||||||
{
|
{
|
||||||
name: String,
|
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
|
impl Character
|
||||||
{
|
{
|
||||||
@@ -9,6 +36,38 @@ impl Character
|
|||||||
Character
|
Character
|
||||||
{
|
{
|
||||||
name: new_name,
|
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<Arc<Mutex<HashMap<String, Character>>>,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<String, Character> =
|
||||||
|
serde_json::from_str(&file_contents)
|
||||||
|
.expect("JSON was not well-formatted");
|
||||||
|
debug!("{:?}",characters);
|
||||||
|
Ok(Arc::new(Mutex::new(characters)))
|
||||||
|
}
|
||||||
|
|||||||
+21
-5
@@ -10,6 +10,8 @@ use log::
|
|||||||
warn,
|
warn,
|
||||||
debug,
|
debug,
|
||||||
};
|
};
|
||||||
|
use serde_json::from_str;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
mod parsing;
|
mod parsing;
|
||||||
mod character;
|
mod character;
|
||||||
@@ -30,24 +32,33 @@ async fn main()
|
|||||||
content: "".to_string(),
|
content: "".to_string(),
|
||||||
character: "".to_string(),
|
character: "".to_string(),
|
||||||
}));
|
}));
|
||||||
|
// Setup the characters hashmap which will store each character in it as a Character struct
|
||||||
|
let mut characters: Arc<Mutex<HashMap::<String, character::Character>>> = 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 //
|
// setup the api stuff //
|
||||||
|
|
||||||
// Make clones of the data Arc for the two processes
|
// 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 characters_clone1 = Arc::clone(&characters);
|
||||||
let tx_clone = tx.clone();
|
let tx_clone = tx.clone();
|
||||||
// Spawn a thread for warp api server
|
// Spawn a thread for warp api server
|
||||||
tokio::spawn(
|
tokio::spawn(
|
||||||
async move {
|
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 parsing stuff //
|
||||||
// Setup the characters hashmap which will store each character in it as a Character struct
|
|
||||||
let mut characters = HashMap::<String, character::Character>::new();
|
|
||||||
|
|
||||||
// Read the file and split it into tokens
|
// 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
|
let file_contents: String = fs::read_to_string("stories/story.ha") // TODO make this a command line argument
|
||||||
.unwrap_or_else(|err|
|
.unwrap_or_else(|err|
|
||||||
@@ -58,10 +69,15 @@ async fn main()
|
|||||||
let tokens: Vec<&str> = file_contents
|
let tokens: Vec<&str> = file_contents
|
||||||
.split_whitespace()
|
.split_whitespace()
|
||||||
.collect();
|
.collect();
|
||||||
|
if ! tokens.contains(&"END")
|
||||||
|
{
|
||||||
|
warn!("No END statement, story may exit unexpectedly");
|
||||||
|
}
|
||||||
|
|
||||||
let data_clone2 = Arc::clone(&data_to_send);
|
let data_clone2 = Arc::clone(&data_to_send);
|
||||||
|
let characters_clone2 = Arc::clone(&characters);
|
||||||
// Run the parsing process
|
// 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
|
// Exit with error or success
|
||||||
Ok(()) =>
|
Ok(()) =>
|
||||||
|
|||||||
+3
-10
@@ -11,7 +11,6 @@ use crate::
|
|||||||
Arc,
|
Arc,
|
||||||
Mutex,
|
Mutex,
|
||||||
info,
|
info,
|
||||||
warn,
|
|
||||||
debug,
|
debug,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -20,7 +19,7 @@ use crate::
|
|||||||
// Returns success or an error string
|
// Returns success or an error string
|
||||||
pub async fn token_parse(
|
pub async fn token_parse(
|
||||||
tokens: &Vec<&str>,
|
tokens: &Vec<&str>,
|
||||||
mut characters: &mut HashMap::<String, character::Character>,
|
mut characters: Arc<Mutex<HashMap::<String, character::Character>>>,
|
||||||
data_to_send: Arc<Mutex<api::DataToSend>>,
|
data_to_send: Arc<Mutex<api::DataToSend>>,
|
||||||
rx: &Receiver<u8>,
|
rx: &Receiver<u8>,
|
||||||
) -> Result<(),String>
|
) -> Result<(),String>
|
||||||
@@ -43,15 +42,9 @@ pub async fn token_parse(
|
|||||||
if token.starts_with('@')
|
if token.starts_with('@')
|
||||||
{
|
{
|
||||||
let character_name: String = token.chars().skip(1).collect();
|
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);
|
info!("Doing something with a character: {}", character_name);
|
||||||
// The index is incremented to after the character's instructions
|
// 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,
|
Ok(increment) => increment,
|
||||||
Err(error) => return Err(error),
|
Err(error) => return Err(error),
|
||||||
@@ -73,7 +66,7 @@ async fn character_parse
|
|||||||
index: usize,
|
index: usize,
|
||||||
tokens: &Vec<&str>,
|
tokens: &Vec<&str>,
|
||||||
character_name: String,
|
character_name: String,
|
||||||
characters: &mut HashMap::<String, character::Character>,
|
characters: &Arc<Mutex<HashMap::<String, character::Character>>>,
|
||||||
data_to_send: &Arc<Mutex<api::DataToSend>>,
|
data_to_send: &Arc<Mutex<api::DataToSend>>,
|
||||||
rx: &Receiver<u8>,
|
rx: &Receiver<u8>,
|
||||||
) -> Result<usize,String>
|
) -> Result<usize,String>
|
||||||
|
|||||||
@@ -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": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user