use wasm_bindgen::prelude::*; use serde::{Serialize, Deserialize}; use crate::value::Value; use crate::js::*; use imbl::Vector; use std::rc::Rc; const OK: Value = Value::Keyword("ok"); const ERR: Value = Value::Keyword("err"); #[wasm_bindgen(module = "/pkg/worker.js")] extern "C" { #[wasm_bindgen(catch)] async fn io (output: String) -> Result; } type Url = Value; // expect a string type Commands = Value; // expect a list of command tuples #[derive(Debug, Clone, PartialEq, Serialize)] #[serde(tag = "verb", content = "data")] pub enum MsgOut { Console(Value), Commands(Commands), Fetch(Url), Complete(Value), Error(String), Ready } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(tag = "verb", content = "data")] pub enum MsgIn { Input(String), Fetch(String, f64, String), Kill, Keyboard(Vec), } impl std::fmt::Display for MsgIn { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { MsgIn::Input(str) => write!(f, "Input: {str}"), MsgIn::Kill => write!(f, "Kill"), MsgIn::Fetch(url, code, text) => write!(f, "Fetch: {url} :: {code} ::\n{text}"), _ => todo!() } } } impl MsgIn { pub fn into_value(self) -> Value { match self { MsgIn::Input(str) => Value::string(str), MsgIn::Fetch(url, status_f64, string) => { let url = Value::string(url); let status = Value::Number(status_f64); let text = Value::string(string); let result_tuple = if status_f64 == 200.0 { Value::tuple(vec![OK, text]) } else { Value::tuple(vec![ERR, status]) }; Value::tuple(vec![url, result_tuple]) } MsgIn::Kill => Value::Nothing, MsgIn::Keyboard(downkeys) => { let mut vector = Vector::new(); for key in downkeys { vector.push_back(Value::String(Rc::new(key))); } Value::List(Box::new(vector)) } } } } pub async fn send_err_to_ludus_console(msg: String) { console_log!("{msg}"); do_io(vec![MsgOut::Ready, MsgOut::Error(msg)]).await; } pub async fn do_io (msgs: Vec) -> Vec { let json = serde_json::to_string(&msgs).unwrap(); let inbox = io (json).await; let inbox = match inbox { Ok(msgs) => msgs, Err(_) => return vec![] }; let inbox = inbox.as_string().expect("response should be a string"); let inbox: Vec = serde_json::from_str(inbox.as_str()).expect("response from js should be valid"); if !inbox.is_empty() { console_log!("ludus received messages"); for msg in inbox.iter() { console_log!("{}", msg); } } inbox }