use crate::state::{get_or_init_state, StoredObject};
use crate::streaming::{
StreamingAlgorithm, StreamingDfgBuilder, StreamingHeuristicBuilder, StreamingSkeletonBuilder,
};
use crate::utilities::to_js_str;
use serde_json::json;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn streaming_dfg_begin() -> Result<JsValue, JsValue> {
let handle = get_or_init_state()
.store_object(StoredObject::StreamingDfgBuilder(StreamingDfgBuilder::new()))?;
Ok(crate::error::js_val(&handle))
}
#[wasm_bindgen]
pub fn streaming_dfg_add_event(
handle: &str,
case_id: &str,
activity: &str,
) -> Result<JsValue, JsValue> {
get_or_init_state().with_streaming_dfg_mut(handle, |b| {
b.add_event(case_id, activity);
to_js_str(&json!({
"ok": true,
"event_count": b.event_count,
"open_traces": b.open_traces.len(),
"activities": b.interner.len(),
}))
})
}
#[wasm_bindgen]
pub fn streaming_dfg_add_batch(handle: &str, events_json: &str) -> Result<JsValue, JsValue> {
let batch: Vec<serde_json::Value> = serde_json::from_str(events_json)
.map_err(|e| crate::error::js_val(&format!("Invalid events JSON: {}", e)))?;
get_or_init_state().with_streaming_dfg_mut(handle, |b| {
let mut added = 0usize;
for item in &batch {
let case_id = item["case_id"].as_str().ok_or_else(|| {
crate::error::js_val("Each event must have a 'case_id' string field")
})?;
let activity = item["activity"].as_str().ok_or_else(|| {
crate::error::js_val("Each event must have an 'activity' string field")
})?;
b.add_event(case_id, activity);
added += 1;
}
to_js_str(&json!({
"ok": true,
"added": added,
"event_count": b.event_count,
"open_traces": b.open_traces.len(),
"activities": b.interner.len(),
}))
})
}
#[wasm_bindgen]
pub fn streaming_dfg_close_trace(handle: &str, case_id: &str) -> Result<JsValue, JsValue> {
get_or_init_state().with_streaming_dfg_mut(handle, |b| {
let closed = b.close_trace(case_id);
to_js_str(&json!({
"ok": closed,
"trace_count": b.trace_count,
"open_traces": b.open_traces.len(),
}))
})
}
#[wasm_bindgen]
pub fn streaming_dfg_flush_open(handle: &str) -> Result<JsValue, JsValue> {
get_or_init_state().with_streaming_dfg_mut(handle, |b| {
let case_ids: Vec<String> = b.open_traces.keys().cloned().collect();
let flushed = case_ids.len();
for id in case_ids {
b.close_trace(&id);
}
to_js_str(&json!({
"ok": true,
"flushed": flushed,
"trace_count": b.trace_count,
}))
})
}
#[wasm_bindgen]
pub fn streaming_dfg_snapshot(handle: &str) -> Result<JsValue, JsValue> {
get_or_init_state().with_streaming_dfg(handle, |b| {
let dfg = b.snapshot();
to_js_str(&dfg)
})
}
#[wasm_bindgen]
pub fn streaming_dfg_finalize(handle: &str) -> Result<JsValue, JsValue> {
let dfg = get_or_init_state().with_streaming_dfg_mut(handle, |b| {
let case_ids: Vec<String> = b.open_traces.keys().cloned().collect();
for id in case_ids {
b.close_trace(&id);
}
Ok(b.snapshot())
})?;
let n_nodes = dfg.nodes.len();
let n_edges = dfg.edges.len();
let dfg_handle = get_or_init_state()
.store_object(StoredObject::DFG(dfg))
.map_err(|_| crate::error::js_val("Failed to store DFG"))?;
get_or_init_state().delete_object(handle)?;
to_js_str(&json!({
"dfg_handle": dfg_handle,
"nodes": n_nodes,
"edges": n_edges,
}))
}
#[wasm_bindgen]
pub fn streaming_dfg_stats(handle: &str) -> Result<JsValue, JsValue> {
get_or_init_state().with_streaming_dfg(handle, |b| {
let stats = b.stats();
to_js_str(&stats)
})
}
#[wasm_bindgen]
pub fn streaming_skeleton_begin(min_frequency: usize) -> Result<JsValue, JsValue> {
let builder = StreamingSkeletonBuilder::with_min_frequency(min_frequency);
let handle =
get_or_init_state().store_object(StoredObject::StreamingSkeletonBuilder(builder))?;
Ok(crate::error::js_val(&handle))
}
#[wasm_bindgen]
pub fn streaming_skeleton_add_event(
handle: &str,
case_id: &str,
activity: &str,
) -> Result<JsValue, JsValue> {
get_or_init_state().with_streaming_skeleton_mut(handle, |b| {
b.add_event(case_id, activity);
let stats = b.stats();
to_js_str(&json!({
"ok": true,
"event_count": stats.event_count,
"open_traces": stats.open_traces,
}))
})
}
#[wasm_bindgen]
pub fn streaming_skeleton_close_trace(handle: &str, case_id: &str) -> Result<JsValue, JsValue> {
get_or_init_state().with_streaming_skeleton_mut(handle, |b| {
let closed = b.close_trace(case_id);
to_js_str(&json!({
"ok": closed,
"trace_count": b.trace_count,
}))
})
}
#[wasm_bindgen]
pub fn streaming_skeleton_snapshot(handle: &str) -> Result<JsValue, JsValue> {
get_or_init_state().with_streaming_skeleton(handle, |b| {
let dfg = b.snapshot();
to_js_str(&dfg)
})
}
#[wasm_bindgen]
pub fn streaming_skeleton_finalize(handle: &str) -> Result<JsValue, JsValue> {
let dfg = get_or_init_state().with_streaming_skeleton_mut(handle, |b| {
let case_ids: Vec<String> = b.open_trace_ids();
for id in case_ids {
b.close_trace(&id);
}
Ok(b.snapshot())
})?;
let n_nodes = dfg.nodes.len();
let n_edges = dfg.edges.len();
let dfg_handle = get_or_init_state()
.store_object(StoredObject::DFG(dfg))
.map_err(|_| crate::error::js_val("Failed to store DFG"))?;
get_or_init_state().delete_object(handle)?;
to_js_str(&json!({
"dfg_handle": dfg_handle,
"nodes": n_nodes,
"edges": n_edges,
}))
}
#[wasm_bindgen]
pub fn streaming_heuristic_begin(threshold: f64) -> Result<JsValue, JsValue> {
let builder = StreamingHeuristicBuilder::with_dependency_threshold(threshold);
let handle =
get_or_init_state().store_object(StoredObject::StreamingHeuristicBuilder(builder))?;
Ok(crate::error::js_val(&handle))
}
#[wasm_bindgen]
pub fn streaming_heuristic_add_event(
handle: &str,
case_id: &str,
activity: &str,
) -> Result<JsValue, JsValue> {
get_or_init_state().with_streaming_heuristic_mut(handle, |b| {
b.add_event(case_id, activity);
let stats = b.stats();
to_js_str(&json!({
"ok": true,
"event_count": stats.event_count,
"open_traces": stats.open_traces,
}))
})
}
#[wasm_bindgen]
pub fn streaming_heuristic_close_trace(handle: &str, case_id: &str) -> Result<JsValue, JsValue> {
get_or_init_state().with_streaming_heuristic_mut(handle, |b| {
let closed = b.close_trace(case_id);
to_js_str(&json!({
"ok": closed,
"trace_count": b.trace_count,
}))
})
}
#[wasm_bindgen]
pub fn streaming_heuristic_snapshot(handle: &str) -> Result<JsValue, JsValue> {
get_or_init_state().with_streaming_heuristic(handle, |b| {
let dfg = b.snapshot();
to_js_str(&dfg)
})
}
#[wasm_bindgen]
pub fn streaming_heuristic_finalize(handle: &str) -> Result<JsValue, JsValue> {
let dfg = get_or_init_state().with_streaming_heuristic_mut(handle, |b| {
let case_ids: Vec<String> = b.open_trace_ids();
for id in case_ids {
b.close_trace(&id);
}
Ok(b.snapshot())
})?;
let n_nodes = dfg.nodes.len();
let n_edges = dfg.edges.len();
let dfg_handle = get_or_init_state()
.store_object(StoredObject::DFG(dfg))
.map_err(|_| crate::error::js_val("Failed to store DFG"))?;
get_or_init_state().delete_object(handle)?;
to_js_str(&json!({
"dfg_handle": dfg_handle,
"nodes": n_nodes,
"edges": n_edges,
}))
}
#[wasm_bindgen]
pub fn streaming_info() -> String {
serde_json::json!({
"status": "streaming_api_available",
"description": "Streaming discovery algorithms for infinite event streams",
"algorithms": [
{"name": "dfg", "status": "implemented"},
{"name": "skeleton", "status": "implemented"},
{"name": "heuristic", "status": "implemented"},
{"name": "alpha_plus_plus", "status": "implemented"},
{"name": "declare", "status": "implemented"},
{"name": "inductive_miner", "status": "implemented"},
{"name": "hill_climbing", "status": "implemented"},
{"name": "noise_filtered_dfg", "status": "implemented"},
{"name": "astar", "status": "implemented"},
]
})
.to_string()
}