Work in progress towards implementing WebSocket connection.
This commit is contained in:
		
							parent
							
								
									1fa196da1f
								
							
						
					
					
						commit
						1df6e574d2
					
				
							
								
								
									
										15
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										15
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -1015,9 +1015,9 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde"
 | 
			
		||||
version = "1.0.206"
 | 
			
		||||
version = "1.0.209"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "5b3e4cd94123dd520a128bcd11e34d9e9e423e7e3e50425cb1b4b1e3549d0284"
 | 
			
		||||
checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "serde_derive",
 | 
			
		||||
]
 | 
			
		||||
@ -1046,9 +1046,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_derive"
 | 
			
		||||
version = "1.0.206"
 | 
			
		||||
version = "1.0.209"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "fabfb6138d2383ea8208cf98ccf69cdfb1aff4088460681d84189aa259762f97"
 | 
			
		||||
checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
@ -1057,9 +1057,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_json"
 | 
			
		||||
version = "1.0.122"
 | 
			
		||||
version = "1.0.127"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da"
 | 
			
		||||
checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "itoa",
 | 
			
		||||
 "memchr",
 | 
			
		||||
@ -1352,11 +1352,14 @@ version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anyhow",
 | 
			
		||||
 "console_error_panic_hook",
 | 
			
		||||
 "gc-arena",
 | 
			
		||||
 "im",
 | 
			
		||||
 "itertools",
 | 
			
		||||
 "minicrossterm",
 | 
			
		||||
 "nom",
 | 
			
		||||
 "piccolo",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_json",
 | 
			
		||||
 "thiserror",
 | 
			
		||||
 "unicode-segmentation",
 | 
			
		||||
 "unicode-width",
 | 
			
		||||
 | 
			
		||||
@ -19,3 +19,6 @@ minicrossterm = { git = "https://git.blastmud.org/blasthavers/minicrossterm.git"
 | 
			
		||||
thiserror = "1.0.63"
 | 
			
		||||
console_error_panic_hook = "0.1.7"
 | 
			
		||||
anyhow = "1.0.86"
 | 
			
		||||
serde = "1.0.209"
 | 
			
		||||
serde_json = "1.0.127"
 | 
			
		||||
gc-arena = "0.5.3"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										179
									
								
								src/lua_state.rs
									
									
									
									
									
								
							
							
						
						
									
										179
									
								
								src/lua_state.rs
									
									
									
									
									
								
							@ -1,13 +1,18 @@
 | 
			
		||||
use anyhow::Error;
 | 
			
		||||
use gc_arena::Rootable;
 | 
			
		||||
use piccolo::{
 | 
			
		||||
    Callback, Closure, Context, Executor, FromValue, Function, IntoValue, Lua, StashedExecutor,
 | 
			
		||||
    StaticError, Table, Value, Variadic,
 | 
			
		||||
    self, Callback, Closure, Context, Executor, FromValue, Function, IntoValue, Lua,
 | 
			
		||||
    StashedExecutor, StaticError, Table, UserData, Value, Variadic,
 | 
			
		||||
};
 | 
			
		||||
use wasm_bindgen::JsValue;
 | 
			
		||||
use web_sys::console;
 | 
			
		||||
use yew::UseStateSetter;
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    command_handler::debrace, echo_to_term_frame, GlobalLayoutCell, GlobalLayoutState,
 | 
			
		||||
    GlobalMemoCell, TermFrame,
 | 
			
		||||
    command_handler::debrace,
 | 
			
		||||
    echo_to_term_frame,
 | 
			
		||||
    websocket::{connect_websocket, send_message_to_mud, WebSocketId},
 | 
			
		||||
    GlobalLayoutCell, GlobalLayoutState, GlobalMemoCell, TermFrame,
 | 
			
		||||
};
 | 
			
		||||
use std::{collections::VecDeque, rc::Rc, str};
 | 
			
		||||
 | 
			
		||||
