refactor, add vehicles and classes
add gitignore for node_modules
This commit is contained in:
parent
6bedb26037
commit
f5df061b42
19 changed files with 1213 additions and 108 deletions
|
@ -6,7 +6,8 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
redis = "0.22.1"
|
||||
redis = { version = "0.22.1", default_features = false, features = ["r2d2"] }
|
||||
redis_ts = "0.4.2"
|
||||
once_cell = "1.16.0"
|
||||
tokio-tungstenite = { version = "0.17.2", features=["native-tls"] }
|
||||
serde_json = "1.0.88"
|
||||
|
@ -14,4 +15,4 @@ serde = { version = "1.0.147", features = ["derive"] }
|
|||
tokio = { version = "1.22.0" }
|
||||
url = "2.3.1"
|
||||
futures-util = "0.3.25"
|
||||
futures = "0.3.25"
|
||||
futures = "0.3.25"
|
||||
|
|
38
services/websocket/event_examples.md
Normal file
38
services/websocket/event_examples.md
Normal file
|
@ -0,0 +1,38 @@
|
|||
```json
|
||||
{
|
||||
"attacker_character_id": "5429241327001550385",
|
||||
"attacker_loadout_id": "29",
|
||||
"attacker_team_id": "2",
|
||||
"attacker_vehicle_id": "0",
|
||||
"attacker_weapon_id": "6005191",
|
||||
"character_id": "5428257385129506001",
|
||||
"event_name": "VehicleDestroy",
|
||||
"facility_id": "0",
|
||||
"faction_id": "1",
|
||||
"team_id": "1",
|
||||
"timestamp": "1669213115",
|
||||
"vehicle_id": "2",
|
||||
"world_id": "1",
|
||||
"zone_id": "6"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"attacker_character_id": "5428257385129506001",
|
||||
"attacker_fire_mode_id": "80387",
|
||||
"attacker_loadout_id": "15",
|
||||
"attacker_team_id": "1",
|
||||
"attacker_vehicle_id": "0",
|
||||
"attacker_weapon_id": "6003665",
|
||||
"character_id": "5429201282572095697",
|
||||
"character_loadout_id": "6",
|
||||
"event_name": "Death",
|
||||
"is_critical": "0",
|
||||
"is_headshot": "0",
|
||||
"team_id": "2",
|
||||
"timestamp": "1669213113",
|
||||
"world_id": "1",
|
||||
"zone_id": "6"
|
||||
}
|
||||
```
|
|
@ -7,11 +7,17 @@ use serde_json::json;
|
|||
use std::{env, time::SystemTime};
|
||||
use tokio_tungstenite::{connect_async, tungstenite::Message};
|
||||
|
||||
mod translators;
|
||||
|
||||
pub static REDIS_CLIENT: Lazy<redis::Client> = Lazy::new(|| {
|
||||
redis::Client::open(std::env::var("REDIS_ADDR").unwrap_or("redis://localhost:6379".to_string()))
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
static PAIR: Lazy<String> = Lazy::new(|| env::var("PAIR").unwrap_or_default());
|
||||
static ROLE: Lazy<String> = Lazy::new(|| env::var("ROLE").unwrap_or("primary".to_string()));
|
||||
static WS_ADDR: Lazy<String> = Lazy::new(|| env::var("WS_ADDR").unwrap_or_default());
|
||||
|
||||
async fn send_init(tx: futures::channel::mpsc::UnboundedSender<Message>) {
|
||||
let worlds_raw = env::var("WORLDS").unwrap_or_default();
|
||||
if worlds_raw == "" {
|
||||
|
@ -36,22 +42,166 @@ async fn send_init(tx: futures::channel::mpsc::UnboundedSender<Message>) {
|
|||
println!("Sent setup message");
|
||||
}
|
||||
|
||||
fn process_event(event: &Event) {
|
||||
struct PopEvent {
|
||||
world_id: String,
|
||||
team_id: String,
|
||||
character_id: String,
|
||||
timestamp: u64,
|
||||
}
|
||||
|
||||
struct VehicleEvent {
|
||||
world_id: String,
|
||||
vehicle_id: String,
|
||||
character_id: String,
|
||||
timestamp: u64,
|
||||
}
|
||||
|
||||
struct ClassEvent {
|
||||
world_id: String,
|
||||
character_id: String,
|
||||
loadout_id: String,
|
||||
timestamp: u64,
|
||||
}
|
||||
|
||||
async fn track_pop(pop_event: PopEvent) {
|
||||
let mut con = REDIS_CLIENT.get_connection().unwrap();
|
||||
|
||||
let PopEvent {
|
||||
world_id,
|
||||
team_id,
|
||||
character_id,
|
||||
timestamp,
|
||||
} = pop_event;
|
||||
|
||||
let key = format!("wp:{}/{}", world_id, team_id);
|
||||
let _: () = con.zadd(key, character_id, timestamp).unwrap();
|
||||
}
|
||||
|
||||
async fn track_vehicle(vehicle_event: VehicleEvent) {
|
||||
let mut con = REDIS_CLIENT.get_connection().unwrap();
|
||||
|
||||
let VehicleEvent {
|
||||
world_id,
|
||||
vehicle_id,
|
||||
timestamp,
|
||||
character_id,
|
||||
} = vehicle_event;
|
||||
|
||||
let vehicle_name = translators::vehicle_to_name(vehicle_id.as_str());
|
||||
|
||||
if vehicle_name == "unknown" {
|
||||
return;
|
||||
}
|
||||
|
||||
let key = format!("v:{}/{}", world_id, vehicle_name);
|
||||
let _: () = con.zadd(key, character_id, timestamp).unwrap();
|
||||
}
|
||||
|
||||
async fn track_class(class_event: ClassEvent) {
|
||||
let mut con = REDIS_CLIENT.get_connection().unwrap();
|
||||
|
||||
let ClassEvent {
|
||||
world_id,
|
||||
character_id,
|
||||
loadout_id,
|
||||
timestamp,
|
||||
} = class_event;
|
||||
|
||||
let class_name = translators::loadout_to_class(loadout_id.as_str());
|
||||
|
||||
if class_name == "unknown" {
|
||||
return;
|
||||
}
|
||||
|
||||
let key = format!("c:{}/{}", world_id, class_name);
|
||||
let _: () = con.zadd(key, character_id, timestamp).unwrap();
|
||||
}
|
||||
|
||||
fn should_process_event() -> bool {
|
||||
let mut con = REDIS_CLIENT.get_connection().unwrap();
|
||||
let role: String = ROLE.parse().unwrap();
|
||||
let heartbeat_key = format!("heartbeat:{}", PAIR.to_string());
|
||||
|
||||
if role == "primary" {
|
||||
let _: () = con.set_ex(heartbeat_key, "1", 60).unwrap();
|
||||
return false;
|
||||
}
|
||||
|
||||
match con.get(heartbeat_key) {
|
||||
Ok(1) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn process_event(event: &Event) {
|
||||
if should_process_event() {
|
||||
return;
|
||||
}
|
||||
|
||||
let timestamp = SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
|
||||
let key: String = format!("wp:{}/{}", event.world_id, event.team_id);
|
||||
con.zadd::<String, u64, String, ()>(key, event.character_id.clone(), timestamp)
|
||||
.unwrap();
|
||||
// General population tracking
|
||||
track_pop(PopEvent {
|
||||
world_id: event.world_id.clone(),
|
||||
team_id: event.team_id.clone(),
|
||||
character_id: event.character_id.clone(),
|
||||
timestamp,
|
||||
})
|
||||
.now_or_never();
|
||||
|
||||
if event.attacker_character_id != "" {
|
||||
let key = format!("wp:{}/{}", event.world_id, event.attacker_team_id);
|
||||
con.zadd::<String, u64, String, ()>(key, event.attacker_character_id.clone(), timestamp)
|
||||
.unwrap();
|
||||
if event.event_name == "VehicleDestroy" {
|
||||
track_vehicle(VehicleEvent {
|
||||
world_id: event.world_id.clone(),
|
||||
vehicle_id: event.vehicle_id.clone(),
|
||||
character_id: event.character_id.clone(),
|
||||
timestamp,
|
||||
})
|
||||
.now_or_never();
|
||||
}
|
||||
|
||||
if event.event_name == "Death" {
|
||||
track_class(ClassEvent {
|
||||
world_id: event.world_id.clone(),
|
||||
character_id: event.character_id.clone(),
|
||||
loadout_id: event.loadout_id.clone(),
|
||||
timestamp,
|
||||
})
|
||||
.now_or_never();
|
||||
}
|
||||
|
||||
if event.attacker_character_id != ""
|
||||
&& (event.attacker_team_id != "" || event.attacker_team_id != "0")
|
||||
{
|
||||
track_pop(PopEvent {
|
||||
world_id: event.world_id.clone(),
|
||||
team_id: event.attacker_team_id.clone(),
|
||||
character_id: event.attacker_character_id.clone(),
|
||||
timestamp,
|
||||
})
|
||||
.now_or_never();
|
||||
|
||||
if event.event_name == "VehicleDestroy" {
|
||||
track_vehicle(VehicleEvent {
|
||||
world_id: event.world_id.clone(),
|
||||
vehicle_id: event.attacker_vehicle_id.clone(),
|
||||
character_id: event.attacker_character_id.clone(),
|
||||
timestamp,
|
||||
})
|
||||
.now_or_never();
|
||||
}
|
||||
|
||||
if event.event_name == "Death" {
|
||||
track_class(ClassEvent {
|
||||
world_id: event.world_id.clone(),
|
||||
character_id: event.attacker_character_id.clone(),
|
||||
loadout_id: event.attacker_loadout_id.clone(),
|
||||
timestamp,
|
||||
})
|
||||
.now_or_never();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,6 +213,18 @@ struct Event {
|
|||
attacker_character_id: String,
|
||||
attacker_team_id: String,
|
||||
team_id: String,
|
||||
|
||||
// Class Tracking
|
||||
#[serde(default)]
|
||||
attacker_loadout_id: String,
|
||||
#[serde(default)]
|
||||
loadout_id: String,
|
||||
|
||||
// Vehicle Tracking
|
||||
#[serde(default)]
|
||||
vehicle_id: String,
|
||||
#[serde(default)]
|
||||
attacker_vehicle_id: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
|
@ -72,12 +234,13 @@ struct Payload {
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let addr = env::var("WS_ADDR").unwrap_or_default();
|
||||
let addr: String = WS_ADDR.to_string();
|
||||
if addr == "" {
|
||||
println!("WS_ADDR not set");
|
||||
return;
|
||||
}
|
||||
let url = url::Url::parse(&addr).unwrap();
|
||||
|
||||
let (tx, rx) = futures::channel::mpsc::unbounded();
|
||||
let (ws_stream, _) = connect_async(url).await.expect("Failed to connect");
|
||||
let (write, read) = ws_stream.split();
|
||||
|
@ -85,6 +248,8 @@ async fn main() {
|
|||
let fused_writer = rx.map(Ok).forward(write).fuse();
|
||||
let fused_reader = read
|
||||
.for_each(|msg| async move {
|
||||
// println!("Processing event: {:?}", msg);
|
||||
|
||||
let body = &msg.unwrap().to_string();
|
||||
let data: Payload = serde_json::from_str(body).unwrap_or(Payload {
|
||||
payload: Event {
|
||||
|
@ -94,6 +259,10 @@ async fn main() {
|
|||
attacker_character_id: "".to_string(),
|
||||
attacker_team_id: "".to_string(),
|
||||
team_id: "".to_string(),
|
||||
attacker_loadout_id: "".to_string(),
|
||||
loadout_id: "".to_string(),
|
||||
vehicle_id: "".to_string(),
|
||||
attacker_vehicle_id: "".to_string(),
|
||||
},
|
||||
});
|
||||
|
||||
|
|
99
services/websocket/src/translators.rs
Normal file
99
services/websocket/src/translators.rs
Normal file
|
@ -0,0 +1,99 @@
|
|||
// GENERATED CODE -- Do not edit. Run `node hack/codegen/codegen.js > services/websocket/src/translators.rs` to regenerate.
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use std::collections::HashMap;
|
||||
|
||||
static VEHICLE_TO_NAME: Lazy<HashMap<&str, &str>> = Lazy::new(|| {
|
||||
HashMap::from([
|
||||
("1", "flash"),
|
||||
("2", "sunderer"),
|
||||
("3", "lightning"),
|
||||
("5", "vanguard"),
|
||||
("6", "prowler"),
|
||||
("7", "scythe"),
|
||||
("8", "reaver"),
|
||||
("9", "mosquito"),
|
||||
("10", "liberator"),
|
||||
("11", "galaxy"),
|
||||
("12", "harasser"),
|
||||
("14", "valkyrie"),
|
||||
("15", "ant"),
|
||||
("100", "ant"),
|
||||
("101", "ant"),
|
||||
("102", "ant"),
|
||||
("150", "ant"),
|
||||
("151", "ant"),
|
||||
("160", "ant"),
|
||||
("161", "ant"),
|
||||
("162", "ant"),
|
||||
("1001", "flash"),
|
||||
("1002", "sunderer"),
|
||||
("1005", "vanguard"),
|
||||
("1007", "scythe"),
|
||||
("1008", "reaver"),
|
||||
("1009", "mosquito"),
|
||||
("1010", "liberator"),
|
||||
("1011", "galaxy"),
|
||||
("1105", "vanguard"),
|
||||
("2006", "ant"),
|
||||
("2009", "ant"),
|
||||
("2010", "flash"),
|
||||
("2033", "javelin"),
|
||||
("2122", "mosquito"),
|
||||
("2123", "reaver"),
|
||||
("2124", "scythe"),
|
||||
("2125", "javelin"),
|
||||
("2129", "javelin"),
|
||||
("2130", "sunderer"),
|
||||
("2131", "galaxy"),
|
||||
("2132", "valkyrie"),
|
||||
("2134", "vanguard"),
|
||||
("2135", "prowler"),
|
||||
("2136", "dervish"),
|
||||
("2137", "chimera"),
|
||||
("2142", "corsair"),
|
||||
])
|
||||
});
|
||||
|
||||
pub fn vehicle_to_name(vehicle_id: &str) -> String {
|
||||
match VEHICLE_TO_NAME.get(&vehicle_id) {
|
||||
Some(name) => name.to_string(),
|
||||
None => "unknown".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
static LOADOUT_TO_CLASS: Lazy<HashMap<&str, &str>> = Lazy::new(|| {
|
||||
HashMap::from([
|
||||
("1", "infiltrator"),
|
||||
("3", "light_assault"),
|
||||
("4", "combat_medic"),
|
||||
("5", "engineer"),
|
||||
("6", "heavy_assault"),
|
||||
("7", "max"),
|
||||
("8", "infiltrator"),
|
||||
("10", "light_assault"),
|
||||
("11", "combat_medic"),
|
||||
("12", "engineer"),
|
||||
("13", "heavy_assault"),
|
||||
("14", "max"),
|
||||
("15", "infiltrator"),
|
||||
("17", "light_assault"),
|
||||
("18", "combat_medic"),
|
||||
("19", "engineer"),
|
||||
("20", "heavy_assault"),
|
||||
("21", "max"),
|
||||
("28", "infiltrator"),
|
||||
("29", "light_assault"),
|
||||
("30", "combat_medic"),
|
||||
("31", "engineer"),
|
||||
("32", "heavy_assault"),
|
||||
("45", "max"),
|
||||
])
|
||||
});
|
||||
|
||||
pub fn loadout_to_class(loadout_id: &str) -> String {
|
||||
match LOADOUT_TO_CLASS.get(&loadout_id) {
|
||||
Some(name) => name.to_string(),
|
||||
None => "unknown".to_string(),
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue