launch_worker/
lib.rs

1use js_sys::{Array, Object};
2use wasm_bindgen::JsValue;
3use web_sys::{Blob, BlobPropertyBag, Url, Worker};
4
5pub fn worker_from_str(worker_str: &str) -> Result<Worker, JsValue> {
6    let blob_parts = str_array_to_js_value(&[worker_str]);
7    let blob = Blob::new_with_str_sequence_and_options(
8        &blob_parts,
9        BlobPropertyBag::new().type_("application/javascript"),
10    )?;
11    let url_obj = Url::create_object_url_with_blob(&blob)?;
12    Worker::new(&url_obj)
13}
14
15pub fn worker_from_runner(runner_name: &str, pkg_name: &str) -> Result<Worker, JsValue> {
16    let pkg_name = pkg_name.to_lowercase().replace('-', "_");
17    let worker_str = format!(
18        "
19        self.onmessage = (event) => {{
20          // The web-worker lives in a different prefixed namespace than the main
21          // thread. To make scripts from the main thread available, it needs to send
22          // its URL, which we receive here.
23          importScripts(event.data.url + '/pkg/{pkg_name}.js')
24          console.log('Imported script in worker_from_runner')
25
26          const {{ {runner_name} }} = wasm_bindgen
27
28          console.log('Launching another runner')
29
30          async function run_in_worker() {{
31            // Load the wasm file by awaiting the Promise returned by `wasm_bindgen`.
32            await wasm_bindgen(event.data.url + '/pkg/{pkg_name}_bg.wasm')
33
34            const runner = {runner_name}.new()
35            runner.init()
36
37            self.onmessage = async (event) => {{
38              console.log('JS: Receive event')
39              runner.onmessage(event)
40            }}
41          }}
42
43          run_in_worker()
44        }}
45        "
46    );
47    let worker = worker_from_str(&worker_str)?;
48    let site_url = get_url()?;
49    let obj = create_obj(vec![("url", JsValue::from_str(&site_url))]);
50    worker.post_message(&obj)?;
51    Ok(worker)
52}
53
54pub fn get_url() -> Result<String, JsValue> {
55    let document = web_sys::window().unwrap().document().unwrap();
56    let location = document.location().unwrap();
57
58    let protocol = location.protocol()?;
59    let host = location.host()?;
60
61    Ok(format!("{protocol}//{host}"))
62}
63
64fn str_array_to_js_value(array: &[&str]) -> JsValue {
65    JsValue::from(
66        array
67            .iter()
68            .map(|&x| JsValue::from(x))
69            .collect::<js_sys::Array>(),
70    )
71}
72
73fn create_obj(iterable: Vec<(&str, JsValue)>) -> Object {
74    let props = iterable
75        .into_iter()
76        .map(|(name, value)| [JsValue::from_str(name), value].iter().collect::<Array>())
77        .collect::<Array>();
78    js_sys::Object::from_entries(&JsValue::from(props)).unwrap()
79}