diff options
author | Daniel Jones <daniel@danieljon.es> | 2024-08-31 02:21:00 +1000 |
---|---|---|
committer | Daniel Jones <daniel@danieljon.es> | 2024-08-31 02:21:00 +1000 |
commit | 1aa744193776fc2f8dacc74c4e9944146c303906 (patch) | |
tree | 26170bae4bc9aa7a462721a8e007b3864c7cd923 | |
parent | 3aee60f52b146bcfc010afab78331872180ecf64 (diff) | |
download | cstracker-master.tar.gz cstracker-master.zip |
-rw-r--r-- | Cargo.toml | 4 | ||||
-rw-r--r-- | src/main.rs | 149 |
2 files changed, 125 insertions, 28 deletions
@@ -4,7 +4,9 @@ version = "0.1.0" edition = "2021" [dependencies] +reqwest = { version = "0.11", features = ["json"] } tokio = { version = "1", features = ["full"] } hyper = { version = "0.14", features = ["full"] } serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0"
\ No newline at end of file +serde_json = "1.0" +webhook = "2.1.2"
\ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 1b2c8c7..76a929d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,12 @@ use hyper::{Body, Request, Response, Server, service::{make_service_fn, service_fn}}; use serde_json::Value; -use std::convert::Infallible; -use serde::Deserialize; +use std::collections::HashMap; +use std::sync::{Arc, Mutex}; +use serde::{Deserialize, Serialize}; +use webhook::client::WebhookClient; +use std::error::Error; + +const IMAGE_URL: &str = "https://www.counter-strike.net/favicon.ico"; #[derive(Debug, Deserialize)] struct MatchData { @@ -17,19 +22,16 @@ struct MatchData { #[derive(Debug, Deserialize)] struct MapData { name: Option<String>, - // Add other map-specific fields as necessary } #[derive(Debug, Deserialize)] struct RoundData { phase: Option<String>, - // Add other round-specific fields as necessary } #[derive(Debug, Deserialize)] struct PlayerIdData { id: Option<u32>, - // Add other player_id-specific fields as necessary } #[derive(Debug, Deserialize)] @@ -37,48 +39,133 @@ struct PlayerStateData { health: Option<u32>, armor: Option<u32>, flashed: Option<u32>, - // Add other player_state-specific fields as necessary } #[derive(Debug, Deserialize)] struct PlayerWeaponsData { primary: Option<String>, secondary: Option<String>, - // Add other player_weapons-specific fields as necessary } #[derive(Debug, Deserialize)] struct PlayerMatchStatsData { kills: Option<u32>, deaths: Option<u32>, - // Add other player_match_stats-specific fields as necessary } #[derive(Debug, Deserialize)] struct AllPlayersIdData { players: Vec<PlayerIdData>, - // Add other allplayers_id-specific fields as necessary } -async fn handle_request(req: Request<Body>) -> Result<Response<Body>, Infallible> { - if req.method() == hyper::Method::POST { - let whole_body = hyper::body::to_bytes(req.into_body()).await.unwrap(); - let json: Value = serde_json::from_slice(&whole_body).unwrap(); +#[derive(Serialize)] +struct Message { + content: String, +} - // Print the raw JSON for debugging - println!("Received JSON: {}", json); +// Define the state type +type State = Arc<Mutex<HashMap<String, HashMap<String, i64>>>>; - // Print out the parsed data for debugging - if let Some(map) = json.as_object() { - for (key, value) in map { - println!("{}: {}", key, value); +async fn handle_request(req: Request<Body>, state: State) -> Result<Response<Body>, Box<dyn Error + Send + Sync>> { + if req.method() == hyper::Method::POST { + let whole_body = hyper::body::to_bytes(req.into_body()).await?; + + // Attempt to parse the JSON + match serde_json::from_slice::<Value>(&whole_body) { + Ok(json) => { + // Print the raw JSON for debugging + // println!("Received JSON: {}", json); + + // Lock the state for reading and writing + let mut previous_state = state.lock().unwrap(); + + // Check if the JSON value is an object + if let Some(map) = json.as_object() { + if let Some(player) = map.get("player") { + if let Some(player_obj) = player.as_object() { + // Extract weapon information + if let Some(weapons) = player_obj.get("weapons") { + if let Some(weapons_obj) = weapons.as_object() { + for (weapon_key, weapon_value) in weapons_obj { + if let Some(weapon_obj) = weapon_value.as_object() { + if let Some(name) = weapon_obj.get("name") { + if let Some(name_str) = name.as_str() { + if let Some(ammo_clip) = weapon_obj.get("ammo_clip") { + if let Some(ammo_clip_value) = ammo_clip.as_i64() { + // Update previous state + let mut weapon_state = previous_state.entry(weapon_key.clone()).or_insert_with(HashMap::new); + let prev_ammo_clip = weapon_state.entry("ammo_clip".to_string()).or_insert(0); + + // Print debug information + println!("Weapon: {}, Ammo Clip (prev): {}, Ammo Clip (current): {}", name_str, prev_ammo_clip, ammo_clip_value); + + // Compare ammo_clip with previous state + if ammo_clip_value < *prev_ammo_clip { + println!("Weapon {}: {} fired! Ammo Clip: {} -> {}", weapon_key, name_str, prev_ammo_clip, ammo_clip_value); + + let url = "https://discord.com/api/webhooks/1277517311347261470/4-UgsyHK3-AcWai9xWsOMHkpnpAHuFc0Izp3fRCb7M0NaHNng9h6tKmS3x_k4X-4tdMS"; + + // Send the webhook message in an async block + let client = WebhookClient::new(&url); + let webhook_info = client.get_information().await?; + println!("webhook: {:?}", webhook_info); + + client.send(|message| message + .content("@everyone") + .username("Thoo") + .avatar_url(IMAGE_URL) + .embed(|embed| embed + .title("Webhook") + .description("Hello, World!") + .footer("Footer", Some(String::from(IMAGE_URL))) + .image(IMAGE_URL) + .thumbnail(IMAGE_URL) + .author("Lmao#0001", Some(String::from(IMAGE_URL)), Some(String::from(IMAGE_URL))) + .field("name", "value", false))).await?; + + } + + // Update previous ammo_clip + *prev_ammo_clip = ammo_clip_value; + } else { + println!("Ammo clip is not an integer for weapon {}", name_str); + } + } else { + println!("Ammo clip field is missing for weapon {}", name_str); + } + } else { + println!("Weapon name is not a string"); + } + } else { + println!("Weapon object does not contain a name field"); + } + } else { + println!("Weapon value is not an object"); + } + } + } else { + println!("Weapons field is not an object"); + } + } else { + println!("Player object does not contain weapons field"); + } + } else { + println!("Player field is not an object"); + } + } else { + println!("JSON does not contain player field"); + } + } else { + println!("JSON is not an object"); + } + + Ok(Response::new(Body::from("Received"))) + }, + Err(e) => { + eprintln!("Failed to parse JSON: {}", e); + Ok(Response::new(Body::from("Invalid JSON"))) } - } else { - println!("Received data is not a JSON object"); } - - // Respond to the GSI service - Ok(Response::new(Body::from("Received"))) } else { Ok(Response::new(Body::from("Unsupported HTTP method"))) } @@ -86,9 +173,17 @@ async fn handle_request(req: Request<Body>) -> Result<Response<Body>, Infallible #[tokio::main] async fn main() { - let make_svc = make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(handle_request)) }); + // Initialize the global state + let state = Arc::new(Mutex::new(HashMap::new())); + + let make_svc = make_service_fn(move |_conn| { + let state = state.clone(); + async move { + Ok::<_, Box<dyn Error + Send + Sync>>(service_fn(move |req| handle_request(req, state.clone()))) + } + }); - let addr = ([0, 0, 0, 0], 5000).into(); // Listen on all interfaces on port 3000 + let addr = ([0, 0, 0, 0], 5000).into(); // Listen on all interfaces on port 5000 let server = Server::bind(&addr).serve(make_svc); println!("Listening on http://{}", addr); @@ -96,4 +191,4 @@ async fn main() { if let Err(e) = server.await { eprintln!("server error: {}", e); } -}
\ No newline at end of file +} |