use std::collections::HashMap;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Mutex, OnceLock};
use super::jsonfmt::{Json, JsonObject};
static TRACES: AtomicU64 = AtomicU64::new(0);
static CONTEXTS: AtomicU64 = AtomicU64::new(0);
static PAGES: AtomicU64 = AtomicU64::new(0);
fn registry() -> &'static Mutex<HashMap<(&'static str, usize), String>> {
static ASSIGNED: OnceLock<Mutex<HashMap<(&'static str, usize), String>>> = OnceLock::new();
ASSIGNED.get_or_init(|| Mutex::new(HashMap::new()))
}
fn identify(kind: &'static str, counter: &AtomicU64, key: Option<usize>) -> String {
let fresh = || format!("{kind}-{}", counter.fetch_add(1, Ordering::SeqCst) + 1);
let Some(key) = key else {
return fresh();
};
let mut assigned = registry()
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner());
assigned.entry((kind, key)).or_insert_with(fresh).clone()
}
#[doc(hidden)]
pub fn reset_trace_identity_counters() {
TRACES.store(0, Ordering::SeqCst);
CONTEXTS.store(0, Ordering::SeqCst);
PAGES.store(0, Ordering::SeqCst);
registry()
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner())
.clear();
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TraceIdentity {
pub trace_id: String,
pub browser_context_id: Option<String>,
pub page_id: String,
navigation: u64,
actions: u64,
}
impl TraceIdentity {
pub fn new(context_key: Option<usize>, page_key: Option<usize>, has_context: bool) -> Self {
let trace_id = format!("trace-{}", TRACES.fetch_add(1, Ordering::SeqCst) + 1);
let browser_context_id = has_context.then(|| identify("context", &CONTEXTS, context_key));
let page_id = identify("page", &PAGES, page_key);
Self {
trace_id,
browser_context_id,
page_id,
navigation: 1,
actions: 0,
}
}
pub fn navigation_id(&self) -> String {
format!("nav-{}", self.navigation)
}
pub fn navigated(&mut self) -> String {
self.navigation += 1;
self.navigation_id()
}
pub fn next_action_id(&mut self) -> String {
self.actions += 1;
format!("{}-action-{}", self.trace_id, self.actions)
}
pub fn owner(&self) -> JsonObject {
JsonObject::new()
.with("traceId", self.trace_id.as_str())
.with(
"browserContextId",
Json::from(self.browser_context_id.clone()),
)
.with("pageId", self.page_id.as_str())
.with("navigationId", self.navigation_id())
}
}