Graceful close
This commit is contained in:
parent
e0aa8abd78
commit
67275f6be8
@ -32,6 +32,7 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<div id="vnc_status" style="position: relative; height: auto;" class="horizontal-centre vertical-centre"></div>
|
||||||
<div id="canvas" class="horizontal-centre vertical-centre"><canvas id="vnc-canvas" tabIndex=1></canvas></div>
|
<div id="canvas" class="horizontal-centre vertical-centre"><canvas id="vnc-canvas" tabIndex=1></canvas></div>
|
||||||
<div class="clipboardback">
|
<div class="clipboardback">
|
||||||
<div class="clipboard">
|
<div class="clipboard">
|
||||||
|
@ -171,6 +171,10 @@ impl Canvas {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn close(&self) {
|
||||||
|
self.ctx.fill();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CanvasUtils {
|
pub struct CanvasUtils {
|
||||||
@ -203,4 +207,8 @@ impl CanvasUtils {
|
|||||||
pub fn draw(&self, ri: &ImageData) {
|
pub fn draw(&self, ri: &ImageData) {
|
||||||
self.inner.as_ref().draw(ri);
|
self.inner.as_ref().draw(ri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn close(&self) {
|
||||||
|
self.inner.as_ref().close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ macro_rules! console_log {
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
fn setInterval(closure: &Closure<dyn FnMut()>, millis: u32) -> f64;
|
fn setInterval(closure: &Closure<dyn FnMut()>, millis: u32) -> f64;
|
||||||
// fn setTimeout(closure: &Closure<dyn FnMut()>, millis: u32) -> f64;
|
// fn setTimeout(closure: &Closure<dyn FnMut()>, millis: u32) -> f64;
|
||||||
fn cancelInterval(token: f64);
|
fn clearInterval(token: f64);
|
||||||
#[wasm_bindgen(js_namespace = console)]
|
#[wasm_bindgen(js_namespace = console)]
|
||||||
pub fn log(s: &str);
|
pub fn log(s: &str);
|
||||||
pub fn prompt(s: &str) -> String;
|
pub fn prompt(s: &str) -> String;
|
||||||
@ -25,6 +25,39 @@ extern "C" {
|
|||||||
pub fn getClipBoard() -> String;
|
pub fn getClipBoard() -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static mut REFRESHER: Option<Interval> = None;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct Interval {
|
||||||
|
_closure: Closure<dyn FnMut()>,
|
||||||
|
token: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Interval {
|
||||||
|
pub fn new<F: 'static>(millis: u32, f: F) -> Interval
|
||||||
|
where
|
||||||
|
F: FnMut(),
|
||||||
|
{
|
||||||
|
// Construct a new closure.
|
||||||
|
let closure = Closure::new(f);
|
||||||
|
// Pass the closure to JS, to run every n milliseconds.
|
||||||
|
let token = setInterval(&closure, millis);
|
||||||
|
|
||||||
|
Interval {
|
||||||
|
_closure: closure,
|
||||||
|
token,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the Interval is destroyed, cancel its `setInterval` timer.
|
||||||
|
impl Drop for Interval {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
console_log!("interval dropped");
|
||||||
|
clearInterval(self.token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn vnc_out_handler(ws: &WebSocket, vnc: &Vnc, canvas: &CanvasUtils) {
|
fn vnc_out_handler(ws: &WebSocket, vnc: &Vnc, canvas: &CanvasUtils) {
|
||||||
let out = vnc.get_output();
|
let out = vnc.get_output();
|
||||||
if !out.is_empty() {
|
if !out.is_empty() {
|
||||||
@ -35,7 +68,10 @@ fn vnc_out_handler(ws: &WebSocket, vnc: &Vnc, canvas: &CanvasUtils) {
|
|||||||
}
|
}
|
||||||
vnc::VncOutput::WsBuf(buf) => match ws.send_with_u8_array(buf) {
|
vnc::VncOutput::WsBuf(buf) => match ws.send_with_u8_array(buf) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(err) => console_log!("error sending message: {:?}", err),
|
Err(err) => {
|
||||||
|
console_log!("error sending message: {:?}", err);
|
||||||
|
vnc_close_handle(vnc, canvas);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
vnc::VncOutput::RequirePassword => {
|
vnc::VncOutput::RequirePassword => {
|
||||||
let pwd = prompt("Please input the password");
|
let pwd = prompt("Please input the password");
|
||||||
@ -61,12 +97,11 @@ fn vnc_out_handler(ws: &WebSocket, vnc: &Vnc, canvas: &CanvasUtils) {
|
|||||||
vnc_out_handler(&ws_cloned, &vnc_cloned, &canvas_cloned);
|
vnc_out_handler(&ws_cloned, &vnc_cloned, &canvas_cloned);
|
||||||
};
|
};
|
||||||
|
|
||||||
let handler = Box::new(refresh) as Box<dyn FnMut()>;
|
let refersher = Interval::new(20, refresh);
|
||||||
|
|
||||||
let cb = Closure::wrap(handler);
|
unsafe {
|
||||||
|
REFRESHER = Some(refersher);
|
||||||
setInterval(&cb, 20);
|
}
|
||||||
cb.forget();
|
|
||||||
}
|
}
|
||||||
vnc::VncOutput::SetClipboard(text) => {
|
vnc::VncOutput::SetClipboard(text) => {
|
||||||
setClipBoard(text.to_owned());
|
setClipBoard(text.to_owned());
|
||||||
@ -77,6 +112,21 @@ fn vnc_out_handler(ws: &WebSocket, vnc: &Vnc, canvas: &CanvasUtils) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn vnc_close_handle(vnc: &Vnc, canvas: &CanvasUtils) {
|
||||||
|
vnc.close();
|
||||||
|
unsafe {
|
||||||
|
REFRESHER.take();
|
||||||
|
}
|
||||||
|
canvas.close();
|
||||||
|
let status = web_sys::window()
|
||||||
|
.unwrap()
|
||||||
|
.document()
|
||||||
|
.unwrap()
|
||||||
|
.get_element_by_id("vnc_status")
|
||||||
|
.unwrap();
|
||||||
|
status.set_text_content(Some("Disconnected"));
|
||||||
|
}
|
||||||
|
|
||||||
fn start_websocket() -> Result<(), JsValue> {
|
fn start_websocket() -> Result<(), JsValue> {
|
||||||
// connect
|
// connect
|
||||||
let url = format!(
|
let url = format!(
|
||||||
@ -117,13 +167,15 @@ fn start_websocket() -> Result<(), JsValue> {
|
|||||||
ws.set_binary_type(web_sys::BinaryType::Arraybuffer);
|
ws.set_binary_type(web_sys::BinaryType::Arraybuffer);
|
||||||
// on message
|
// on message
|
||||||
let cloned_ws = ws.clone();
|
let cloned_ws = ws.clone();
|
||||||
|
let vnc_cloned = vnc.clone();
|
||||||
|
let canvas_cloned = canvas.clone();
|
||||||
|
|
||||||
let onmessage_callback = Closure::<dyn FnMut(_)>::new(move |e: MessageEvent| {
|
let onmessage_callback = Closure::<dyn FnMut(_)>::new(move |e: MessageEvent| {
|
||||||
if let Ok(abuf) = e.data().dyn_into::<js_sys::ArrayBuffer>() {
|
if let Ok(abuf) = e.data().dyn_into::<js_sys::ArrayBuffer>() {
|
||||||
let array = js_sys::Uint8Array::new(&abuf);
|
let array = js_sys::Uint8Array::new(&abuf);
|
||||||
// let mut canvas_ctx = None;
|
// let mut canvas_ctx = None;
|
||||||
vnc.do_input(array.to_vec());
|
vnc_cloned.do_input(array.to_vec());
|
||||||
vnc_out_handler(&cloned_ws, &vnc, &canvas);
|
vnc_out_handler(&cloned_ws, &vnc_cloned, &canvas_cloned);
|
||||||
} else {
|
} else {
|
||||||
console_log!("message event, received Unknown: {:?}", e.data());
|
console_log!("message event, received Unknown: {:?}", e.data());
|
||||||
}
|
}
|
||||||
@ -148,6 +200,7 @@ fn start_websocket() -> Result<(), JsValue> {
|
|||||||
|
|
||||||
let onclose_callback = Closure::<dyn FnMut()>::new(move || {
|
let onclose_callback = Closure::<dyn FnMut()>::new(move || {
|
||||||
console_log!("socket close");
|
console_log!("socket close");
|
||||||
|
vnc_close_handle(&vnc, &canvas);
|
||||||
});
|
});
|
||||||
ws.set_onclose(Some(onclose_callback.as_ref().unchecked_ref()));
|
ws.set_onclose(Some(onclose_callback.as_ref().unchecked_ref()));
|
||||||
onclose_callback.forget();
|
onclose_callback.forget();
|
||||||
|
@ -67,6 +67,10 @@ impl Vnc {
|
|||||||
pub fn mouse_event(&self, mouse: web_sys::MouseEvent, et: MouseEventType) {
|
pub fn mouse_event(&self, mouse: web_sys::MouseEvent, et: MouseEventType) {
|
||||||
self.inner.lock().unwrap().mouse_event(mouse, et);
|
self.inner.lock().unwrap().mouse_event(mouse, et);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn close(&self) {
|
||||||
|
self.inner.lock().unwrap().close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for Vnc {
|
impl Clone for Vnc {
|
||||||
|
@ -166,6 +166,10 @@ impl Vnc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_clipboard(&mut self, text: &str) {
|
pub fn set_clipboard(&mut self, text: &str) {
|
||||||
|
if self.state != VncState::Connected {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self.send_client_cut_text(text);
|
self.send_client_cut_text(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,6 +190,10 @@ impl Vnc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn require_frame(&mut self, incremental: u8) {
|
pub fn require_frame(&mut self, incremental: u8) {
|
||||||
|
if self.state != VncState::Connected {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if 0 == incremental {
|
if 0 == incremental {
|
||||||
// first frame
|
// first frame
|
||||||
// set the client encoding
|
// set the client encoding
|
||||||
@ -195,6 +203,10 @@ impl Vnc {
|
|||||||
self.framebuffer_update_request(incremental)
|
self.framebuffer_update_request(incremental)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn close(&mut self) {
|
||||||
|
self.state = VncState::Disconnected;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
Loading…
Reference in New Issue
Block a user