Packages
statsig_elixir
0.8.4
0.20.3-beta.2607250300
0.20.3-beta.2607240300
0.20.2
0.20.2-rc.2607201629
0.20.2-beta.2607230301
0.20.2-beta.2607220301
0.20.2-beta.2607180300
0.20.2-beta.2607170300
0.20.1
0.20.1-rc.2607140134
0.20.1-rc.2607132133
0.20.1-beta.2607150300
0.20.0
0.19.9-rc.2607090505
0.19.9-rc.2607010924
0.19.9-beta.2607110300
0.19.9-beta.2607100302
0.19.9-beta.2607090302
0.19.9-beta.2607080301
0.19.9-beta.2607020303
0.19.9-beta.2607010304
0.19.9-beta.2606260304
0.19.8
0.19.7-rc.2606232103
0.19.7-beta.2606240303
0.19.7-beta.2606190306
0.19.7-beta.2606180304
0.19.6
0.19.6-rc.2606161624
0.19.6-rc.2606151903
0.19.6-beta.2606170305
0.19.6-beta.2606100304
0.19.5
0.19.5-rc.2606050349
0.19.5-beta.2606060303
0.19.4
0.19.4-rc.2605212136
0.19.3
0.19.3-beta.2604211739
0.19.2
0.19.2-rc.2604140138
0.19.2-beta.2604150312
0.19.1
0.19.1-rc.2604121707
0.19.1-beta.2604130314
0.19.1-beta.2604110309
0.19.1-beta.2604100313
0.19.0
0.18.2-rc.2604080018
0.18.2-beta.2604080312
0.18.1
0.18.1-rc.2604070138
0.18.1-beta.2604072116
0.18.0
0.17.3-rc.2603272156
0.17.3-beta.2603290312
0.17.3-beta.2603280308
0.17.3-beta.2603250310
0.17.2
0.17.2-rc.2603240138
0.17.2-beta.2603241852
0.17.1
0.17.1-rc.2603201903
0.17.1-rc.2603192323
0.17.1-beta.2603210301
0.17.1-beta.2603200305
0.17.1-beta.2603181954
0.17.0
0.16.6-rc.2603180529
0.16.6-rc.2603170138
0.16.6-beta.2603181807
0.16.5
0.16.5-rc.2603131810
0.16.5-beta.2603130304
0.16.4
0.16.4-rc.2603092140
0.16.4-beta.2603110302
0.16.4-beta.2603060304
0.16.4-beta.2603051742
0.16.4-beta.2603040814
0.16.4-beta.2603040303
0.16.3
0.16.3-rc.2602271954
0.16.3-rc.2602270324
0.16.3-rc.2602240138
0.16.3-beta.2603040747
0.16.3-beta.2603021916
0.16.3-beta.2602280254
0.16.3-beta.2602262056
0.16.3-beta.2602250307
0.16.3-beta.2602240529
0.16.2
0.16.2-rc.2602202152
0.16.2-rc.2602200042
0.16.2-beta.2602210300
0.16.2-beta.2602200305
0.16.1
0.16.1-rc.2602180406
0.16.1-beta.2602190307
0.16.0
0.15.2-rc.2602172254
0.15.2-rc.2602140111
0.15.2-rc.2602130016
0.15.2-rc.2602100139
0.15.2-rc.2602030138
0.15.2-beta.2602180309
0.15.2-beta.2602150309
0.15.2-beta.2602140304
0.15.2-beta.2602130310
0.15.2-beta.2602122245
0.15.2-beta.2602122035
0.15.2-beta.2602120040
0.15.2-beta.2602110310
0.15.2-beta.2602050305
0.15.2-beta.2602040304
0.15.2-beta.2602031515
0.15.1
0.15.1-rc.2601270136
0.15.1-beta.2601310133
0.15.1-beta.2601301825
0.15.1-beta.2601300156
0.15.1-beta.2601292313
0.15.1-beta.2601280249
0.15.0
0.14.2-rc.2601230113
0.14.2-rc.2601200136
0.14.2-rc.2601130135
0.14.2-rc.2601062017
0.14.2-rc.2512230135
0.14.2-beta.2601262335
0.14.2-beta.2601240243
0.14.2-beta.2601230247
0.14.2-beta.2601220251
0.14.2-beta.2601210246
0.14.2-beta.2601170240
0.14.2-beta.2601160247
0.14.2-beta.2601140250
0.14.2-beta.2601130116
0.14.2-beta.2601100241
0.14.2-beta.2601070246
0.14.2-beta.2512310244
0.14.2-beta.2512240241
0.14.1
0.14.1-rc.2512190311
0.14.1-rc.2512162207
0.14.1-rc.2512160223
0.14.1-beta.2512200239
0.14.1-beta.2512190242
0.14.1-beta.2512170241
0.14.0
0.13.1-beta.2512140246
0.13.1-beta.2512130201
0.13.1-beta.2512120242
0.13.1-beta.2512110242
0.13.1-beta.2512110007
0.13.1-beta.2512102250
0.13.1-beta.2512102139
0.13.1-beta.2512100241
0.13.1-beta.2512051931
0.13.1-beta.2512050240
0.12.1
0.12.1-rc.2511121816
0.12.1-rc.2511110014
0.12.1-beta.2511110238
0.12.0
0.11.2-rc.2511040014
0.11.2-beta.2511050238
0.11.2-beta.2511032240
0.11.2-beta.2511032212
0.11.2-beta.2511030239
0.11.2-beta.2510310237
0.11.1
0.11.1-rc.2510292219
0.11.1-rc.2510280013
0.11.1-beta.2510300237
0.11.1-beta.2510290239
0.11.0
0.10.3-rc.2510210409
0.10.3-rc.2510210014
0.10.3-rc.6
0.10.3-beta.2510250234
0.10.3-beta.2510240234
0.10.3-beta.2510230235
0.10.3-beta.2510220237
0.10.2
0.10.2-rc.2510141845
0.10.2-beta.2510180231
0.10.2-beta.2510172041
0.10.2-beta.2510170235
0.10.2-beta.2510160235
0.10.2-beta.2510152259
0.10.2-beta.2510152125
0.10.2-beta.2510151849
0.10.2-beta.2510150236
0.10.2-beta.2510142155
0.10.2-beta.2510142023
0.10.1
0.10.0
0.10.0-rc.2510090432
0.10.0-rc.2510070136
0.10.0-beta.2510120235
0.10.0-beta.2510102126
0.10.0-beta.2510100234
0.10.0-beta.2510090234
0.10.0-beta.2510072144
0.9.6-beta.2510020232
0.9.5-rc.2510030411
0.9.5-rc.2510020138
0.9.5-beta.2510010238
0.9.4-rc.2509300113
0.9.4-beta.2509252256
0.9.3
0.9.3-beta.2509250234
0.9.3-beta.2509240232
0.9.3-beta.2509231844
0.9.2-rc.2509221315
0.9.2-beta.2509190233
0.9.2-beta.2509180233
0.9.2-beta.2509180231
0.9.2-beta.2509170231
0.9.1
0.9.1-rc.2509190115
0.9.1-rc.2509181925
0.9.1-rc.2509171909
0.9.0-rc.1
0.8.9-beta.2509161804
0.8.9-beta.2509160231
0.8.8-beta.2509130225
0.8.8-beta.2509112152
0.8.8-beta.2509112049
0.8.8-beta.2509110233
0.8.7
0.8.7-rc.2509102057
0.8.7-rc.2509102017
0.8.7-rc.2509100003
0.8.7-rc.2509092342
0.8.7-beta.2509092208
0.8.6
0.8.6-rc.2509082013
0.8.6-beta.2509040231
0.8.6-beta.2509020235
0.8.5
0.8.5-beta.2508300230
0.8.4
0.8.3
0.8.3-beta.2508280233
0.8.2
0.8.2-rc.2508282224
0.8.1
0.8.1-rc.2508271913
0.8.1-rc.2508262341
0.8.1-rc.2508251314
0.8.0
0.7.4-rc.2508222145
0.7.4-rc.2508220107
0.7.4-rc.2508220104
0.7.4-rc.2508220101
0.7.4-rc.2508220057
0.7.4-rc.2508220049
0.7.4-rc.2508220046
0.7.4-rc.2508220041
0.7.4-rc.2508220033
0.7.4-rc.2508220032
0.7.4-rc.2508220027
0.7.4-rc.2508220022
0.7.4-rc.2508220017
0.7.4-rc.2508220010
0.7.4-rc.2508220006
0.7.4-rc.2508220000
0.7.4-rc.2508212357
0.7.4-rc.2508212349
0.7.4-rc.2508202203
0.7.4-rc.2508202034
0.7.4-rc.2508191829
0.7.4-beta.2508220235
0.7.4-beta.2508210235
0.7.4-beta.2508200235
0.7.4-beta.2508190236
0.7.4-beta.2508160236
0.7.4-beta.2508150240
0.0.6-beta.7
0.0.6-beta.6
0.0.2
retired
0.0.1
retired
A performant elixir SDK for Statsig feature gates and experiments using Rustler
Current section
Files
Jump to
Current section
Files
native/statsig_elixir/src/statsig_nfi.rs
use rustler::{Env, Error, ResourceArc, Term};
use statsig_rust::{
statsig_metadata::StatsigMetadata, statsig_types::Layer as LayerActual, Statsig,
};
use std::{
collections::HashMap,
sync::{Arc, RwLock},
};
use crate::{
statsig_options_nfi::StatsigOptions,
statsig_types_nfi::{
AllowedPrimitive, ClientInitResponseOptions, DynamicConfig, DynamicConfigEvaluationOptions,
Experiment, ExperimentEvaluationOptions, FeatureGate, FeatureGateEvaluationOptions,
LayerEvaluationOptions,
},
statsig_user_nfi::StatsigUser,
};
use serde_json::Value;
struct StatsigResource {
pub statsig_core: RwLock<Arc<Statsig>>,
}
#[allow(non_local_definitions)]
fn load(env: Env, _: Term) -> bool {
_ = rustler::resource!(StatsigResource, env);
_ = rustler::resource!(LayerResource, env);
true
}
pub struct LayerResource {
pub core: RwLock<Arc<LayerActual>>,
}
impl LayerResource {
pub fn new(layer: LayerActual) -> Self {
LayerResource {
core: RwLock::new(Arc::new(layer)),
}
}
}
#[rustler::nif(schedule = "DirtyCpu")]
pub fn new(
sdk_key: String,
options: Option<StatsigOptions>,
system_metadata: HashMap<String, String>,
) -> Result<ResourceArc<StatsigResource>, Error> {
update_metadata(system_metadata);
let statsig = Statsig::new(&sdk_key, options.map(|op| Arc::new(op.into())));
Ok(ResourceArc::new(StatsigResource {
statsig_core: RwLock::new(Arc::new(statsig)),
}))
}
#[rustler::nif]
pub fn initialize(statsig: ResourceArc<StatsigResource>) -> Result<(), Error> {
match statsig.statsig_core.read() {
Ok(read) => {
let statsig: Arc<Statsig> = Arc::clone(&read);
let rt_handle = match statsig.statsig_runtime.get_handle() {
Ok(handle) => handle,
Err(_) => return Err(Error::RaiseAtom("Failed to get Statsig")),
};
match rt_handle.block_on(statsig.initialize()) {
Ok(_) => Ok(()),
Err(_) => Err(Error::RaiseAtom("failed to init")),
}
}
Err(_) => Err(Error::RaiseAtom("failed to init")),
}
}
#[rustler::nif]
pub fn get_feature_gate(
statsig: ResourceArc<StatsigResource>,
gate_name: &str,
statsig_user: StatsigUser,
options: Option<FeatureGateEvaluationOptions>,
) -> Result<FeatureGate, Error> {
match statsig.statsig_core.read() {
Ok(read_guard) => Ok(read_guard
.get_feature_gate_with_options(
&statsig_user.into(),
gate_name,
options.map(|o| o.into()).unwrap_or_default(),
)
.into()),
Err(_) => Err(Error::RaiseAtom("Failed to get Statsig")),
}
}
#[rustler::nif]
pub fn check_gate(
statsig: ResourceArc<StatsigResource>,
gate_name: &str,
statsig_user: StatsigUser,
options: Option<FeatureGateEvaluationOptions>,
) -> Result<bool, Error> {
match statsig.statsig_core.read() {
Ok(read_guard) => Ok(read_guard.check_gate_with_options(
&statsig_user.into(),
gate_name,
options.map(|o| o.into()).unwrap_or_default(),
)),
Err(_) => Err(Error::RaiseAtom("Failed to get Statsig")),
}
}
#[rustler::nif]
pub fn get_dynamic_config(
statsig: ResourceArc<StatsigResource>,
config_name: &str,
statsig_user: StatsigUser,
options: Option<DynamicConfigEvaluationOptions>,
) -> Result<DynamicConfig, Error> {
match statsig.statsig_core.read() {
Ok(read_guard) => Ok(read_guard
.get_dynamic_config_with_options(
&statsig_user.into(),
config_name,
options.map(|o| o.into()).unwrap_or_default(),
)
.into()),
Err(_) => Err(Error::RaiseAtom("Failed to get Statsig")),
}
}
#[rustler::nif]
pub fn get_experiment(
statsig: ResourceArc<StatsigResource>,
experiment_name: &str,
statsig_user: StatsigUser,
options: Option<ExperimentEvaluationOptions>,
) -> Result<Experiment, Error> {
match statsig.statsig_core.read() {
Ok(read_guard) => Ok(read_guard
.get_experiment_with_options(
&statsig_user.into(),
experiment_name,
options.map(|o| o.into()).unwrap_or_default(),
)
.into()),
Err(_) => Err(Error::RaiseAtom("Failed to get Statsig")),
}
}
#[rustler::nif]
pub fn get_layer(
statsig: ResourceArc<StatsigResource>,
layer_name: &str,
statsig_user: StatsigUser,
options: Option<LayerEvaluationOptions>,
) -> Result<ResourceArc<LayerResource>, Error> {
match statsig.statsig_core.read() {
Ok(read_guard) => {
let layer = read_guard.get_layer_with_options(
&statsig_user.into(),
layer_name,
options.map(|o| o.into()).unwrap_or_default(),
);
Ok(ResourceArc::new(LayerResource::new(layer)))
}
Err(_) => Err(Error::RaiseAtom("Failed to get Statsig")),
}
}
#[rustler::nif]
pub fn get_prompt(
statsig: ResourceArc<StatsigResource>,
prompt_name: &str,
statsig_user: StatsigUser,
options: Option<LayerEvaluationOptions>,
) -> Result<ResourceArc<LayerResource>, Error> {
match statsig.statsig_core.read() {
Ok(read_guard) => {
let layer = read_guard.get_prompt_with_options(
&statsig_user.into(),
prompt_name,
options.map(|o| o.into()).unwrap_or_default(),
);
Ok(ResourceArc::new(LayerResource::new(layer)))
}
Err(_) => Err(Error::RaiseAtom("Failed to get Statsig")),
}
}
#[rustler::nif]
pub fn log_event(
statsig: ResourceArc<StatsigResource>,
statsig_user: StatsigUser,
event_name: &str,
value: Option<&str>,
metadata: Option<HashMap<String, String>>,
) -> Result<(), Error> {
match statsig.statsig_core.read() {
Ok(read_guard) => {
read_guard.log_event(
&statsig_user.into(),
event_name,
value.map(|v| v.to_string()),
metadata,
);
Ok(())
}
Err(_) => Err(Error::RaiseAtom("Failed to get Statsig")),
}
}
#[rustler::nif]
pub fn log_event_with_number(
statsig: ResourceArc<StatsigResource>,
statsig_user: StatsigUser,
event_name: &str,
value: Option<f64>,
metadata: Option<HashMap<String, String>>,
) -> Result<(), Error> {
match statsig.statsig_core.read() {
Ok(read_guard) => {
read_guard.log_event_with_number(&statsig_user.into(), event_name, value, metadata);
Ok(())
}
Err(_) => Err(Error::RaiseAtom("Failed to get Statsig")),
}
}
#[rustler::nif(schedule = "DirtyCpu")]
pub fn get_client_init_response_as_string(
statsig: ResourceArc<StatsigResource>,
statsig_user: StatsigUser,
options: Option<ClientInitResponseOptions>,
) -> Result<String, Error> {
match statsig.statsig_core.read() {
Ok(read_guard) => {
let response = match options {
Some(o) => read_guard.get_client_init_response_with_options_as_string(
&statsig_user.into(),
&o.into(),
),
None => read_guard.get_client_init_response_as_string(&statsig_user.into()),
};
Ok(response)
}
Err(_) => Err(Error::RaiseAtom("Failed to get Statsig")),
}
}
#[rustler::nif(schedule = "DirtyIo")]
pub fn flush(statsig: ResourceArc<StatsigResource>) -> Result<(), Error> {
match statsig.statsig_core.read() {
Ok(read_guard) => {
let statsig: Arc<Statsig> = Arc::clone(&read_guard);
let rt_handle = match statsig.statsig_runtime.get_handle() {
Ok(handle) => handle,
Err(_) => return Err(Error::RaiseAtom("Failed to get Statsig")),
};
rt_handle.block_on(async move { statsig.flush_events().await });
Ok(())
}
Err(_) => Err(Error::RaiseAtom("Failed to get Statsig")),
}
}
#[rustler::nif]
pub fn shutdown(statsig: ResourceArc<StatsigResource>) -> Result<(), Error> {
match statsig.statsig_core.read() {
Ok(read_guard) => {
let statsig: Arc<Statsig> = Arc::clone(&read_guard);
let rt_handle = match statsig.statsig_runtime.get_handle() {
Ok(handle) => handle,
Err(_) => return Err(Error::RaiseAtom("Failed to get Statsig")),
};
rt_handle.block_on(async move {
match statsig.shutdown().await {
Ok(_) => Ok(()),
Err(_) => Err(Error::RaiseAtom("Failed to shutdown")),
}
})
}
Err(_) => Err(Error::RaiseAtom("Failed to get Statsig")),
}
}
// Layer NFI
#[rustler::nif]
pub fn layer_get(
layer: ResourceArc<LayerResource>,
param_name: &str,
default: AllowedPrimitive,
) -> Result<AllowedPrimitive, Error> {
match layer.core.read() {
Ok(layer) => match default.clone() {
AllowedPrimitive::Int(i) => Ok(AllowedPrimitive::Int(layer.get_i64(param_name, i))),
AllowedPrimitive::Float(f) => Ok(AllowedPrimitive::Float(layer.get_f64(param_name, f))),
AllowedPrimitive::Bool(b) => Ok(AllowedPrimitive::Bool(layer.get_bool(param_name, b))),
AllowedPrimitive::Str(_) => match layer.get_raw_value(param_name) {
Some(json_value) => {
let res = match json_value {
Value::String(s) => s.to_owned(),
_ => json_value.to_string(),
};
Ok(AllowedPrimitive::Str(res))
}
None => Ok(default),
},
},
Err(_) => Err(Error::RaiseAtom("Failed to get Statsig")),
}
}
#[rustler::nif]
pub fn layer_get_rule_id(layer: ResourceArc<LayerResource>) -> Result<String, Error> {
match layer.core.read() {
Ok(read_guard) => Ok(read_guard.rule_id.clone()),
Err(_) => Err(Error::RaiseAtom("Failed to get Statsig")),
}
}
#[rustler::nif]
pub fn layer_get_group_name(layer: ResourceArc<LayerResource>) -> Result<Option<String>, Error> {
println!("get group name");
match layer.core.read() {
Ok(read_guard) => Ok(read_guard.group_name.clone()),
Err(_) => Err(Error::RaiseAtom("Failed to get Statsig")),
}
}
// Util Functions
fn update_metadata(system_metadata: HashMap<String, String>) {
let unknown = "unknown".to_string();
let os = system_metadata.get("os").unwrap_or(&unknown);
let arch = system_metadata.get("arch").unwrap_or(&unknown);
let language_version = system_metadata.get("language_version").unwrap_or(&unknown);
StatsigMetadata::update_values(
"statsig-server-core-elixir".to_owned(),
os.to_string(),
arch.to_string(),
language_version.to_string(),
);
}
rustler::init!("Elixir.Statsig.NativeBindings", load = load);