use std::cell::Cell;
use std::rc::Rc;
use wasm_bindgen::prelude::*;
use crate::webview::{FromBase64, HANDLER_NAME, ToBase64};
fn get_ipc() -> Option<js_sys::Function> {
let window = web_sys::window()?;
let ipc = js_sys::Reflect::get(&window, &"ipc".into()).ok()?;
ipc.dyn_ref::<js_sys::Object>()
.and_then(|object| js_sys::Reflect::get(object, &"postMessage".into()).ok())?
.dyn_ref::<js_sys::Function>()
.cloned()
}
pub fn send<Cmd: ToBase64>(cmd: &Cmd) {
if let (Some(data), Some(post_message)) = (cmd.to_base64(), get_ipc()) {
let ipc = js_sys::Reflect::get(&web_sys::window().unwrap(), &"ipc".into()).unwrap();
let _ = post_message.call1(&ipc, &JsValue::from_str(&data));
}
}
pub fn connect<Cmd, Evt>(ready: Cmd, handler: impl Fn(Evt) + 'static)
where
Cmd: ToBase64 + 'static,
Evt: FromBase64 + 'static,
{
let window = web_sys::window().unwrap();
let interval_id: Rc<Cell<Option<i32>>> = Rc::new(Cell::new(None));
let closure = Closure::wrap(Box::new({
let window = window.clone();
let interval_id = interval_id.clone();
move |data: String| {
if let Some(event) = Evt::from_base64(&data) {
if let Some(id) = interval_id.get() {
window.clear_interval_with_handle(id);
interval_id.set(None);
}
handler(event);
}
}
}) as Box<dyn Fn(String)>);
js_sys::Reflect::set(&window, &HANDLER_NAME.into(), closure.as_ref()).unwrap();
closure.forget();
let poll = Closure::wrap(Box::new({
let interval_id = interval_id.clone();
move || {
if interval_id.get().is_some() && get_ipc().is_some() {
send(&ready);
}
}
}) as Box<dyn Fn()>);
let id = window
.set_interval_with_callback_and_timeout_and_arguments_0(poll.as_ref().unchecked_ref(), 50)
.unwrap();
interval_id.set(Some(id));
poll.forget();
}