A worked simple webrdp

This commit is contained in:
Jovi Hsu 2022-10-25 05:02:48 +00:00
parent a031a9d047
commit 10e5ab5311
9 changed files with 456 additions and 126 deletions

View File

@ -15,12 +15,14 @@ wasm-bindgen = "0.2.63"
js-sys = "0.3"
x509-parser = "0.14.0"
rdp-rs = { path = "./rdp-rs", default-features = false }
# websocket
ws_stream_wasm = { version = "^0.7", features = ["tokio_io"] }
async_io_stream = { version = "^0.3", features = ["tokio_io"] }
pharos = "0.5.3"
# async
wasm-bindgen-futures = "0.4.33"
futures = "0.3.25"
async-trait = "0.1.58"
tokio = { version = "^1", features = [
"sync",
"macros",
@ -28,6 +30,11 @@ tokio = { version = "^1", features = [
"rt",
"time"
]}
async-trait = "0.1.58"
# log
tracing = "^0.1"
tracing-wasm = "0.2.1"
# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires

@ -1 +1 @@
Subproject commit c340a749868f70fde328bf15c751f843da6e119e
Subproject commit bbb0eaf86fe016ebf5414c6cd0125d1e374c1877

View File

@ -1,21 +1,22 @@
use crate::input::{InputEvent, KeyEventType, MouseEventType};
use rdp::core::event::BitmapEvent;
use std::rc::Rc;
use crate::{
console_log, log,
rdp_client::{ImageData, ImageType, MouseEventType, Rdp},
};
use tokio::sync::mpsc;
use tracing::warn;
use wasm_bindgen::prelude::*;
use wasm_bindgen::{Clamped, JsCast};
use web_sys::{
CanvasRenderingContext2d, HtmlButtonElement, HtmlCanvasElement, KeyboardEvent, MouseEvent,
};
struct Canvas {
canvas: HtmlCanvasElement,
ctx: CanvasRenderingContext2d,
output: mpsc::Sender<InputEvent>,
}
impl Canvas {
fn new() -> Self {
fn new(sender: mpsc::Sender<InputEvent>) -> Self {
let document = web_sys::window().unwrap().document().unwrap();
let canvas = document.get_element_by_id("rdp-canvas").unwrap();
let canvas: HtmlCanvasElement = canvas
@ -28,7 +29,11 @@ impl Canvas {
.unwrap()
.dyn_into::<CanvasRenderingContext2d>()
.unwrap();
Self { canvas, ctx }
Self {
canvas,
ctx,
output: sender,
}
}
fn set_resolution(&self, width: u32, height: u32) {
@ -39,12 +44,17 @@ impl Canvas {
self.ctx.fill();
}
fn bind(&self, rdp: &Rdp) {
let handler = rdp.clone();
fn bind(&self) {
let sender = self.output.clone();
let key_down = move |e: KeyboardEvent| {
let sender = sender.clone();
e.prevent_default();
e.stop_propagation();
handler.key_press(e, true);
futures::executor::block_on(async move {
let _ = sender
.send(InputEvent::Keyboard(e, KeyEventType::Down))
.await;
});
};
let handler = Box::new(key_down) as Box<dyn FnMut(_)>;
@ -56,11 +66,14 @@ impl Canvas {
.unwrap();
cb.forget();
let handler = rdp.clone();
let sender = self.output.clone();
let key_up = move |e: KeyboardEvent| {
let sender = sender.clone();
e.prevent_default();
e.stop_propagation();
handler.key_press(e, false);
futures::executor::block_on(async move {
let _ = sender.send(InputEvent::Keyboard(e, KeyEventType::Up)).await;
});
};
let handler = Box::new(key_up) as Box<dyn FnMut(_)>;
@ -72,7 +85,7 @@ impl Canvas {
.unwrap();
cb.forget();
let handler = rdp.clone();
let sender = self.output.clone();
let ctrl_alt_del_btn = web_sys::window()
.unwrap()
.document()
@ -83,7 +96,45 @@ impl Canvas {
.map_err(|_| ())
.unwrap();
let ctrl_alt_del = move || {
handler.ctrl_alt_del();
let sender = sender.clone();
futures::executor::block_on(async move {
let _ = sender
.send(InputEvent::KeyCode(
0x001D, /* Control Left */
KeyEventType::Down,
))
.await;
let _ = sender
.send(InputEvent::KeyCode(
0x0038, /* Alt Left */
KeyEventType::Down,
))
.await;
let _ = sender
.send(InputEvent::KeyCode(
0xE053, /* Delete */
KeyEventType::Down,
))
.await;
let _ = sender
.send(InputEvent::KeyCode(
0xE053, /* Delete */
KeyEventType::Up,
))
.await;
let _ = sender
.send(InputEvent::KeyCode(
0x0038, /* Alt Left */
KeyEventType::Up,
))
.await;
let _ = sender
.send(InputEvent::KeyCode(
0x001D, /* Control Left */
KeyEventType::Up,
))
.await;
});
};
let handler = Box::new(ctrl_alt_del) as Box<dyn FnMut()>;
@ -100,10 +151,16 @@ impl Canvas {
// to do:
// calculate relation position
let handler = rdp.clone();
let sender = self.output.clone();
let mouse_move = move |e: MouseEvent| {
let sender = sender.clone();
e.prevent_default();
e.stop_propagation();
handler.mouse_event(e, MouseEventType::Move);
futures::executor::block_on(async move {
let _ = sender
.send(InputEvent::Mouse(e, MouseEventType::Move))
.await;
});
};
let handler = Box::new(mouse_move) as Box<dyn FnMut(_)>;
@ -115,10 +172,16 @@ impl Canvas {
.unwrap();
cb.forget();
let handler = rdp.clone();
let sender = self.output.clone();
let mouse_down = move |e: MouseEvent| {
let sender = sender.clone();
// e.prevent_default();
e.stop_propagation();
handler.mouse_event(e, MouseEventType::Down);
futures::executor::block_on(async move {
let _ = sender
.send(InputEvent::Mouse(e, MouseEventType::Down))
.await;
});
};
let handler = Box::new(mouse_down) as Box<dyn FnMut(_)>;
@ -130,10 +193,14 @@ impl Canvas {
.unwrap();
cb.forget();
let handler = rdp.clone();
let sender = self.output.clone();
let mouse_up = move |e: MouseEvent| {
let sender = sender.clone();
e.prevent_default();
e.stop_propagation();
handler.mouse_event(e, MouseEventType::Up);
futures::executor::block_on(async move {
let _ = sender.send(InputEvent::Mouse(e, MouseEventType::Up)).await;
});
};
let handler = Box::new(mouse_up) as Box<dyn FnMut(_)>;
@ -160,53 +227,53 @@ impl Canvas {
cb.forget();
}
fn draw(&self, ri: &ImageData) {
match ri.type_ {
ImageType::Copy => {
//copy
let sx = (ri.data[0] as u16) << 8 | ri.data[1] as u16;
let sy = (ri.data[2] as u16) << 8 | ri.data[3] as u16;
fn draw(&self, bm: BitmapEvent) {
let bitmap_dest_left = bm.dest_left as u32;
let _bitmap_dest_right = bm.dest_right as u32;
let _bitmap_dest_bottom = bm.dest_bottom as u32;
let bitmap_dest_top = bm.dest_top as u32;
let bitmap_width = bm.width as u32;
let bitmap_height = bm.height as u32;
let _ = self
.ctx
.draw_image_with_html_canvas_element_and_sw_and_sh_and_dx_and_dy_and_dw_and_dh(
&self.canvas,
sx as f64,
sy as f64,
ri.width as f64,
ri.height as f64,
ri.x as f64,
ri.y as f64,
ri.width as f64,
ri.height as f64,
);
let mut data = bm.decompress().unwrap();
let mut y = 0;
let mut x = 0;
while y < bitmap_height {
while x < bitmap_width {
let idx = (y as usize * bitmap_width as usize + x as usize) * 4;
data.swap(idx, idx + 2);
data[idx + 3] = 255;
x += 1;
}
ImageType::Fill => {
// fill
let (r, g, b) = (ri.data[2], ri.data[1], ri.data[0]);
let style = format!("rgb({},{},{})", r, g, b);
self.ctx.set_fill_style(&JsValue::from_str(&style));
x = 0;
y += 1;
}
ImageType::Raw => {
let data = web_sys::ImageData::new_with_u8_clamped_array_and_sh(
Clamped(&ri.data),
ri.width as u32,
ri.height as u32,
Clamped(&data),
bitmap_width as u32,
bitmap_height as u32,
);
if data.is_err() {
console_log!(
"renderring failed at ({}, {}), width {}, height {}, len {}",
ri.x,
ri.y,
ri.width,
ri.height,
ri.data.len(),
warn!(
"renderring failed at ({}, {}), width {}, height {}",
bitmap_dest_left, bitmap_dest_top, bitmap_width, bitmap_height,
);
} else {
//
// trace!(
// "draw x:{}-{}, y:{}-{}",
// bitmap_dest_left,
// bitmap_dest_right,
// bitmap_dest_top,
// bitmap_dest_bottom
// );
}
let data = data.unwrap();
let _ = self.ctx.put_image_data(&data, ri.x as f64, ri.y as f64);
}
}
let _ = self
.ctx
.put_image_data(&data, bitmap_dest_left as f64, bitmap_dest_top as f64);
}
fn close(&self) {
@ -227,22 +294,19 @@ impl Clone for CanvasUtils {
}
impl CanvasUtils {
pub fn new() -> Self {
pub fn new(sender: mpsc::Sender<InputEvent>) -> Self {
Self {
inner: Rc::new(Canvas::new()),
inner: Rc::new(Canvas::new(sender)),
}
}
pub fn init(&self, width: u32, height: u32) {
self.inner.as_ref().set_resolution(width, height);
self.inner.as_ref().bind();
}
pub fn bind(&self, rdp: &Rdp) {
self.inner.as_ref().bind(rdp);
}
pub fn draw(&self, ri: &ImageData) {
self.inner.as_ref().draw(ri);
pub fn draw(&self, bm: BitmapEvent) {
self.inner.as_ref().draw(bm);
}
pub fn close(&self) {

206
webrdp/src/input.rs Normal file
View File

@ -0,0 +1,206 @@
use rdp::core::event::{KeyboardEvent as RdpKeyBorad, PointerButton, PointerEvent, RdpEvent};
use tracing::trace;
use web_sys::{KeyboardEvent, MouseEvent};
#[derive(Debug)]
pub enum MouseEventType {
Down,
Up,
Move,
}
#[derive(Debug)]
pub enum KeyEventType {
Down,
Up,
}
pub enum InputEvent {
Mouse(MouseEvent, MouseEventType),
Keyboard(KeyboardEvent, KeyEventType),
KeyCode(u16, KeyEventType),
}
fn to_scancode(code: &str) -> u16 {
match code {
"Escape" => 0x0001,
"Digit1" => 0x0002,
"Digit2" => 0x0003,
"Digit3" => 0x0004,
"Digit4" => 0x0005,
"Digit5" => 0x0006,
"Digit6" => 0x0007,
"Digit7" => 0x0008,
"Digit8" => 0x0009,
"Digit9" => 0x000A,
"Digit0" => 0x000B,
"Minus" => 0x000C,
"Equal" => 0x000D,
"Backspace" => 0x000E,
"Tab" => 0x000F,
"KeyQ" => 0x0010,
"KeyW" => 0x0011,
"KeyE" => 0x0012,
"KeyR" => 0x0013,
"KeyT" => 0x0014,
"KeyY" => 0x0015,
"KeyU" => 0x0016,
"KeyI" => 0x0017,
"KeyO" => 0x0018,
"KeyP" => 0x0019,
"BracketLeft" => 0x001A,
"BracketRight" => 0x001B,
"Enter" => 0x001C,
"ControlLeft" => 0x001D,
"KeyA" => 0x001E,
"KeyS" => 0x001F,
"KeyD" => 0x0020,
"KeyF" => 0x0021,
"KeyG" => 0x0022,
"KeyH" => 0x0023,
"KeyJ" => 0x0024,
"KeyK" => 0x0025,
"KeyL" => 0x0026,
"Semicolon" => 0x0027,
"Quote" => 0x0028,
"Backquote" => 0x0029,
"ShiftLeft" => 0x002A,
"Backslash" => 0x002B,
"KeyZ" => 0x002C,
"KeyX" => 0x002D,
"KeyC" => 0x002E,
"KeyV" => 0x002F,
"KeyB" => 0x0030,
"KeyN" => 0x0031,
"KeyM" => 0x0032,
"Comma" => 0x0033,
"Period" => 0x0034,
"Slash" => 0x0035,
"ShiftRight" => 0x0036,
"NumpadMultiply" => 0x0037,
"AltLeft" => 0x0038,
"Space" => 0x0039,
"CapsLock" => 0x003A,
"F1" => 0x003B,
"F2" => 0x003C,
"F3" => 0x003D,
"F4" => 0x003E,
"F5" => 0x003F,
"F6" => 0x0040,
"F7" => 0x0041,
"F8" => 0x0042,
"F9" => 0x0043,
"F10" => 0x0044,
"Pause" => 0x0045,
"ScrollLock" => 0x0046,
"Numpad7" => 0x0047,
"Numpad8" => 0x0048,
"Numpad9" => 0x0049,
"NumpadSubtract" => 0x004A,
"Numpad4" => 0x004B,
"Numpad5" => 0x004C,
"Numpad6" => 0x004D,
"NumpadAdd" => 0x004E,
"Numpad1" => 0x004F,
"Numpad2" => 0x0050,
"Numpad3" => 0x0051,
"Numpad0" => 0x0052,
"NumpadDecimal" => 0x0053,
"IntlBackslash" => 0x0056,
"F11" => 0x0057,
"F12" => 0x0058,
"NumpadEqual" => 0x0059,
"F13" => 0x0064,
"F14" => 0x0065,
"F15" => 0x0066,
"F16" => 0x0067,
"F17" => 0x0068,
"F18" => 0x0069,
"F19" => 0x006A,
"F20" => 0x006B,
"F21" => 0x006C,
"F22" => 0x006D,
"F23" => 0x006E,
"KanaMode" => 0x0070,
"Lang2" => 0x0071,
"Lang1" => 0x0072,
"IntlRo" => 0x0073,
"F24" => 0x0076,
"Convert" => 0x0079,
"NonConvert" => 0x007B,
"IntlYen" => 0x007D,
"NumpadComma" => 0x007E,
"MediaTrackPrevious" => 0xE010,
"MediaTrackNext" => 0xE019,
"NumpadEnter" => 0xE01C,
"ControlRight" => 0xE01D,
"AudioVolumeMute" => 0xE020,
"LaunchApp2" => 0xE021,
"MediaPlayPause" => 0xE022,
"MediaStop" => 0xE024,
"BrowserHome" => 0xE032,
"NumpadDivide" => 0xE035,
"PrintScreen" => 0xE037,
"AltRight" => 0xE038,
"NumLock" => 0xE045,
// "Pause" => 0xE046,
"Home" => 0xE047,
"ArrowUp" => 0xE048,
"PageUp" => 0xE049,
"ArrowLeft" => 0xE04B,
"ArrowRight" => 0xE04D,
"End" => 0xE04F,
"ArrowDown" => 0xE050,
"PageDown" => 0xE051,
"Insert" => 0xE052,
"Delete" => 0xE053,
"ContextMenu" => 0xE05D,
"Power" => 0xE05E,
"BrowserSearch" => 0xE065,
"BrowserFavorites" => 0xE066,
"BrowserRefresh" => 0xE067,
"BrowserStop" => 0xE068,
"BrowserForward" => 0xE069,
"BrowserBack" => 0xE06A,
"LaunchApp1" => 0xE06B,
"LaunchMail" => 0xE06C,
"MediaSelect" => 0xE06D,
_ => 0x0000,
}
}
impl From<InputEvent> for RdpEvent {
fn from(i: InputEvent) -> Self {
match i {
InputEvent::Mouse(e, t) => RdpEvent::Pointer(PointerEvent {
x: e.offset_x().try_into().unwrap_or(0),
y: e.offset_y().try_into().unwrap_or(0),
button: match e.button() {
0 => {
if let MouseEventType::Move = t {
PointerButton::None
} else {
PointerButton::Left
}
}
1 => PointerButton::Middle,
2 => PointerButton::Right,
_ => PointerButton::None,
},
down: matches!(t, MouseEventType::Down),
}),
InputEvent::Keyboard(e, t) => {
trace!("Key {}, event {:?}", e.code(), t);
RdpEvent::Key(RdpKeyBorad {
code: to_scancode(&e.code()),
down: matches!(t, KeyEventType::Down),
})
}
InputEvent::KeyCode(e, t) => RdpEvent::Key(RdpKeyBorad {
code: e,
down: matches!(t, KeyEventType::Down),
}),
}
}
}

View File

@ -1,20 +1,17 @@
mod canvas;
mod input;
mod rdp_ws;
mod utils;
use rdp_ws::Rdp;
use tracing::warn;
use tracing_wasm::WASMLayerConfigBuilder;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::spawn_local;
#[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;
}
@ -42,7 +39,10 @@ fn start_websocket() -> Result<(), JsValue> {
spawn_local(async move {
let mut rdp = Rdp::new(&url, "", "", "");
while !rdp.start().await {}
while !rdp.start().await {
warn!("Wrong credientials");
}
rdp.main_loop().await
});
Ok(())
@ -51,5 +51,10 @@ fn start_websocket() -> Result<(), JsValue> {
#[wasm_bindgen(start)]
pub fn run_app() -> Result<(), JsValue> {
utils::set_panic_hook();
tracing_wasm::set_as_global_default_with_config(
WASMLayerConfigBuilder::new()
.set_max_level(tracing::Level::INFO)
.build(),
);
start_websocket()
}

View File

@ -84,7 +84,6 @@ impl CsspClient {
fn handle_server_challenge(&mut self, rdp: &mut RdpInner) {
let server_challenge = rdp.reader.read_to_end();
let ans1_tree = BerObj::from_der(&server_challenge);
// console_log!("ans1_tree {:#?}", ans1_tree);
if let ASN1Type::SequenceOwned(ref seq) = ans1_tree.get_value() {
if let ASN1Type::PrivOwned(nego_tokens) = seq[1].get_value() {
if let ASN1Type::SequenceOwned(ref nego_seq) = nego_tokens.get_value() {

View File

@ -1,5 +1,3 @@
use crate::{console_log, log};
use super::protocol::*;
use super::*;
@ -73,7 +71,7 @@ impl RdpInner {
self.initializer = Some(handler);
}
// console_log!("left {}, require {}", self.reader.remain(), self.require);
// trace!("left {}, require {}", self.reader.remain(), self.require);
if let State::Disconnected = self.state {
break;
}
@ -87,7 +85,7 @@ impl RdpInner {
None
} else {
let mut out = Vec::with_capacity(self.outs.len());
// console_log!("Get {} output", self.outs.len());
// trace!("Get {} output", self.outs.len());
for o in self.outs.drain(..) {
out.push(o);
}
@ -113,7 +111,7 @@ impl RdpInner {
impl RdpInner {
fn move_next(&mut self) {
console_log!("State move from {:?} to the next", self.state);
trace!("State move from {:?} to the next", self.state);
match self.state {
State::Init => {
let mut x224 = x224::X224::new(Self::move_next, Self::disconnect_with_err);
@ -149,7 +147,7 @@ impl RdpInner {
}
fn disconnect_with_err(&mut self, err: &str) {
console_log!("{:#?}", err);
error!("{:#?}", err);
self.state = State::Disconnected;
self.outs.push(RdpOutput::Err(err.to_string()));
}

View File

@ -1,16 +1,16 @@
use super::ws_bio::*;
use crate::canvas;
use rdp::{
core::client::{Connector, RdpClient},
model::{
error::{RdpError, RdpErrorKind, RdpResult},
link::{self, AsyncSecureBio},
core::{
client::{Connector, RdpClient},
event::RdpEvent,
},
model::error::RdpErrorKind,
};
use tokio::sync::mpsc;
use tracing::{info, warn};
use web_sys::Element;
use crate::{console_log, log};
use super::ws_bio::WsSecureBio;
const RDP_HOSTNAME: &str = "webrdp";
pub struct Rdp {
@ -19,6 +19,8 @@ pub struct Rdp {
username: String,
password: String,
domain: String,
screen: (u16, u16),
rdp_client: Option<RdpClient<WsStream>>,
}
impl Rdp {
@ -29,12 +31,23 @@ impl Rdp {
.unwrap()
.get_element_by_id("rdp_status")
.unwrap();
let body = web_sys::window()
.unwrap()
.document()
.unwrap()
.body()
.unwrap();
let height = body.client_height() as u16;
let width = body.client_width() as u16;
Self {
url: url.to_owned(),
status_bar,
username: username.to_owned(),
password: password.to_owned(),
domain: domain.to_owned(),
rdp_client: None,
screen: (width, height),
}
}
@ -53,15 +66,8 @@ impl Rdp {
pub async fn start(&mut self) -> bool {
let ws_stream = WsSecureBio::new(&self.url).await;
let body = web_sys::window()
.unwrap()
.document()
.unwrap()
.body()
.unwrap();
let mut rdp_connector = Connector::new()
.screen(body.client_width() as u16, body.client_height() as u16)
.screen(self.screen.0, self.screen.1)
.credentials(
self.domain.clone(),
self.username.clone(),
@ -74,24 +80,50 @@ impl Rdp {
.name(RDP_HOSTNAME.to_string())
.use_nla(true);
let mut rdp_client = rdp_connector.connect(Box::new(ws_stream)).await.unwrap();
console_log!("Rdp Started");
loop {
if let Err(rdp::model::error::Error::RdpError(e)) = rdp_client
match rdp_connector.connect(Box::new(ws_stream)).await {
Ok(rdp_client) => {
info!("Rdp Started");
self.rdp_client = Some(rdp_client);
true
}
Err(_) => false,
}
}
pub async fn main_loop(mut self) {
let mut rdp_client = self.rdp_client.take().unwrap();
let (canvas_sender, mut rdp_reciver) = mpsc::channel(100);
let canvas = canvas::CanvasUtils::new(canvas_sender);
canvas.init(self.screen.0 as u32, self.screen.1 as u32);
'main: loop {
tokio::select! {
engine_recv = rdp_client
.read(|event| match event {
_ => console_log!("ignore event"),
})
.await
{
RdpEvent::Bitmap(bitmap) => {
canvas.draw(bitmap);
}
_ => unreachable!()
}) => {
if let Err(rdp::model::error::Error::RdpError(e)) = engine_recv {
match e.kind() {
RdpErrorKind::Disconnect => {
console_log!("Server ask for disconnect");
info!("Server ask for disconnect");
canvas.close();
self.disconnect_with_msg("Disconnected");
break 'main;
}
_ => warn!("{:?}", e),
}
}
},
canvas_recv = rdp_reciver.recv() => {
if let Some(rdp_event) = canvas_recv {
let _ = rdp_client.try_write(rdp_event.into()).await;
}
_ => console_log!("{:?}", e),
}
}
}
true
}
fn disconnect_with_msg(&self, msg: &str) {

View File

@ -2,24 +2,26 @@ use async_io_stream::IoStream;
use async_trait::async_trait;
use rdp::model::{error::RdpResult, link::AsyncSecureBio};
use tokio::io::AsyncReadExt;
use tracing::{info, trace};
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use ws_stream_wasm::*;
use crate::{console_log, log};
use {futures::stream::StreamExt, pharos::*, wasm_bindgen::UnwrapThrowExt, ws_stream_wasm::*};
pub type WsStream = IoStream<WsStreamIo, Vec<u8>>;
pub struct WsSecureBio {
peer_cert: Vec<u8>,
ws_stream: IoStream<WsStreamIo, Vec<u8>>,
ws_stream: WsStream,
ws_meta: WsMeta,
}
#[async_trait]
impl AsyncSecureBio<IoStream<WsStreamIo, Vec<u8>>> for WsSecureBio {
impl AsyncSecureBio<WsStream> for WsSecureBio {
async fn start_ssl(&mut self, _check_certificate: bool) -> RdpResult<()> {
let _ = self.ws_meta.wrapped().send_with_str("SSL");
let mut ber_cert = [0; 1500];
let size = self.ws_stream.read(&mut ber_cert).await.unwrap();
console_log!("Read {} byte public cert", size);
trace!("Read {} byte public cert", size);
self.peer_cert = ber_cert.to_vec();
Ok(())
}
@ -27,10 +29,11 @@ impl AsyncSecureBio<IoStream<WsStreamIo, Vec<u8>>> for WsSecureBio {
Ok(Some(self.peer_cert.clone()))
}
async fn shutdown(&mut self) -> std::io::Result<()> {
unimplemented!()
let _ = self.ws_meta.close().await;
Ok(())
}
fn get_io(&mut self) -> &mut IoStream<WsStreamIo, Vec<u8>> {
fn get_io(&mut self) -> &mut WsStream {
&mut self.ws_stream
}
}
@ -38,6 +41,22 @@ impl AsyncSecureBio<IoStream<WsStreamIo, Vec<u8>>> for WsSecureBio {
impl WsSecureBio {
pub async fn new(url: &str) -> Self {
let (ws, wsio) = WsMeta::connect(url, vec!["binary"]).await.unwrap();
let onclose_callback = Closure::<dyn FnMut()>::new(move || {
info!("socket close");
let status_bar = web_sys::window()
.unwrap()
.document()
.unwrap()
.get_element_by_id("rdp_status")
.unwrap();
status_bar.set_text_content(Some("Server Disconnected"));
panic!("Closed");
});
ws.wrapped()
.set_onclose(Some(onclose_callback.as_ref().unchecked_ref()));
onclose_callback.forget();
Self {
peer_cert: vec![],
ws_stream: wsio.into_io(),