refactor, add vehicles and classes

add gitignore for node_modules
This commit is contained in:
41666 2022-11-23 15:12:09 -05:00
parent 6bedb26037
commit f5df061b42
19 changed files with 1213 additions and 108 deletions

View file

@ -7,7 +7,6 @@ edition = "2021"
[dependencies]
rocket = { version = "0.5.0-rc.2", features = ["json"] }
rocket_db_pools = { version = "0.1.0-rc.2", features = [ "deadpool_redis" ] }
serde_json = "1.0.88"
serde = "1.0.147"
redis = { version = "0.22.1", default_features = false, features = [] }
once_cell = "1.16.0"
serde = "1.0.147"

106
services/api/src/classes.rs Normal file
View file

@ -0,0 +1,106 @@
use core::time;
use rocket_db_pools::deadpool_redis::redis::{pipe, AsyncCommands};
use rocket_db_pools::Connection;
use serde::{Deserialize, Serialize};
use std::ops::Sub;
use std::time::SystemTime;
use crate::redispool::RedisPool;
#[derive(Serialize, Deserialize, Debug)]
struct ClassCounts {
world_id: String,
classes: Classes,
}
#[derive(Serialize, Deserialize, Debug)]
struct Classes {
light_assault: u32,
engineer: u32,
combat_medic: u32,
heavy_assault: u32,
infiltrator: u32,
max: u32,
}
#[get("/w/<world_id>/classes")]
pub async fn get_classes(world_id: String, mut con: Connection<RedisPool>) -> serde_json::Value {
let cache_key = format!("cache:classes:{}", world_id);
match con.get::<String, String>(cache_key.clone()).await {
Ok(cached) => {
return serde_json::from_str(&cached).unwrap();
}
Err(_) => {}
}
let filter_timestamp = SystemTime::now()
.sub(time::Duration::from_secs(60 * 15))
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs();
// I hate this but it's fast???
// The type only allows 12 at a time.
let (light_assault, engineer, combat_medic, heavy_assault, infiltrator, max): (
u32,
u32,
u32,
u32,
u32,
u32,
) = pipe()
.zcount(
format!("c:{}/{}", world_id, "light_assault"),
filter_timestamp,
"+inf",
)
.zcount(
format!("c:{}/{}", world_id, "engineer"),
filter_timestamp,
"+inf",
)
.zcount(
format!("c:{}/{}", world_id, "combat_medic"),
filter_timestamp,
"+inf",
)
.zcount(
format!("c:{}/{}", world_id, "heavy_assault"),
filter_timestamp,
"+inf",
)
.zcount(
format!("c:{}/{}", world_id, "infiltrator"),
filter_timestamp,
"+inf",
)
.zcount(
format!("c:{}/{}", world_id, "max"),
filter_timestamp,
"+inf",
)
.query_async(&mut *con)
.await
.unwrap();
let response = ClassCounts {
world_id,
classes: Classes {
light_assault,
engineer,
combat_medic,
heavy_assault,
infiltrator,
max,
},
};
let out = json!(response);
con.set_ex::<String, String, ()>(cache_key, out.to_string(), 5)
.await
.unwrap();
out
}

View file

