use std::cell::{Cell, RefCell};
use wasm_bindgen::closure::Closure;
use wasm_bindgen::JsCast;
const STATES: &str = "frus-run-states";
const FRESH: &str = "frus-run-fresh";
thread_local! {
static LATEST: RefCell<Option<String>> = const { RefCell::new(None) };
static WATCHED: Cell<bool> = const { Cell::new(false) };
}
fn storage() -> Option<web_sys::Storage> {
web_sys::window()?.session_storage().ok()?
}
#[inline(never)]
pub(crate) fn start() -> Option<String> {
let window = web_sys::window()?;
let watched = js_sys::Reflect::get(&window, &"__frusRun".into())
.map(|v| v.is_truthy())
.unwrap_or(false);
WATCHED.with(|w| w.set(watched));
if !watched {
return None;
}
let keep = Closure::<dyn FnMut()>::new(|| {
let Some(storage) = storage() else { return };
if storage.get_item(FRESH).ok().flatten().is_some() {
let _ = storage.remove_item(FRESH);
let _ = storage.remove_item(STATES);
return;
}
LATEST.with(|latest| {
if let Some(states) = latest.borrow().as_deref() {
let _ = storage.set_item(STATES, states);
}
});
});
let _ = window.add_event_listener_with_callback("pagehide", keep.as_ref().unchecked_ref());
keep.forget();
let command = Closure::<dyn FnMut(String)>::new(|command: String| {
crate::dev_commands::push_command(&command);
});
let _ = js_sys::Reflect::set(&window, &"__frusCommand".into(), command.as_ref());
command.forget();
let storage = storage()?;
let states = storage.get_item(STATES).ok().flatten();
let _ = storage.remove_item(STATES);
states
}
pub(crate) fn send_screenshot(window: &winit::window::Window) {
use winit::platform::web::WindowExtWebSys;
let Some(canvas) = window.canvas() else {
return;
};
let Ok(data) = canvas.to_data_url() else {
log::warn!(target: "frus::dev", "the page's picture could not be read");
return;
};
let Some(page) = web_sys::window() else {
return;
};
let send = js_sys::Reflect::get(&page, &"__frusScreenshot".into())
.ok()
.and_then(|f| f.dyn_into::<js_sys::Function>().ok());
match send {
Some(send) => {
let _ = send.call1(&page, &data.into());
}
None => log::warn!(target: "frus::dev", "this page is not served by frus run"),
}
}
pub(crate) fn keep(snapshot: impl FnOnce() -> String) {
if watched() {
set_latest(snapshot());
}
}
#[inline(never)]
fn watched() -> bool {
WATCHED.with(Cell::get)
}
#[inline(never)]
fn set_latest(states: String) {
LATEST.with(|latest| *latest.borrow_mut() = Some(states));
}