Files
GMW/services/frontend-leptos/frontend/src/ws/context.rs
T

141 lines
6.3 KiB
Rust

// services/frontend-leptos/frontend/src/ws/context.rs
use leptos::prelude::*;
use crate::ws::socket::{WsHandle, WsStatus, WsEvent};
use shared_types::message::MessageRecord;
use shared_types::voice::ActiveSpeaker;
use shared_types::media::MediaState;
use shared_types::recording::VoiceRecording;
#[derive(Clone)]
pub struct WsContext {
pub handle: std::rc::Rc<WsHandle>,
pub status: ReadSignal<WsStatus>,
// Per-event callbacks (set externally by feature components)
// Wrapped in Rc so cloning shares the same callback slots
pub on_message_created: std::rc::Rc<std::cell::RefCell<Option<Box<dyn Fn(MessageRecord)>>>>,
pub on_message_updated: std::rc::Rc<std::cell::RefCell<Option<Box<dyn Fn(MessageRecord)>>>>,
pub on_message_deleted: std::rc::Rc<std::cell::RefCell<Option<Box<dyn Fn(String)>>>>,
pub on_message_analyzed: std::rc::Rc<std::cell::RefCell<Option<Box<dyn Fn(MessageRecord)>>>>,
pub on_voice_active_user: std::rc::Rc<std::cell::RefCell<Option<Box<dyn Fn(ActiveSpeaker)>>>>,
pub on_voice_recording_uploaded: std::rc::Rc<std::cell::RefCell<Option<Box<dyn Fn(VoiceRecording)>>>>,
pub on_media_state: std::rc::Rc<std::cell::RefCell<Option<Box<dyn Fn(MediaState)>>>>,
pub on_binary: std::rc::Rc<std::cell::RefCell<Option<Box<dyn Fn(Vec<u8>)>>>>,
}
impl WsContext {
pub fn new(url: &str) -> Self {
let ws_handle = std::rc::Rc::new(WsHandle::new(url));
let status = ws_handle.status;
let ctx = Self {
status,
handle: ws_handle,
on_message_created: std::rc::Rc::new(std::cell::RefCell::new(None)),
on_message_updated: std::rc::Rc::new(std::cell::RefCell::new(None)),
on_message_deleted: std::rc::Rc::new(std::cell::RefCell::new(None)),
on_message_analyzed: std::rc::Rc::new(std::cell::RefCell::new(None)),
on_voice_active_user: std::rc::Rc::new(std::cell::RefCell::new(None)),
on_voice_recording_uploaded: std::rc::Rc::new(std::cell::RefCell::new(None)),
on_media_state: std::rc::Rc::new(std::cell::RefCell::new(None)),
on_binary: std::rc::Rc::new(std::cell::RefCell::new(None)),
};
// Wire up the main event dispatcher
let ctx_clone = ctx.clone();
ctx.handle.on_event(move |event| {
ctx_clone.dispatch_event(event);
});
ctx
}
fn dispatch_event(&self, event: WsEvent) {
match event {
WsEvent::Text(text) => {
// Parse JSON envelope: { type: string, data?: any }
if let Ok(parsed) = serde_json::from_str::<serde_json::Value>(&text) {
let event_type = parsed["type"].as_str().unwrap_or("").to_string();
let data = parsed.get("data");
match event_type.as_str() {
"message_created" => {
if let Some(d) = data.and_then(|v| serde_json::from_value::<MessageRecord>(v.clone()).ok()) {
if let Some(cb) = self.on_message_created.borrow().as_ref() {
cb(d);
}
}
}
"message_updated" => {
if let Some(d) = data.and_then(|v| serde_json::from_value::<MessageRecord>(v.clone()).ok()) {
if let Some(cb) = self.on_message_updated.borrow().as_ref() {
cb(d);
}
}
}
"message_deleted" => {
if let Some(d) = data.and_then(|v| v.as_str().map(String::from)) {
if let Some(cb) = self.on_message_deleted.borrow().as_ref() {
cb(d);
}
}
}
"message_analyzed" => {
if let Some(d) = data.and_then(|v| serde_json::from_value::<MessageRecord>(v.clone()).ok()) {
if let Some(cb) = self.on_message_analyzed.borrow().as_ref() {
cb(d);
}
}
}
"voice_active_user" => {
if let Some(d) = data.and_then(|v| serde_json::from_value::<ActiveSpeaker>(v.clone()).ok()) {
if let Some(cb) = self.on_voice_active_user.borrow().as_ref() {
cb(d);
}
}
}
"voice_recording_uploaded" => {
if let Some(d) = data.and_then(|v| serde_json::from_value::<VoiceRecording>(v.clone()).ok()) {
if let Some(cb) = self.on_voice_recording_uploaded.borrow().as_ref() {
cb(d);
}
}
}
"media_state" => {
if let Some(d) = data.and_then(|v| serde_json::from_value::<MediaState>(v.clone()).ok()) {
if let Some(cb) = self.on_media_state.borrow().as_ref() {
cb(d);
}
}
}
_ => {
// Unknown event type — log and ignore
web_sys::console::log_1(&format!("[WS] unhandled event: {}", event_type).into());
}
}
}
}
WsEvent::Binary(data) => {
if let Some(cb) = self.on_binary.borrow().as_ref() {
cb(data);
}
}
}
}
pub fn connect(&self) {
self.handle.connect();
}
pub fn disconnect(&self) {
self.handle.disconnect();
}
pub fn send_text(&self, text: &str) {
let _ = self.handle.send_text(text);
}
pub fn send_binary(&self, data: &[u8]) {
let _ = self.handle.send_binary(data);
}
}