Skip to content

Commit

Permalink
feat: add querying capability to js bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
dankotov committed Sep 12, 2024
1 parent 50d30e2 commit ddd568e
Showing 1 changed file with 116 additions and 0 deletions.
116 changes: 116 additions & 0 deletions src/node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use ahash::AHashMap;
use memmap2::MmapOptions;
use napi::bindgen_prelude::*;
use napi::Either;
use napi::JsBigInt;
use napi::JsUnknown;
use parser::first_pass::parser_settings::rm_map_user_friendly_names;
use parser::first_pass::parser_settings::rm_user_friendly_names;
use parser::first_pass::parser_settings::ParserInputs;
use parser::parse_demo::DemoOutput;
Expand All @@ -14,13 +17,100 @@ use parser::second_pass::parser_settings::create_huffman_lookup_table;
use parser::second_pass::variants::soa_to_aos;
use parser::second_pass::variants::BytesVariant;
use parser::second_pass::variants::OutputSerdeHelperStruct;
use parser::second_pass::variants::Variant;
use parser::second_pass::voice_data::convert_voice_data_to_wav;
use serde_json::Value;
use std::collections::HashMap;
use std::fs::File;
use std::hash::RandomState;
use std::result::Result;

#[napi]
#[derive(Clone)]
pub struct JsVariant(Variant);

impl FromNapiValue for JsVariant {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> napi::Result<Self> {
let js_unknown = JsUnknown::from_napi_value(env, napi_val)?;

match js_unknown.get_type() {
Ok(js_unknown_type) => {
if js_unknown_type == ValueType::Boolean {
if let Ok(val) = js_unknown.coerce_to_bool() {
Ok(JsVariant(Variant::Bool(val.get_value()?)))
} else {
Err(Error::new(
Status::InvalidArg,
"Unspported Boolean type for Variant".to_owned(),
))
}
} else if js_unknown_type == ValueType::String {
if let Ok(val) = js_unknown.coerce_to_string() {
Ok(JsVariant(Variant::String(val.into_utf8()?.into_owned()?)))
} else {
Err(Error::new(
Status::InvalidArg,
"Unsupported String for Variant".to_owned(),
))
}
} else if js_unknown_type == ValueType::Number {
if let Ok(val) = js_unknown.coerce_to_number() {
let num = val.get_double()?;
if num.fract() == 0.0 {
if let Ok(val) = val.get_uint32() {
Ok(JsVariant(Variant::U32(val)))
} else if let Ok(val) = val.get_int32() {
let int32_val = val;
if int32_val >= i16::MIN as i32 && int32_val <= i16::MAX as i32 {
Ok(JsVariant(Variant::I16(int32_val as i16)))
} else {
Ok(JsVariant(Variant::I32(int32_val)))
}
} else {
Err(Error::new(
Status::InvalidArg,
"Unsupported number type".to_owned(),
))
}
} else {
Ok(JsVariant(Variant::F32(num as f32)))
}
} else {
Err(Error::new(
Status::InvalidArg,
"Unsupported number type".to_owned(),
))
}
} else if js_unknown_type == ValueType::BigInt {
let bigint_val = js_unknown.cast::<JsBigInt>();
match bigint_val.get_u64() {
Ok((val, true)) => Ok(JsVariant(Variant::U64(val))),
_ => Err(Error::new(
Status::InvalidArg,
"Unsupported number type".to_owned(),
)),
}
} else {
Err(Error::new(
Status::InvalidArg,
"Unspported type for Variant".to_owned(),
))
}
}
_ => Err(Error::new(
Status::InvalidArg,
"Unspported type for Variant".to_owned(),
)),
}
}
}

#[napi]
pub struct WantedPropState {
pub prop: String,
pub state: JsVariant,
}

