A worked simple webrdp
This commit is contained in:
parent
a031a9d047
commit
10e5ab5311
@ -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
|
@ -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
206
webrdp/src/input.rs
Normal 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),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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()));
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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(),
|
||||
|
Loading…
Reference in New Issue
Block a user