@ -28,7 +33,11 @@ impl LuaState {
 | 
			
		||||
    fn try_set_current_frame(&mut self, frame: &TermFrame) -> Result<(), StaticError> {
 | 
			
		||||
        self.interp.try_enter(|ctx| {
 | 
			
		||||
            let info_table = Table::from_value(ctx, ctx.get_global(ctx.intern_static(b"info")))?;
 | 
			
		||||
            info_table.set(ctx, ctx.intern_static(b"current_frame"), frame.0 as i64)?;
 | 
			
		||||
            info_table.set(
 | 
			
		||||
                ctx,
 | 
			
		||||
                ctx.intern_static(b"current_frame"),
 | 
			
		||||
                wrap_frame(ctx, frame),
 | 
			
		||||
            )?;
 | 
			
		||||
            Ok(())
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
@ -111,6 +120,7 @@ pub fn install_lua_globals(
 | 
			
		||||
            register_command!(echo);
 | 
			
		||||
            register_command!(echo_frame);
 | 
			
		||||
            register_command!(echo_frame_raw);
 | 
			
		||||
            register_command!(sendmud_raw);
 | 
			
		||||
            register_command!(hsplit);
 | 
			
		||||
            register_command!(panel_merge);
 | 
			
		||||
            register_command!(vsplit);
 | 
			
		||||
@ -122,6 +132,10 @@ pub fn install_lua_globals(
 | 
			
		||||
            ctx.set_global(ctx.intern_static(b"info").into_value(ctx), info_table)
 | 
			
		||||
                .map(|_| ())
 | 
			
		||||
                .map_err(|_| Error::msg("Can't set info key"))?;
 | 
			
		||||
            let muds_table = Table::new(&ctx);
 | 
			
		||||
            ctx.set_global(ctx.intern_static(b"muds").into_value(ctx), muds_table)
 | 
			
		||||
                .map(|_| ())
 | 
			
		||||
                .map_err(|_| Error::msg("Can't set muds key"))?;
 | 
			
		||||
 | 
			
		||||
            Ok(())
 | 
			
		||||
        })
 | 
			
		||||
@ -137,12 +151,11 @@ fn echo_frame_raw<'gc, 'a>(
 | 
			
		||||
) -> Callback<'gc> {
 | 
			
		||||
    let global_memo = global_memo.clone();
 | 
			
		||||
    Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
 | 
			
		||||
        let frame_no: u64 = stack.from_front(ctx)?;
 | 
			
		||||
        let frame: TermFrame = try_unwrap_frame(ctx, &stack.pop_front())?;
 | 
			
		||||
        let message: piccolo::String = stack.from_front(ctx)?;
 | 
			
		||||
        let message_str = str::from_utf8(message.as_bytes())
 | 
			
		||||
            .map_err(|_| "Expected message to echo to be UTF-8.".into_value(ctx))?;
 | 
			
		||||
        echo_to_term_frame(&global_memo, &TermFrame(frame_no), message_str)
 | 
			
		||||
            .map_err(|m| m.into_value(ctx))?;
 | 
			
		||||
        echo_to_term_frame(&global_memo, &frame, message_str).map_err(|m| m.into_value(ctx))?;
 | 
			
		||||
        Ok(piccolo::CallbackReturn::Return)
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
@ -267,3 +280,153 @@ fn panel_merge<'gc>(
 | 
			
		||||
        Ok(piccolo::CallbackReturn::Return)
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn wrap_frame<'gc>(ctx: Context<'gc>, frame: &TermFrame) -> Value<'gc> {
 | 
			
		||||
    UserData::new::<Rootable![TermFrame]>(&ctx, frame.clone()).into()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn try_unwrap_frame<'gc>(
 | 
			
		||||
    ctx: Context<'gc>,
 | 
			
		||||
    value: &Value<'gc>,
 | 
			
		||||
) -> Result<TermFrame, piccolo::Error<'gc>> {
 | 
			
		||||
    match u64::from_value(ctx, *value) {
 | 
			
		||||
        Ok(v) => Ok(TermFrame(v)),
 | 
			
		||||
        Err(_) => Ok(UserData::from_value(ctx, *value)?
 | 
			
		||||
            .downcast::<Rootable![TermFrame]>()?
 | 
			
		||||
            .clone()),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn wrap_socketid<'gc>(ctx: Context<'gc>, socket: &WebSocketId) -> Value<'gc> {
 | 
			
		||||
    UserData::new::<Rootable![WebSocketId]>(&ctx, socket.clone()).into()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn try_unwrap_socketid<'gc>(
 | 
			
		||||
    ctx: Context<'gc>,
 | 
			
		||||
    value: &Value<'gc>,
 | 
			
		||||
) -> Result<WebSocketId, piccolo::Error<'gc>> {
 | 
			
		||||
    Ok(UserData::from_value(ctx, *value)?
 | 
			
		||||
        .downcast::<Rootable![WebSocketId]>()?
 | 
			
		||||
        .clone())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn handle_websocket_output(
 | 
			
		||||
    socket: &WebSocketId,
 | 
			
		||||
    engine: &mut LuaState,
 | 
			
		||||
    input: &[u8],
 | 
			
		||||
) -> Result<(), String> {
 | 
			
		||||
    engine
 | 
			
		||||
        .interp
 | 
			
		||||
        .try_enter(|ctx| {
 | 
			
		||||
            let handlers = Table::from_value(ctx, ctx.get_global(ctx.intern_static(b"handlers")))?;
 | 
			
		||||
            let input_fn =
 | 
			
		||||
                Function::from_value(ctx, handlers.get(ctx, ctx.intern_static(b"mudoutput")))?;
 | 
			
		||||
            ctx.fetch(&engine.exec).restart(
 | 
			
		||||
                ctx,
 | 
			
		||||
                input_fn,
 | 
			
		||||
                (wrap_socketid(ctx, socket), ctx.intern(input)),
 | 
			
		||||
            );
 | 
			
		||||
            Ok(())
 | 
			
		||||
        })
 | 
			
		||||
        .map_err(|err| format!("{}", err))?;
 | 
			
		||||
    engine
 | 
			
		||||
        .interp
 | 
			
		||||
        .execute::<()>(&engine.exec)
 | 
			
		||||
        .map_err(|err| format!("{}", err))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn handle_websocket_output_log_err(socket: &WebSocketId, engine: &mut LuaState, input: &[u8]) {
 | 
			
		||||
    match handle_websocket_output(socket, engine, input) {
 | 
			
		||||
        Ok(()) => {}
 | 
			
		||||
        Err(e) => console::log_2(
 | 
			
		||||
            &JsValue::from_str("An error occurred calling the WebSocket input handler"),
 | 
			
		||||
            &JsValue::from_str(&e),
 | 
			
		||||
        ),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn handle_websocket_close(socket: &WebSocketId, engine: &mut LuaState) -> Result<(), String> {
 | 
			
		||||
    engine
 | 
			
		||||
        .interp
 | 
			
		||||
        .try_enter(|ctx| {
 | 
			
		||||
            let handlers = Table::from_value(ctx, ctx.get_global(ctx.intern_static(b"handlers")))?;
 | 
			
		||||
            let input_fn =
 | 
			
		||||
                Function::from_value(ctx, handlers.get(ctx, ctx.intern_static(b"mudclose")))?;
 | 
			
		||||
            ctx.fetch(&engine.exec)
 | 
			
		||||
                .restart(ctx, input_fn, wrap_socketid(ctx, socket));
 | 
			
		||||
            Ok(())
 | 
			
		||||
        })
 | 
			
		||||
        .map_err(|err| format!("{}", err))?;
 | 
			
		||||
    engine
 | 
			
		||||
        .interp
 | 
			
		||||
        .execute::<()>(&engine.exec)
 | 
			
		||||
        .map_err(|err| format!("{}", err))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn handle_websocket_close_log_err(socket: &WebSocketId, engine: &mut LuaState) {
 | 
			
		||||
    match handle_websocket_close(socket, engine) {
 | 
			
		||||
        Ok(()) => {}
 | 
			
		||||
        Err(e) => console::log_2(
 | 
			
		||||
            &JsValue::from_str("An error occurred calling the WebSocket input handler"),
 | 
			
		||||
            &JsValue::from_str(&e),
 | 
			
		||||
        ),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn sendmud_raw<'gc>(
 | 
			
		||||
    ctx: Context<'gc>,
 | 
			
		||||
    global_memo: &GlobalMemoCell,
 | 
			
		||||
    _global_layout: &UseStateSetter<GlobalLayoutCell>,
 | 
			
		||||
) -> Callback<'gc> {
 | 
			
		||||
    let global_memo = global_memo.clone();
 | 
			
		||||
    Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
 | 
			
		||||
        let mud: WebSocketId = try_unwrap_socketid(ctx, &stack.pop_front())?;
 | 
			
		||||
        let msg: piccolo::String = stack.from_front(ctx)?;
 | 
			
		||||
        send_message_to_mud(&mud, msg.as_bytes(), &global_memo)?;
 | 
			
		||||
        Ok(piccolo::CallbackReturn::Return)
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn connect_mud<'gc>(
 | 
			
		||||
    ctx: Context<'gc>,
 | 
			
		||||
    global_memo: &GlobalMemoCell,
 | 
			
		||||
    _global_layout: &UseStateSetter<GlobalLayoutCell>,
 | 
			
		||||
) -> Callback<'gc> {
 | 
			
		||||
    let global_memo = global_memo.clone();
 | 
			
		||||
    Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
 | 
			
		||||
        let trusted: bool = false;
 | 
			
		||||
        let name: String = loop {
 | 
			
		||||
            let v: String = stack.from_front(ctx)?;
 | 
			
		||||
            if v == "-trust" {
 | 
			
		||||
                trusted = true;
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            break v;
 | 
			
		||||
        };
 | 
			
		||||
        let name: Value<'gc> = ctx.intern(debrace(&name).as_bytes()).into();
 | 
			
		||||
 | 
			
		||||
        let muds = Table::from_value(ctx, ctx.get_global(ctx.intern_static(b"muds")))?;
 | 
			
		||||
        if !muds.get_value(name).is_nil() {
 | 
			
		||||
            Err(Error::msg(
 | 
			
		||||
                "Attempt to create MUD connection using name that's already taken",
 | 
			
		||||
            ))?
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let url: String = stack.from_front(ctx)?;
 | 
			
		||||
        let new_socket = connect_websocket(
 | 
			
		||||
            trusted,
 | 
			
		||||
            &url,
 | 
			
		||||
            &mut global_memo.ws_registry.borrow_mut(),
 | 
			
		||||
            &global_memo,
 | 
			
		||||
        )?;
 | 
			
		||||
 | 
			
		||||
        ctx.registry.singleton()
 | 
			
		||||
        
 | 
			
		||||
        muds.set(ctx, name, new_socket)?;
 | 
			
		||||
 | 
			
		||||
        let mud: WebSocketId = try_unwrap_socketid(ctx, &stack.pop_front())?;
 | 
			
		||||
        let msg: piccolo::String = stack.from_front(ctx)?;
 | 
			
		||||
        send_message_to_mud(&mud, msg.as_bytes(), &global_memo)?;
 | 
			
		||||
        Ok(piccolo::CallbackReturn::Return)
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -11,15 +11,18 @@ pub mod parsing;
 | 
			
		||||
pub mod split_panel;
 | 
			
		||||
pub mod term_split;
 | 
			
		||||
pub mod term_view;
 | 
			
		||||
pub mod websocket;
 | 
			
		||||
use crate::lua_state::{install_lua_globals, LuaState};
 | 
			
		||||
use crate::split_panel::*;
 | 
			
		||||
use crate::term_view::*;
 | 
			
		||||
use crate::websocket::RegisteredWebSockets;
 | 
			
		||||
 | 
			
		||||
#[derive(Properties)]
 | 
			
		||||
pub struct GlobalMemoState {
 | 
			
		||||
    // No strong references allowed between each of these groups of state.
 | 
			
		||||
    frame_registry: RefCell<RegisteredTermFrames>,
 | 
			
		||||
    lua_engine: RefCell<LuaState>,
 | 
			
		||||
    ws_registry: RefCell<RegisteredWebSockets>,
 | 
			
		||||
 | 
			
		||||
    // A cache of the latest layout info (separate from the state).
 | 
			
		||||
    // Updating this doesn't force a relayout, so only update the cache when
 | 
			
		||||
@ -59,6 +62,7 @@ fn app() -> Html {
 | 
			
		||||
    });
 | 
			
		||||
    let global_memo = use_memo((), |_| GlobalMemoState {
 | 
			
		||||
        frame_registry: RegisteredTermFrames::new().into(),
 | 
			
		||||
        ws_registry: RegisteredWebSockets::new().into(),
 | 
			
		||||
        lua_engine: LuaState::setup().expect("Can create interpreter").into(),
 | 
			
		||||
        layout: RefCell::new((*global_layout).clone()),
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
 | 
			
		||||
use gc_arena::Collect;
 | 
			
		||||
use wasm_bindgen::prelude::*;
 | 
			
		||||
use web_sys::{Element, Node};
 | 
			
		||||
use yew::prelude::*;
 | 
			
		||||
@ -65,7 +66,8 @@ extern "C" {
 | 
			
		||||
    fn fit(this: &FitAddon);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Eq, Ord, Hash, PartialEq, PartialOrd, Clone, Debug)]
 | 
			
		||||
#[derive(Eq, Ord, Hash, PartialEq, PartialOrd, Clone, Debug, Collect)]
 | 
			
		||||
#[collect(require_static)]
 | 
			
		||||
pub struct TermFrame(pub u64);
 | 
			
		||||
 | 
			
		||||
#[derive(Properties)]
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										140
									
								
								src/websocket.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								src/websocket.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,140 @@
 | 
			
		||||
use std::collections::BTreeMap;
 | 
			
		||||
 | 
			
		||||
use gc_arena::Collect;
 | 
			
		||||
use serde::Deserialize;
 | 
			
		||||
use wasm_bindgen::{closure::Closure, JsCast, JsValue};
 | 
			
		||||
use web_sys::{
 | 
			
		||||
    console,
 | 
			
		||||
    js_sys::{ArrayBuffer, JsString, Uint8Array},
 | 
			
		||||
    BinaryType, DomException, MessageEvent, WebSocket,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    lua_state::{handle_websocket_close_log_err, handle_websocket_output_log_err},
 | 
			
		||||
    GlobalMemoCell,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(PartialEq, PartialOrd, Eq, Ord, Debug, Clone, Collect)]
 | 
			
		||||
#[collect(require_static)]
 | 
			
		||||
pub struct WebSocketId(pub u64);
 | 
			
		||||
pub struct WebSocketData {
 | 
			
		||||
    pub connection: WebSocket,
 | 
			
		||||
    pub trusted: bool, // Is it allowed to submit Lua to be run?
 | 
			
		||||
    pub closed: bool,
 | 
			
		||||
    pub url: String,
 | 
			
		||||
    pub retained_closures: Option<(Closure<dyn FnMut(MessageEvent)>, Closure<dyn FnMut()>)>,
 | 
			
		||||
}
 | 
			
		||||
pub type RegisteredWebSockets = BTreeMap<WebSocketId, WebSocketData>;
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize)]
 | 
			
		||||
pub enum MessageFromServer {
 | 
			
		||||
    RunLua(String),
 | 
			
		||||
    #[serde(other)]
 | 
			
		||||
    Unknown,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn connect_websocket(
 | 
			
		||||
    trusted: bool,
 | 
			
		||||
    url: &str,
 | 
			
		||||
    sockets: &mut RegisteredWebSockets,
 | 
			
		||||
    // Only used for callbacks, expected sockets already borrowed mut!
 | 
			
		||||
    globals: &GlobalMemoCell,
 | 
			
		||||
) -> anyhow::Result<WebSocketId> {
 | 
			
		||||
    let mut data = WebSocketData {
 | 
			
		||||
        connection: WebSocket::new(url).map_err(|e| {
 | 
			
		||||
            anyhow::Error::msg(
 | 
			
		||||
                e.dyn_into::<DomException>()
 | 
			
		||||
                    .map(|e| e.message().to_string())
 | 
			
		||||
                    .unwrap_or("Unknown error connecting".to_owned()),
 | 
			
		||||
            )
 | 
			
		||||
        })?,
 | 
			
		||||
        trusted,
 | 
			
		||||
        closed: false,
 | 
			
		||||
        url: url.to_owned(),
 | 
			
		||||
        retained_closures: None,
 | 
			
		||||
    };
 | 
			
		||||
    data.connection.set_binary_type(BinaryType::Arraybuffer);
 | 
			
		||||
 | 
			
		||||
    let new_id = sockets
 | 
			
		||||
        .last_key_value()
 | 
			
		||||
        .map_or(WebSocketId(0), |v| WebSocketId(v.0 .0 + 1));
 | 
			
		||||
    let data_globals = globals.clone();
 | 
			
		||||
    let data_new_id = new_id.clone();
 | 
			
		||||
    let data_closure: Closure<dyn FnMut(MessageEvent)> = Closure::new(move |ev: MessageEvent| {
 | 
			
		||||
        let data = ev.data();
 | 
			
		||||
        if data.has_type::<ArrayBuffer>() {
 | 
			
		||||
            handle_websocket_output_log_err(
 | 
			
		||||
                &data_new_id,
 | 
			
		||||
                &mut data_globals.lua_engine.borrow_mut(),
 | 
			
		||||
                &Uint8Array::new(&data).to_vec(),
 | 
			
		||||
            );
 | 
			
		||||
        } else if data.has_type::<JsString>() {
 | 
			
		||||
            let msg: String = data.unchecked_into::<JsString>().into();
 | 
			
		||||
            if let Some(latest_data) = data_globals.ws_registry.borrow().get(&data_new_id) {
 | 
			
		||||
                if latest_data.trusted {
 | 
			
		||||
                    match data_globals.lua_engine.borrow_mut().execute(&msg) {
 | 
			
		||||
                        Ok(()) => {}
 | 
			
		||||
                        Err(e) => console::log_3(
 | 
			
		||||
                            &JsValue::from_str("Error executing Lua from websocket"),
 | 
			
		||||
                            &JsValue::from_str(&latest_data.url),
 | 
			
		||||
                            &JsValue::from_str(&e),
 | 
			
		||||
                        ),
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    console::log_2(
 | 
			
		||||
                        &JsValue::from_str("Ignoring Lua from untrusted websocket."),
 | 
			
		||||
                        &JsValue::from_str(&latest_data.url),
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    let close_globals = globals.clone();
 | 
			
		||||
    let close_id = new_id.clone();
 | 
			
		||||
    let close_closure: Closure<dyn FnMut()> =
 | 
			
		||||
        Closure::new(
 | 
			
		||||
            move || match close_globals.ws_registry.borrow_mut().get_mut(&close_id) {
 | 
			
		||||
                None => {}
 | 
			
		||||
                Some(closed_socket) => {
 | 
			
		||||
                    closed_socket.closed = true;
 | 
			
		||||
                    closed_socket.retained_closures = None;
 | 
			
		||||
                    handle_websocket_close_log_err(
 | 
			
		||||
                        &close_id,
 | 
			
		||||
                        &mut close_globals.lua_engine.borrow_mut(),
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    data.connection
 | 
			
		||||
        .add_event_listener_with_callback("message", data_closure.as_ref().unchecked_ref())
 | 
			
		||||
        .expect("Couldn't set message handler on WebSocket");
 | 
			
		||||
    data.connection
 | 
			
		||||
        .add_event_listener_with_callback("close", close_closure.as_ref().unchecked_ref())
 | 
			
		||||
        .expect("Couldn't set close handler on WebSocket");
 | 
			
		||||
    data.connection
 | 
			
		||||
        .add_event_listener_with_callback("error", close_closure.as_ref().unchecked_ref())
 | 
			
		||||
        .expect("Couldn't set error handler on WebSocket");
 | 
			
		||||
    data.retained_closures = Some((data_closure, close_closure));
 | 
			
		||||
    sockets.insert(new_id.clone(), data);
 | 
			
		||||
    Ok(new_id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn send_message_to_mud(
 | 
			
		||||
    socket: &WebSocketId,
 | 
			
		||||
    msg: &[u8],
 | 
			
		||||
    global: &GlobalMemoCell,
 | 
			
		||||
) -> anyhow::Result<()> {
 | 
			
		||||
    match global.ws_registry.borrow().get(socket) {
 | 
			
		||||
        None => Err(anyhow::Error::msg("MUD connection not found")),
 | 
			
		||||
        Some(sock_data) if sock_data.closed => Err(anyhow::Error::msg("MUD connection is closed")),
 | 
			
		||||
        Some(sock_data) => {
 | 
			
		||||
            sock_data.connection.send_with_u8_array(msg).map_err(|e| {
 | 
			
		||||
                e.dyn_into::<DomException>()
 | 
			
		||||
                    .map(|e| anyhow::Error::msg(e.message()))
 | 
			
		||||
                    .unwrap_or_else(|_| anyhow::Error::msg("Unexpected exception while sending"))
 | 
			
		||||
            })?;
 | 
			
		||||
            Ok(())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user