wasm-rdp/webrdp/src/lib.rs
2022-10-20 07:34:38 +00:00

193 lines
6.1 KiB
Rust

mod canvas;
mod rdp;
mod utils;
use canvas::CanvasUtils;
use rdp::Rdp;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::{ErrorEvent, HtmlButtonElement, MessageEvent, WebSocket};
#[macro_export]
macro_rules! console_log {
($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
}
#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
#[wasm_bindgen(js_namespace = console)]
pub fn log(s: &str);
pub fn setClipBoard(s: String);
pub fn getClipBoard() -> String;
}
fn rdp_close_handle(rdp: &Rdp, canvas: &CanvasUtils, msg: &str) {
rdp.close();
// unsafe {
// REFRESHER.take();
// }
canvas.close();
let status = web_sys::window()
.unwrap()
.document()
.unwrap()
.get_element_by_id("rdp_status")
.unwrap();
status.set_text_content(Some(msg));
}
fn rdp_out_handler(ws: &WebSocket, rdp: &Rdp, canvas: &CanvasUtils) {
let out = rdp.get_output();
if let Some(out) = out {
for ref o in out {
match o {
rdp::RdpOutput::Err(err) => {
console_log!("Err {}", err);
rdp_close_handle(rdp, canvas, err);
}
rdp::RdpOutput::WsBuf(buf) => match ws.send_with_u8_array(buf) {
Ok(_) => {}
Err(err) => {
let err = format!("error sending message: {:?}", err);
rdp_close_handle(rdp, canvas, &err);
}
},
rdp::RdpOutput::RequireSSL => match ws.send_with_str("SSL") {
Ok(_) => {}
Err(err) => {
let err = format!("error launching ssl: {:?}", err);
rdp_close_handle(rdp, canvas, &err);
}
},
rdp::RdpOutput::RequirePassword => {
// let pwd = prompt("Please input the password");
// rdp.set_credential(&pwd);
// rdp_out_handler(ws, rdp, canvas);
}
rdp::RdpOutput::RenderImage(ri) => {
canvas.draw(ri);
}
rdp::RdpOutput::SetResolution(x, y) => {
canvas.init(*x as u32, *y as u32);
canvas.bind(rdp);
// rdp.require_frame(0);
rdp_out_handler(ws, rdp, canvas);
// let vnc_cloned = rdp.clone();
// let ws_cloned = ws.clone();
// let canvas_cloned = canvas.clone();
// set a interval for fps enhance
// let refresh = move || {
// vnc_cloned.require_frame(1);
// rdp_out_handler(&ws_cloned, &vnc_cloned, &canvas_cloned);
// };
// let refersher = Interval::new(20, refresh);
// unsafe {
// REFRESHER = Some(refersher);
// }
}
rdp::RdpOutput::SetClipboard(text) => {
setClipBoard(text.to_owned());
// ConsoleService::log(&self.error_msg);
}
}
}
}
}
fn start_websocket() -> Result<(), JsValue> {
// connect
let url = format!(
"{scheme}://{host}/websockify",
scheme = if web_sys::window()
.unwrap()
.location()
.protocol()?
.starts_with("https")
{
"wss"
} else {
"ws"
},
host = web_sys::window().unwrap().location().host()?
);
let ws = WebSocket::new_with_str(&url, "binary")?;
let canvas = CanvasUtils::new();
let rdp = Rdp::new();
let clipboard = web_sys::window()
.unwrap()
.document()
.unwrap()
.get_element_by_id("clipboardsend")
.unwrap()
.dyn_into::<HtmlButtonElement>()
.map_err(|_| ())
.unwrap();
let rdp_cloned = rdp.clone();
let onclickcb = Closure::<dyn FnMut()>::new(move || {
console_log!("Send {:?}", getClipBoard());
rdp_cloned.set_clipboard(&getClipBoard());
});
clipboard.set_onclick(Some(onclickcb.as_ref().unchecked_ref()));
onclickcb.forget();
ws.set_binary_type(web_sys::BinaryType::Arraybuffer);
// on message
let cloned_ws = ws.clone();
let rdp_cloned = rdp.clone();
let canvas_cloned = canvas.clone();
let onmessage_callback = Closure::<dyn FnMut(_)>::new(move |e: MessageEvent| {
if let Ok(abuf) = e.data().dyn_into::<js_sys::ArrayBuffer>() {
let array = js_sys::Uint8Array::new(&abuf);
// let mut canvas_ctx = None;
rdp_cloned.do_input(array.to_vec());
rdp_out_handler(&cloned_ws, &rdp_cloned, &canvas_cloned);
} else {
console_log!("message event, received Unknown: {:?}", e.data());
}
});
ws.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref()));
// forget the callback to keep it alive
onmessage_callback.forget();
// onerror
let onerror_callback = Closure::<dyn FnMut(_)>::new(move |e: ErrorEvent| {
console_log!("error event: {:?}", e);
});
ws.set_onerror(Some(onerror_callback.as_ref().unchecked_ref()));
onerror_callback.forget();
// onopen
let rdp_cloned = rdp.clone();
let ws_cloned = ws.clone();
let canvas_cloned = canvas.clone();
let onopen_callback = Closure::<dyn FnMut()>::new(move || {
console_log!("socket opened");
rdp_cloned.init();
rdp_out_handler(&ws_cloned, &rdp_cloned, &canvas_cloned);
});
ws.set_onopen(Some(onopen_callback.as_ref().unchecked_ref()));
onopen_callback.forget();
let onclose_callback = Closure::<dyn FnMut()>::new(move || {
console_log!("socket close");
rdp_close_handle(&rdp, &canvas, "Disconnected");
});
ws.set_onclose(Some(onclose_callback.as_ref().unchecked_ref()));
onclose_callback.forget();
Ok(())
}
#[wasm_bindgen(start)]
pub fn run_app() -> Result<(), JsValue> {
utils::set_panic_hook();
start_websocket()
}