wifi-densepose/vendor/midstream/wasm-bindings/src/lib.rs

481 lines
15 KiB
Rust

//! WASM bindings for MidStream Lean Agentic Learning System
//!
//! Provides WebSocket, SSE, and HTTP streaming support for browser and Node.js
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
use web_sys::{WebSocket, EventSource, Request, RequestInit, Response};
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use std::rc::Rc;
use js_sys::{Function, Promise, Uint8Array};
// Re-export types from midstream
use midstream::{
TemporalComparator, RealtimeScheduler, SchedulingPolicy, Priority,
AttractorAnalyzer, TemporalNeuralSolver, MetaLearner, MetaLevel,
ComparisonAlgorithm, TemporalFormula, TemporalTrace, TemporalState,
};
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
#[wasm_bindgen(js_namespace = console)]
fn error(s: &str);
}
/// Initialize panic hook for better error messages
#[wasm_bindgen(start)]
pub fn init() {
console_error_panic_hook::set_once();
log("MidStream WASM initialized");
}
// ============================================================================
// WebSocket Client
// ============================================================================
#[wasm_bindgen]
pub struct WebSocketClient {
socket: WebSocket,
on_message: Rc<RefCell<Option<Function>>>,
on_error: Rc<RefCell<Option<Function>>>,
on_close: Rc<RefCell<Option<Function>>>,
}
#[wasm_bindgen]
impl WebSocketClient {
#[wasm_bindgen(constructor)]
pub fn new(url: &str) -> Result<WebSocketClient, JsValue> {
let socket = WebSocket::new(url)?;
socket.set_binary_type(web_sys::BinaryType::Arraybuffer);
Ok(WebSocketClient {
socket,
on_message: Rc::new(RefCell::new(None)),
on_error: Rc::new(RefCell::new(None)),
on_close: Rc::new(RefCell::new(None)),
})
}
pub fn connect(&self) -> Result<(), JsValue> {
// Set up message handler
let on_message_cb = self.on_message.clone();
let onmessage_callback = Closure::wrap(Box::new(move |e: web_sys::MessageEvent| {
if let Some(callback) = on_message_cb.borrow().as_ref() {
if let Ok(txt) = e.data().dyn_into::<js_sys::JsString>() {
let _ = callback.call1(&JsValue::NULL, &txt);
} else if let Ok(array) = e.data().dyn_into::<js_sys::ArrayBuffer>() {
let uint8_array = Uint8Array::new(&array);
let _ = callback.call1(&JsValue::NULL, &uint8_array);
}
}
}) as Box<dyn FnMut(web_sys::MessageEvent)>);
self.socket.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref()));
onmessage_callback.forget();
// Set up error handler
let on_error_cb = self.on_error.clone();
let onerror_callback = Closure::wrap(Box::new(move |e: web_sys::ErrorEvent| {
if let Some(callback) = on_error_cb.borrow().as_ref() {
let _ = callback.call1(&JsValue::NULL, &e.into());
}
}) as Box<dyn FnMut(web_sys::ErrorEvent)>);
self.socket.set_onerror(Some(onerror_callback.as_ref().unchecked_ref()));
onerror_callback.forget();
// Set up close handler
let on_close_cb = self.on_close.clone();
let onclose_callback = Closure::wrap(Box::new(move |e: web_sys::CloseEvent| {
if let Some(callback) = on_close_cb.borrow().as_ref() {
let _ = callback.call1(&JsValue::NULL, &e.into());
}
}) as Box<dyn FnMut(web_sys::CloseEvent)>);
self.socket.set_onclose(Some(onclose_callback.as_ref().unchecked_ref()));
onclose_callback.forget();
Ok(())
}
pub fn send(&self, data: &str) -> Result<(), JsValue> {
self.socket.send_with_str(data)
}
pub fn send_bytes(&self, data: &[u8]) -> Result<(), JsValue> {
self.socket.send_with_u8_array(data)
}
pub fn close(&self) -> Result<(), JsValue> {
self.socket.close()
}
pub fn set_on_message(&self, callback: Function) {
*self.on_message.borrow_mut() = Some(callback);
}
pub fn set_on_error(&self, callback: Function) {
*self.on_error.borrow_mut() = Some(callback);
}
pub fn set_on_close(&self, callback: Function) {
*self.on_close.borrow_mut() = Some(callback);
}
pub fn ready_state(&self) -> u16 {
self.socket.ready_state()
}
}
// ============================================================================
// SSE Client
// ============================================================================
#[wasm_bindgen]
pub struct SSEClient {
event_source: EventSource,
on_message: Rc<RefCell<Option<Function>>>,
on_error: Rc<RefCell<Option<Function>>>,
}
#[wasm_bindgen]
impl SSEClient {
#[wasm_bindgen(constructor)]
pub fn new(url: &str) -> Result<SSEClient, JsValue> {
let event_source = EventSource::new(url)?;
Ok(SSEClient {
event_source,
on_message: Rc::new(RefCell::new(None)),
on_error: Rc::new(RefCell::new(None)),
})
}
pub fn connect(&self) -> Result<(), JsValue> {
// Set up message handler
let on_message_cb = self.on_message.clone();
let onmessage_callback = Closure::wrap(Box::new(move |e: web_sys::MessageEvent| {
if let Some(callback) = on_message_cb.borrow().as_ref() {
if let Ok(data) = e.data().dyn_into::<js_sys::JsString>() {
let _ = callback.call1(&JsValue::NULL, &data);
}
}
}) as Box<dyn FnMut(web_sys::MessageEvent)>);
self.event_source.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref()));
onmessage_callback.forget();
// Set up error handler
let on_error_cb = self.on_error.clone();
let onerror_callback = Closure::wrap(Box::new(move |e: web_sys::Event| {
if let Some(callback) = on_error_cb.borrow().as_ref() {
let _ = callback.call1(&JsValue::NULL, &e);
}
}) as Box<dyn FnMut(web_sys::Event)>);
self.event_source.set_onerror(Some(onerror_callback.as_ref().unchecked_ref()));
onerror_callback.forget();
Ok(())
}
pub fn close(&self) {
self.event_source.close();
}
pub fn set_on_message(&self, callback: Function) {
*self.on_message.borrow_mut() = Some(callback);
}
pub fn set_on_error(&self, callback: Function) {
*self.on_error.borrow_mut() = Some(callback);
}
pub fn ready_state(&self) -> u16 {
self.event_source.ready_state()
}
}
// ============================================================================
// HTTP Streaming Client
// ============================================================================
#[wasm_bindgen]
pub struct StreamingHTTPClient;
#[wasm_bindgen]
impl StreamingHTTPClient {
#[wasm_bindgen(constructor)]
pub fn new() -> StreamingHTTPClient {
StreamingHTTPClient
}
pub async fn stream(&self, url: &str, on_chunk: Function) -> Result<(), JsValue> {
let mut opts = RequestInit::new();
opts.method("GET");
let request = Request::new_with_str_and_init(url, &opts)?;
let window = web_sys::window().ok_or("No window object")?;
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into()?;
if let Some(body) = resp.body() {
let reader = body.get_reader();
loop {
let result = JsFuture::from(reader.read()).await?;
let done = js_sys::Reflect::get(&result, &JsValue::from_str("done"))?;
if done.as_bool().unwrap_or(false) {
break;
}
let value = js_sys::Reflect::get(&result, &JsValue::from_str("value"))?;
if let Ok(uint8_array) = value.dyn_into::<Uint8Array>() {
let _ = on_chunk.call1(&JsValue::NULL, &uint8_array);
}
}
}
Ok(())
}
}
// ============================================================================
// Lean Agentic System WASM Bindings
// ============================================================================
#[wasm_bindgen]
pub struct TemporalComparatorWasm {
inner: TemporalComparator<String>,
}
#[wasm_bindgen]
impl TemporalComparatorWasm {
#[wasm_bindgen(constructor)]
pub fn new() -> TemporalComparatorWasm {
TemporalComparatorWasm {
inner: TemporalComparator::new(),
}
}
pub fn compare(&mut self, seq1: JsValue, seq2: JsValue, algorithm: &str) -> Result<f64, JsValue> {
let seq1_vec: Vec<String> = serde_wasm_bindgen::from_value(seq1)?;
let seq2_vec: Vec<String> = serde_wasm_bindgen::from_value(seq2)?;
let algo = match algorithm {
"dtw" | "DTW" => ComparisonAlgorithm::DTW,
"lcs" | "LCS" => ComparisonAlgorithm::LCS,
"edit" | "EditDistance" => ComparisonAlgorithm::EditDistance,
"corr" | "Correlation" => ComparisonAlgorithm::Correlation,
_ => return Err(JsValue::from_str("Unknown algorithm")),
};
Ok(self.inner.compare(&seq1_vec, &seq2_vec, algo))
}
pub fn detect_pattern(&self, sequence: JsValue, pattern: JsValue) -> Result<JsValue, JsValue> {
let seq_vec: Vec<String> = serde_wasm_bindgen::from_value(sequence)?;
let pat_vec: Vec<String> = serde_wasm_bindgen::from_value(pattern)?;
let positions = self.inner.detect_pattern(&seq_vec, &pat_vec);
serde_wasm_bindgen::to_value(&positions).map_err(|e| JsValue::from_str(&e.to_string()))
}
pub fn cache_stats(&self) -> Result<JsValue, JsValue> {
let stats = self.inner.cache_stats();
serde_wasm_bindgen::to_value(&stats).map_err(|e| JsValue::from_str(&e.to_string()))
}
}
#[wasm_bindgen]
pub struct AttractorAnalyzerWasm {
inner: AttractorAnalyzer,
}
#[wasm_bindgen]
impl AttractorAnalyzerWasm {
#[wasm_bindgen(constructor)]
pub fn new(embedding_dim: usize, time_delay: usize) -> AttractorAnalyzerWasm {
AttractorAnalyzerWasm {
inner: AttractorAnalyzer::new(embedding_dim, time_delay),
}
}
pub fn analyze(&self, data: JsValue) -> Result<JsValue, JsValue> {
let data_vec: Vec<f64> = serde_wasm_bindgen::from_value(data)?;
let result = self.inner.analyze(&data_vec)
.map_err(|e| JsValue::from_str(&e))?;
serde_wasm_bindgen::to_value(&result).map_err(|e| JsValue::from_str(&e.to_string()))
}
}
#[wasm_bindgen]
pub struct MetaLearnerWasm {
inner: MetaLearner,
}
#[wasm_bindgen]
impl MetaLearnerWasm {
#[wasm_bindgen(constructor)]
pub fn new(max_history: usize) -> MetaLearnerWasm {
MetaLearnerWasm {
inner: MetaLearner::new(max_history),
}
}
pub fn learn(&mut self, content: &str, reward: f64) {
self.inner.learn(content.to_string(), reward);
}
pub fn ascend(&mut self) -> Result<String, JsValue> {
self.inner.ascend()
.map(|level| format!("{:?}", level))
.map_err(|e| JsValue::from_str(&e))
}
pub fn descend(&mut self) -> Result<String, JsValue> {
self.inner.descend()
.map(|level| format!("{:?}", level))
.map_err(|e| JsValue::from_str(&e))
}
pub fn get_summary(&self) -> Result<JsValue, JsValue> {
let summary = self.inner.get_summary();
serde_wasm_bindgen::to_value(&summary).map_err(|e| JsValue::from_str(&e.to_string()))
}
pub fn current_level(&self) -> String {
format!("{:?}", self.inner.current_level())
}
}
// ============================================================================
// MidStream Agent
// ============================================================================
#[derive(Serialize, Deserialize)]
pub struct AgentConfig {
pub max_history: usize,
pub embedding_dim: usize,
pub scheduling_policy: String,
}
impl Default for AgentConfig {
fn default() -> Self {
Self {
max_history: 1000,
embedding_dim: 3,
scheduling_policy: "EDF".to_string(),
}
}
}
#[wasm_bindgen]
pub struct MidStreamAgent {
temporal: TemporalComparator<String>,
attractor: AttractorAnalyzer,
meta_learner: MetaLearner,
config: AgentConfig,
}
#[wasm_bindgen]
impl MidStreamAgent {
#[wasm_bindgen(constructor)]
pub fn new(config: JsValue) -> Result<MidStreamAgent, JsValue> {
let config: AgentConfig = if config.is_undefined() {
AgentConfig::default()
} else {
serde_wasm_bindgen::from_value(config)?
};
Ok(MidStreamAgent {
temporal: TemporalComparator::new(),
attractor: AttractorAnalyzer::new(config.embedding_dim, 1),
meta_learner: MetaLearner::new(config.max_history),
config,
})
}
pub fn process_message(&mut self, message: &str) -> Result<JsValue, JsValue> {
// Simple message processing with learning
self.meta_learner.learn(message.to_string(), 0.8);
let summary = self.meta_learner.get_summary();
serde_wasm_bindgen::to_value(&summary).map_err(|e| JsValue::from_str(&e.to_string()))
}
pub fn analyze_conversation(&mut self, messages: JsValue) -> Result<JsValue, JsValue> {
let msg_vec: Vec<String> = serde_wasm_bindgen::from_value(messages)?;
let mut result = serde_json::json!({
"message_count": msg_vec.len(),
"patterns": [],
"meta_learning": self.meta_learner.get_summary(),
});
serde_wasm_bindgen::to_value(&result).map_err(|e| JsValue::from_str(&e.to_string()))
}
pub fn get_status(&self) -> Result<JsValue, JsValue> {
let status = serde_json::json!({
"meta_level": format!("{:?}", self.meta_learner.current_level()),
"config": {
"max_history": self.config.max_history,
"embedding_dim": self.config.embedding_dim,
}
});
serde_wasm_bindgen::to_value(&status).map_err(|e| JsValue::from_str(&e.to_string()))
}
}
// ============================================================================
// Benchmarking utilities
// ============================================================================
#[wasm_bindgen]
pub fn benchmark_dtw(size: usize, iterations: usize) -> f64 {
let mut comparator = TemporalComparator::<i32>::new();
let seq1: Vec<i32> = (0..size as i32).collect();
let seq2: Vec<i32> = (0..size as i32).map(|x| x + 1).collect();
let start = js_sys::Date::now();
for _ in 0..iterations {
comparator.compare(&seq1, &seq2, ComparisonAlgorithm::DTW);
}
let end = js_sys::Date::now();
(end - start) / iterations as f64
}
#[wasm_bindgen]
pub fn benchmark_lcs(size: usize, iterations: usize) -> f64 {
let mut comparator = TemporalComparator::<i32>::new();
let seq1: Vec<i32> = (0..size as i32).collect();
let seq2: Vec<i32> = (0..size as i32).map(|x| x + 1).collect();
let start = js_sys::Date::now();
for _ in 0..iterations {
comparator.compare(&seq1, &seq2, ComparisonAlgorithm::LCS);
}
let end = js_sys::Date::now();
(end - start) / iterations as f64
}
#[wasm_bindgen]
pub fn get_version() -> String {
env!("CARGO_PKG_VERSION").to_string()
}