use firebase instead of mixpanel in for event tracking

This commit is contained in:
Diego Prats 2024-11-08 08:38:56 -08:00
parent f7fe621554
commit 630b10ed24
3 changed files with 92 additions and 16 deletions

View File

@ -1567,7 +1567,7 @@ dependencies = [
[[package]] [[package]]
name = "nexus-network" name = "nexus-network"
version = "0.1.0" version = "0.3.2"
dependencies = [ dependencies = [
"ark-bn254", "ark-bn254",
"ark-crypto-primitives", "ark-crypto-primitives",

View File

@ -1,4 +1,4 @@
use crate::config::analytics_token; use crate::config::{analytics_token, analytics_api_secret};
use chrono::Datelike; use chrono::Datelike;
use chrono::Timelike; use chrono::Timelike;
use reqwest::header::{ACCEPT, CONTENT_TYPE}; use reqwest::header::{ACCEPT, CONTENT_TYPE};
@ -16,14 +16,27 @@ pub fn track(
) { ) {
println!("{}", description); println!("{}", description);
let token = analytics_token(ws_addr_string); let firebase_app_id = analytics_token(ws_addr_string);
if token.is_empty() { let firebase_api_secret = analytics_api_secret(ws_addr_string);
if firebase_app_id.is_empty() {
return; return;
} }
let local_now = chrono::offset::Local::now(); let local_now = chrono::offset::Local::now();
// For tracking events, we use the Firebase Measurement Protocol
// Firebase is mostly designed for mobile and web apps, but for our use case of a CLI,
// we can use the Measurement Protocol to track events by POST to a URL.
// The only thing that may be unexpected is that the URL we use includes a firebase secret (something we dont typically add to client code)
// Firebase format for properties for Mesurement protocol:
// https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference?client_type=firebase#payload
// https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference?client_type=firebase#payload_query_parameters
let mut properties = json!({ let mut properties = json!({
"token": token,
"time": SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis(), "time": SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis(),
// app_instance_id is the standard key Firebase uses this key to track the same user across sessions
// its is a bit redundant, but I wanted to keep the recommended format Firebase uses to minimize surprises
// I still left the distinct_id key as well for backwards compatibility
"app_instance_id": event_properties["prover_id"],
"distinct_id": event_properties["prover_id"], "distinct_id": event_properties["prover_id"],
"prover_type": "volunteer", "prover_type": "volunteer",
"client_type": "cli", "client_type": "cli",
@ -36,14 +49,26 @@ pub fn track(
for (k, v) in event_properties.as_object().unwrap() { for (k, v) in event_properties.as_object().unwrap() {
properties[k] = v.clone(); properties[k] = v.clone();
} }
// Firebase format for events
let body = json!({ let body = json!({
"event": event_name, "app_instance_id": event_properties["prover_id"],
"properties": properties "events": [{
"name": event_name,
"params": properties
}],
}); });
tokio::spawn(async move { tokio::spawn(async move {
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let _ = client let _ = client
.post("https://api.mixpanel.com/track?ip=1") //URL is the google analytics endpoint for firebase: https://stackoverflow.com/questions/50355752/firebase-analytics-from-remote-rest-api
.post(format!(
"https://www.google-analytics.com/mp/collect?firebase_app_id={}&api_secret={}",
firebase_app_id,
firebase_api_secret
))
.body(format!("[{}]", body.to_string())) .body(format!("[{}]", body.to_string()))
.header(ACCEPT, "text/plain") .header(ACCEPT, "text/plain")
.header(CONTENT_TYPE, "application/json") .header(CONTENT_TYPE, "application/json")

View File

@ -1,18 +1,69 @@
// This version is ONLY compiled when running in debug mode
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
pub fn analytics_token(_ws_addr_string: &str) -> String { pub fn analytics_token(_ws_addr_string: &str) -> String {
// Use one of the tokens in the release version if debugging analytics // Use one of the tokens in the release version if debugging analytics
return "".into(); return "".into();
} }
// The following enum is used to determine the environment from the web socket string
#[derive(Debug)]
#[cfg(not(debug_assertions))]
enum Environment {
Dev,
Staging,
Beta,
Unknown,
}
// The web socket addresses for the different environments
#[cfg(not(debug_assertions))]
mod web_socket_urls {
pub const DEV: &str = "wss://dev.orchestrator.nexus.xyz:443/";
pub const STAGING: &str = "wss://staging.orchestrator.nexus.xyz:443/";
pub const BETA: &str = "wss://beta.orchestrator.nexus.xyz:443/";
}
// the firebase APP IDS by environment
#[cfg(not(debug_assertions))]
mod firebase {
pub const DEV_APP_ID: &str = "1:954530464230:web:f0a14de14ef7bcdaa99627";
pub const STAGING_APP_ID: &str = "1:222794630996:web:1758d64a85eba687eaaac1";
pub const BETA_APP_ID: &str = "1:279395003658:web:04ee2c524474d683d75ef3";
// DUMMY VALUES FOR DEBUGGING, NOT REAL API SECRETS
pub const DEV_API_SECRET: &str = "85858585858585858585858585858585";
pub const STAGING_API_SECRET: &str = "85858585858585858585858585858585";
pub const BETA_API_SECRET: &str = "85858585858585858585858585858585";
}
// // This version is ONLY compiled when running in release mode
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
pub fn analytics_token(ws_addr_string: &str) -> String { pub fn analytics_token(ws_addr_string: &str) -> String {
if ws_addr_string.starts_with("wss://dev.orchestrator.nexus.xyz:443/") {
return "".into(); // TODO: Firebase Analytics tid // Determine the environment from the web socket string (ws_addr_string)
} else if ws_addr_string.starts_with("wss://staging.orchestrator.nexus.xyz:443/") { let env = match ws_addr_string {
return "".into(); // TODO: Firebase Analytics tid web_socket_urls::DEV => Environment::Dev,
} else if ws_addr_string.starts_with("wss://beta.orchestrator.nexus.xyz:443/") { web_socket_urls::STAGING => Environment::Staging,
return "".into(); // TODO: Firebase Analytics tid web_socket_urls::BETA => Environment::Beta,
} else { _ => Environment::Unknown,
return "".into();
}; };
// Return the appropriate Firebase App ID based on the environment
match env {
Environment::Dev => firebase::DEV_APP_ID.to_string(),
Environment::Staging => firebase::STAGING_APP_ID.to_string(),
Environment::Beta => firebase::BETA_APP_ID.to_string(),
Environment::Unknown => String::new(),
}
} }
#[cfg(not(debug_assertions))]
pub fn analytics_api_secret(ws_addr_string: &str) -> String {
match ws_addr_string {
web_socket_urls::DEV => firebase::DEV_API_SECRET.to_string(),
web_socket_urls::STAGING => firebase::STAGING_API_SECRET.to_string(),
web_socket_urls::BETA => firebase::BETA_API_SECRET.to_string(),
_ => String::new(),
}
}