use js_sys::{Object, Reflect};
use wasm_bindgen::prelude::*;
use web_sys::Worker;
thread_local! {
static CHAT_ACTIVE: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
static CHAT_FAST: std::cell::Cell<i32> = const { std::cell::Cell::new(0) };
}
const CHAT_FAST_MS: u32 = 500; const CHAT_IDLE_MS: u32 = 2500; const CHAT_FAST_REFILL: i32 = 12;
pub(crate) fn chat_start(worker: Worker) {
if CHAT_ACTIVE.with(|a| a.get()) {
return;
}
let Some(room) = crate::app::tenant::current_name() else {
return;
};
CHAT_ACTIVE.with(|a| a.set(true));
wasm_bindgen_futures::spawn_local(chat_poll_loop(worker, room));
}
async fn chat_poll_loop(worker: Worker, room: String) {
let mut cursor: i64 = -1;
while CHAT_ACTIVE.with(|a| a.get()) {
if let Ok(msgs) = crate::registry::chat_poll(&room, cursor).await {
if !msgs.is_empty() {
CHAT_FAST.with(|f| f.set(CHAT_FAST_REFILL)); }
for (n, name, text) in msgs {
if n > cursor {
cursor = n;
}
chat_post_to_worker(&worker, &format!("{name}: {text}"));
}
}
let ms = CHAT_FAST.with(|f| {
let n = f.get();
if n > 0 {
f.set(n - 1);
CHAT_FAST_MS
} else {
CHAT_IDLE_MS
}
});
crate::runtime::sleep_ms(ms).await;
}
}
fn chat_post_to_worker(worker: &Worker, line: &str) {
let m = Object::new();
let _ = Reflect::set(&m, &JsValue::from_str("type"), &JsValue::from_str("chat:msg"));
let _ = Reflect::set(&m, &JsValue::from_str("text"), &JsValue::from_str(line));
let _ = worker.post_message(&m);
}
pub(crate) fn chat_send(text: String) {
CHAT_FAST.with(|f| f.set(CHAT_FAST_REFILL)); wasm_bindgen_futures::spawn_local(async move {
let Some(room) = crate::app::tenant::current_name() else {
return;
};
let Some((signer, _)) = crate::app::chat::credit_signer().await else {
return;
};
let now = (js_sys::Date::now() / 1000.0) as u64;
let _ = crate::registry::chat_post(&signer, now, &room, &text).await;
});
}
pub(crate) fn chat_stop() {
CHAT_ACTIVE.with(|a| a.set(false));
CHAT_FAST.with(|f| f.set(0));
}