use wasm_bindgen::{JsCast, JsValue};
use web_sys::js_sys::Array;
use web_sys::{Blob, BlobPropertyBag, Url, Worker, WorkerOptions};
pub fn new_worker_from_js(js: &str, options: Option<WorkerOptions>) -> Result<Worker, JsValue> {
let blob_options = BlobPropertyBag::new();
blob_options.set_type("application/javascript");
let blob_parts = Array::new_with_length(1);
blob_parts.set(0, JsValue::from_str(js));
let blob = Blob::new_with_str_sequence_and_options(&blob_parts.into(), &blob_options)?;
let blob_url = Url::create_object_url_with_blob(&blob)?;
let worker = match options {
Some(options) => Worker::new_with_options(&blob_url, &options)?,
None => Worker::new(&blob_url)?,
};
Url::revoke_object_url(&blob_url)?;
Ok(worker)
}
pub fn current_wasm_module() -> Result<JsValue, JsValue> {
let module = wasm_bindgen::module();
if module.is_undefined() || module.is_null() {
return Err(JsValue::from_str(
"wasm_bindgen::module() returned undefined; worker bootstrap requires the shared module",
));
}
Ok(module)
}
#[wasm_bindgen::prelude::wasm_bindgen(inline_js = r#"
export function awsm_bundle_url() {
if (typeof document !== "undefined") {
const scripts = document.querySelectorAll("script[type=module]");
for (const s of scripts) {
const t = s.textContent || "";
const m = t.match(/from\s+['"]([^'"]+\.js)['"]/);
if (m) return new URL(m[1], location.href).href;
}
}
return import.meta.url;
}
"#)]
extern "C" {
pub fn awsm_bundle_url() -> String;
}
pub const WORKER_BOOTSTRAP_JS: &str = r#"
self.onmessage = async (e) => {
if (e.data && e.data.kind === "awsm-init") {
const { wasm_module, glue_url } = e.data;
try {
const wbg = await import(glue_url);
// wasm-bindgen's `--target web` default export accepts a
// pre-compiled Module and skips re-compile.
await wbg.default(wasm_module);
wbg.awsm_worker_entry();
self.postMessage({ kind: "awsm-ready" });
} catch (err) {
self.postMessage({
kind: "awsm-init-error",
message: (err && err.message) ? err.message : String(err),
});
}
return;
}
// Subsequent messages handled by the listener installed by
// awsm_worker_entry().
};
"#;
#[allow(dead_code)]
pub fn coerce_worker(value: JsValue) -> Option<Worker> {
value.dyn_into().ok()
}