use cogcore::{UserScript, View, glib};
use consortium_hmi::Bridge;
use futures_channel::mpsc::unbounded;
use futures_util::StreamExt;
const JS_PRELUDE: &str = include_str!("bridge_prelude.js");
pub(super) fn attach(
bridge: Bridge,
runtime: tokio::runtime::Handle,
view: &View,
) -> cogcore::Result<()> {
let manager = view.user_content_manager().ok_or(cogcore::Error::Null(
"webkit_web_view_get_user_content_manager",
))?;
manager.add_script(&UserScript::new_at_document_start(JS_PRELUDE)?);
manager.register_script_message_handler("bridge")?;
let (responses, mut response_rx) = unbounded::<(u64, String)>();
let response_view = view.clone();
glib::MainContext::default().spawn_local(async move {
while let Some((id, result)) = response_rx.next().await {
let _ = response_view.run_js(&resolve_script(id, &result));
}
});
manager.connect_script_message("bridge", move |message| {
let Ok(dispatch) = bridge.dispatch(&message) else {
return;
};
let responses = responses.clone();
let task = runtime.spawn(async move {
let result = dispatch.response.await;
let _ = responses.unbounded_send((dispatch.id, result));
});
drop(task);
})?;
Ok(())
}
fn resolve_script(id: u64, result: &str) -> String {
format!("window.__BRIDGE__._resolve({id},{result})")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn response_script_preserves_raw_json() {
assert_eq!(
resolve_script(5, r#"{"ok":true}"#),
r#"window.__BRIDGE__._resolve(5,{"ok":true})"#,
);
}
}