fn parse_demo(bytes: BytesVariant, parser: &mut Parser) -> Result<DemoOutput, Error> {
match bytes {
BytesVariant::Mmap(m) => match parser.parse_demo(&m) {
Expand All @@ -42,6 +132,7 @@ pub fn parse_voice(path_or_buf: Either<String, Buffer>) -> napi::Result<HashMap<
wanted_other_props: vec![],
wanted_events: vec![],
wanted_ticks: vec![],
wanted_prop_states: AHashMap::default(),
real_name_to_og_name: AHashMap::default(),
parse_ents: false,
parse_projectiles: false,
Expand Down Expand Up @@ -74,6 +165,7 @@ pub fn list_game_events(path_or_buf: Either<String, Buffer>) -> napi::Result<Val
real_name_to_og_name: AHashMap::default(),
wanted_player_props: vec![],
wanted_other_props: vec![],
wanted_prop_states: AHashMap::default(),
wanted_events: vec!["all".to_string()],
parse_ents: false,
wanted_ticks: vec![],
Expand Down Expand Up @@ -106,6 +198,7 @@ pub fn parse_grenades(path_or_buf: Either<String, Buffer>) -> napi::Result<Value
wanted_player_props: vec![],
wanted_other_props: vec![],
wanted_events: vec![],
wanted_prop_states: AHashMap::default(),
parse_ents: true,
wanted_ticks: vec![],
parse_projectiles: true,
Expand Down Expand Up @@ -134,6 +227,7 @@ pub fn parse_header(path_or_buf: Either<String, Buffer>) -> napi::Result<Value>
wanted_players: vec![],
wanted_player_props: vec![],
wanted_other_props: vec![],
wanted_prop_states: AHashMap::default(),
wanted_events: vec![],
parse_ents: false,
wanted_ticks: vec![],
Expand Down Expand Up @@ -198,6 +292,7 @@ pub fn parse_event(
wanted_players: vec![],
wanted_player_props: real_names_player.clone(),
wanted_other_props: real_other_props,
wanted_prop_states: AHashMap::default(),
wanted_events: vec![event_name],
parse_ents: true,
wanted_ticks: vec![],
Expand Down Expand Up @@ -260,6 +355,7 @@ pub fn parse_events(
wanted_players: vec![],
wanted_player_props: real_names_player.clone(),
wanted_other_props: real_other_props.clone(),
wanted_prop_states: AHashMap::default(),
wanted_events: event_names,
parse_ents: true,
wanted_ticks: vec![],
Expand All @@ -285,6 +381,7 @@ pub fn parse_ticks(
wanted_props: Vec<String>,
wanted_ticks: Option<Vec<i32>>,
wanted_players: Option<Vec<String>>,
prop_states: Option<Vec<&WantedPropState>>,
struct_of_arrays: Option<bool>,
order_by_steamid: Option<bool>,
) -> napi::Result<Value> {
Expand All @@ -296,6 +393,16 @@ pub fn parse_ticks(
Some(v) => v.iter().map(|x| x.parse::<u64>().unwrap_or(0)).collect(),
None => vec![],
};
let wanted_prop_states: AHashMap<String, Variant> = prop_states
.unwrap_or_default()
.into_iter()
.map(|prop| (prop.prop.clone(), prop.state.0.clone()))
.collect();
let real_wanted_prop_states = rm_map_user_friendly_names(&wanted_prop_states);
let real_wanted_prop_states = match real_wanted_prop_states {
Ok(real_wanted_prop_states) => real_wanted_prop_states,
Err(e) => return Err(Error::new(Status::InvalidArg, format!("{}", e).to_owned())),
};

let bytes = resolve_byte_type(path_or_buf)?;
let huf = create_huffman_lookup_table();
Expand All @@ -304,6 +411,12 @@ pub fn parse_ticks(
for (real_name, user_friendly_name) in real_names.iter().zip(&wanted_props) {
real_name_to_og_name.insert(real_name.clone(), user_friendly_name.clone());
}
for (real_name, user_friendly_name) in real_wanted_prop_states
.keys()
.zip(wanted_prop_states.keys())
{
real_name_to_og_name.insert(real_name.clone(), user_friendly_name.clone());
}

let wanted_ticks = match wanted_ticks {
Some(t) => t,
Expand All @@ -320,6 +433,7 @@ pub fn parse_ticks(
wanted_player_props: real_names.clone(),
wanted_other_props: vec![],
wanted_events: vec![],
wanted_prop_states: real_wanted_prop_states,
parse_ents: true,
wanted_ticks: wanted_ticks,
parse_projectiles: false,
Expand Down Expand Up @@ -391,6 +505,7 @@ pub fn parse_player_info(path_or_buf: Either<String, Buffer>) -> napi::Result<Va
real_name_to_og_name: AHashMap::default(),
wanted_player_props: vec![],
wanted_other_props: vec![],
wanted_prop_states: AHashMap::default(),
wanted_events: vec![],
parse_ents: false,
wanted_ticks: vec![],
Expand Down Expand Up @@ -420,6 +535,7 @@ pub fn parse_player_skins(path_or_buf: Either<String, Buffer>) -> napi::Result<V
real_name_to_og_name: AHashMap::default(),
wanted_player_props: vec![],
wanted_other_props: vec![],
wanted_prop_states: AHashMap::default(),
wanted_events: vec![],
parse_ents: true,
wanted_ticks: vec![],
Expand Down

0 comments on commit ddd568e

Please sign in to comment.