@ -1,10 +1,16 @@
pub mod classes;
pub mod cors;
pub mod population;
pub mod redispool;
pub mod vehicles;
use redispool::RedisPool;
use rocket::fairing::AdHoc;
use rocket::{error, Build, Rocket};
use rocket_db_pools::deadpool_redis::redis::{cmd, pipe};
use rocket_db_pools::{Connection, Database};
use core::time;
use once_cell::sync::Lazy;
use rocket::{Build, Rocket};
use serde::{Deserialize, Serialize};
use std::{ops::Sub, time::SystemTime};
#[macro_use]
extern crate rocket;
@ -16,31 +22,14 @@ struct IncomingHeaders {
host: String,
}
#[derive(Serialize, Deserialize, Debug)]
struct Factions {
tr: u32,
nc: u32,
vs: u32,
ns: u32,
fn hello_world(host: String, world_id: &str) -> serde_json::Value {
json!({
"population": format!("https://{}/w/{}", host, world_id),
"vehicles": format!("https://{}/w/{}/vehicles", host, world_id),
"classes": format!("https://{}/w/{}/classes", host, world_id),
})
}
#[derive(Serialize, Deserialize, Debug)]
struct WorldPopulation {
world_id: u32,
total: u32,
factions: Factions,
}
#[derive(Serialize, Deserialize, Debug)]
struct MultipleWorldPopulation {
worlds: Vec<WorldPopulation>,
}
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()
});
fn hello(host: String) -> serde_json::Value {
json!({
"@": "Saerro Listening Post - PlanetSide 2 Live Population API",
@ -48,73 +37,76 @@ fn hello(host: String) -> serde_json::Value {
"@Disclaimer": "Genudine Dynamics is not responsible for any damages caused by this software. Use at your own risk.",
"@Support": "#api-dev in https://discord.com/servers/planetside-2-community-251073753759481856",
"Worlds": {
"Connery": format!("https://{}/w/1", host),
"Miller": format!("https://{}/w/10", host),
"Cobalt": format!("https://{}/w/13", host),
"Emerald": format!("https://{}/w/17", host),
"Jaeger": format!("https://{}/w/19", host),
"SolTech": format!("https://{}/w/40", host),
"Genudine": format!("https://{}/w/1000", host),
"Ceres": format!("https://{}/w/2000", host),
"Connery": hello_world(host.clone(), "1"),
"Miller": hello_world(host.clone(), "10"),
"Cobalt": hello_world(host.clone(), "13"),
"Emerald": hello_world(host.clone(), "17"),
"Jaeger": hello_world(host.clone(), "19"),
"SolTech": hello_world(host.clone(), "40"),
"Genudine": hello_world(host.clone(), "1000"),
"Ceres": hello_world(host.clone(), "2000"),
},
"All Worlds": format!("https://{}/m/?ids=1,10,13,17,19,40,1000,2000", host),
// "All World Population": format!("https://{}/m/?ids=1,10,13,17,19,40,1000,2000", host),
})
}
async fn get_world_pop(world_id: String) -> WorldPopulation {
let mut con = REDIS_CLIENT.get_connection().unwrap();
let filter_timestamp = SystemTime::now()
.sub(time::Duration::from_secs(60 * 15))
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs();
let (vs, nc, tr, ns): (u32, u32, u32, u32) = redis::pipe()
.zcount(format!("wp:{}/{}", world_id, 1), filter_timestamp, "+inf")
.zcount(format!("wp:{}/{}", world_id, 2), filter_timestamp, "+inf")
.zcount(format!("wp:{}/{}", world_id, 3), filter_timestamp, "+inf")
.zcount(format!("wp:{}/{}", world_id, 4), filter_timestamp, "+inf")
.query(&mut con)
.unwrap();
let total = tr + vs + nc;
let response = WorldPopulation {
world_id: world_id.parse().unwrap(),
total,
factions: Factions { tr, nc, vs, ns },
};
response
}
#[get("/w/<world_id>")]
async fn world_pop(world_id: String) -> serde_json::Value {
let response = get_world_pop(world_id).await;
json!(response)
}
#[get("/m?<ids>")]
async fn multiple_world_pop(ids: String) -> serde_json::Value {
let mut response = MultipleWorldPopulation { worlds: vec![] };
for id in ids.split(",") {
response.worlds.push(get_world_pop(id.to_string()).await);
}
json!(response)
}
#[get("/")]
async fn index() -> serde_json::Value {
fn index() -> serde_json::Value {
hello("saerro.harasse.rs".to_string())
}
#[get("/health")]
async fn health(mut con: Connection<RedisPool>) -> serde_json::Value {
let (ping, pc, ps4us, ps4eu): (String, bool, bool, bool) = pipe()
.cmd("PING")
.get("heartbeat:pc")
.get("heartbeat:ps4us")
.get("heartbeat:ps4eu")
.query_async(&mut *con)
.await
.unwrap_or_default();
json!({
"status": "ok",
"redis": ping == "PONG",
"pc": if pc { "primary" } else { "backup/down" },
"ps4us": if ps4us { "primary" } else { "backup/down" },
"ps4eu": if ps4eu { "primary" } else { "backup/down" },
})
}
#[launch]
fn rocket() -> Rocket<Build> {
let figment = rocket::Config::figment().merge((
"databases.redis.url",
format!(
"redis://{}:{}",
std::env::var("REDIS_HOST").unwrap_or("localhost".to_string()),
std::env::var("REDIS_PORT").unwrap_or("6379".to_string()),
),
));
rocket::build()
.configure(figment)
.attach(cors::CORS)
.mount("/", routes![index, world_pop, multiple_world_pop])
.attach(RedisPool::init())
.attach(AdHoc::on_ignite("Redis Check", |rocket| async move {
if let Some(pool) = RedisPool::fetch(&rocket) {
let mut con = pool.get().await.unwrap();
let _: () = cmd("PING").query_async(&mut con).await.unwrap();
} else {
error!("Redis connection failed");
}
rocket
}))
.mount(
"/",
routes![
index,
health,
population::get_world_pop,
vehicles::get_vehicles,
classes::get_classes,
],
)
}

View file

@ -0,0 +1,55 @@
use core::time;
use std::{ops::Sub, time::SystemTime};
use rocket_db_pools::{deadpool_redis::redis::pipe, Connection};
use serde::{Deserialize, Serialize};
use crate::redispool::RedisPool;
#[derive(Serialize, Deserialize, Debug)]
pub struct Factions {
tr: u32,
nc: u32,
vs: u32,
ns: u32,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct WorldPopulation {
world_id: u32,
total: u32,
factions: Factions,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct MultipleWorldPopulation {
worlds: Vec<WorldPopulation>,
}
#[get("/w/<world_id>")]
pub async fn get_world_pop(world_id: String, mut con: Connection<RedisPool>) -> serde_json::Value {
let filter_timestamp = SystemTime::now()
.sub(time::Duration::from_secs(60 * 15))
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs();
let (vs, nc, tr, ns): (u32, u32, u32, u32) = pipe()
.zcount(format!("wp:{}/{}", world_id, 1), filter_timestamp, "+inf")
.zcount(format!("wp:{}/{}", world_id, 2), filter_timestamp, "+inf")
.zcount(format!("wp:{}/{}", world_id, 3), filter_timestamp, "+inf")
.zcount(format!("wp:{}/{}", world_id, 4), filter_timestamp, "+inf")
.query_async(&mut *con)
.await
.unwrap();
let total = tr + vs + nc;
let response = WorldPopulation {
world_id: world_id.parse().unwrap(),
total,
factions: Factions { tr, nc, vs, ns },
};
json!(response)
}

View file

@ -0,0 +1,5 @@
use rocket_db_pools::{deadpool_redis, Database};
#[derive(Database)]
#[database("redis")]
pub struct RedisPool(deadpool_redis::Pool);

View file

@ -0,0 +1,214 @@
use core::time;
use rocket_db_pools::deadpool_redis::redis::{pipe, AsyncCommands};
use rocket_db_pools::Connection;
use serde::{Deserialize, Serialize};
use std::ops::Sub;
use std::time::SystemTime;
use crate::redispool::RedisPool;
#[derive(Serialize, Deserialize, Debug)]
struct VehiclesCounts {
world_id: String,
total: u32,
vehicles: Vehicles,
}
#[derive(Serialize, Deserialize, Debug)]
struct Vehicles {
flash: u32,
sunderer: u32,
lightning: u32,
scythe: u32,
vanguard: u32,
prowler: u32,
reaver: u32,
mosquito: u32,
galaxy: u32,
valkyrie: u32,
liberator: u32,
ant: u32,
harasser: u32,
dervish: u32,
chimera: u32,
javelin: u32,
corsair: u32,
}
#[get("/w/<world_id>/vehicles")]
pub async fn get_vehicles(world_id: String, mut con: Connection<RedisPool>) -> serde_json::Value {
let cache_key = format!("cache:vehicles:{}", world_id);
match con.get::<String, String>(cache_key.clone()).await {
Ok(cached) => {
return serde_json::from_str(&cached).unwrap();
}
Err(_) => {}
}
let filter_timestamp = SystemTime::now()
.sub(time::Duration::from_secs(60 * 15))
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs();
// I hate this but it's fast???
// The type only allows 12 at a time.
let (
flash,
sunderer,
lightning,
scythe,
vanguard,
prowler,
reaver,
mosquito,
galaxy,
valkyrie,
liberator,
ant,
): (u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32) = pipe()
.zcount(
format!("v:{}/{}", world_id, "flash"),
filter_timestamp,
"+inf",
)
.zcount(
format!("v:{}/{}", world_id, "sunderer"),
filter_timestamp,
"+inf",
)
.zcount(
format!("v:{}/{}", world_id, "lightning"),
filter_timestamp,
"+inf",
)
.zcount(
format!("v:{}/{}", world_id, "scythe"),
filter_timestamp,
"+inf",
)
.zcount(
format!("v:{}/{}", world_id, "vanguard"),
filter_timestamp,
"+inf",
)
.zcount(
format!("v:{}/{}", world_id, "prowler"),
filter_timestamp,
"+inf",
)
.zcount(
format!("v:{}/{}", world_id, "reaver"),
filter_timestamp,
"+inf",
)
.zcount(
format!("v:{}/{}", world_id, "mosquito"),
filter_timestamp,
"+inf",
)
.zcount(
format!("v:{}/{}", world_id, "galaxy"),
filter_timestamp,
"+inf",
)
.zcount(
format!("v:{}/{}", world_id, "valkyrie"),
filter_timestamp,
"+inf",
)
.zcount(
format!("v:{}/{}", world_id, "liberator"),
filter_timestamp,
"+inf",
)
.zcount(
format!("v:{}/{}", world_id, "ant"),
filter_timestamp,
"+inf",
)
.query_async(&mut *con)
.await
.unwrap();
let (harasser, dervish, chimera, javelin, corsair): (u32, u32, u32, u32, u32) = pipe()
.zcount(
format!("v:{}/{}", world_id, "harasser"),
filter_timestamp,
"+inf",
)
.zcount(
format!("v:{}/{}", world_id, "dervish"),
filter_timestamp,
"+inf",
)
.zcount(
format!("v:{}/{}", world_id, "chimera"),
filter_timestamp,
"+inf",
)
.zcount(
format!("v:{}/{}", world_id, "javelin"),
filter_timestamp,
"+inf",
)
.zcount(
format!("v:{}/{}", world_id, "corsair"),
filter_timestamp,
"+inf",
)
.query_async(&mut *con)
.await
.unwrap();
let total = flash
+ sunderer
+ lightning
+ scythe
+ vanguard
+ prowler
+ reaver
+ mosquito
+ galaxy
+ valkyrie
+ liberator
+ ant
+ harasser
+ dervish
+ chimera
+ javelin
+ corsair;
let response = VehiclesCounts {
world_id,
total,
vehicles: Vehicles {
flash,
sunderer,
lightning,
scythe,
vanguard,
prowler,
reaver,
mosquito,
galaxy,
valkyrie,
liberator,
ant,
harasser,
dervish,
chimera,
javelin,
corsair,
},
};
let out = json!(response);
con.set_ex::<String, String, ()>(cache_key, out.to_string(), 5)
.await
.unwrap();
out
}

View file

@ -21,7 +21,21 @@ fn cmd_prune() {
let keys: Vec<String> = con.keys("wp:*").unwrap();
for key in keys {
println!("-> Pruning {}", key);
println!("-> Pruning world pop {}", key);
let removed_items: u64 = con.zrembyscore(key, 0, prune_after).unwrap();
println!("==> Removed {} items", removed_items);
}
let keys: Vec<String> = con.keys("v:*").unwrap();
for key in keys {
println!("-> Pruning vehicle {}", key);
let removed_items: u64 = con.zrembyscore(key, 0, prune_after).unwrap();
println!("==> Removed {} items", removed_items);
}
let keys: Vec<String> = con.keys("c:*").unwrap();
for key in keys {
println!("-> Pruning class {}", key);
let removed_items: u64 = con.zrembyscore(key, 0, prune_after).unwrap();
println!("==> Removed {} items", removed_items);
}

View file

@ -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"

View 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"
}
```

View file

@ -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(),
},
});

View 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(),
}
}