Graceful close

This commit is contained in:
Jovi Hsu 2022-10-08 06:42:49 +00:00
parent e0aa8abd78
commit 67275f6be8
5 changed files with 87 additions and 9 deletions

View File

@ -32,6 +32,7 @@
</head>
<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 class="clipboardback">
<div class="clipboard">

View File

@ -171,6 +171,10 @@ impl Canvas {
}
}
}
fn close(&self) {
self.ctx.fill();
}
}
pub struct CanvasUtils {
@ -203,4 +207,8 @@ impl CanvasUtils {
pub fn draw(&self, ri: &ImageData) {
self.inner.as_ref().draw(ri);
}
pub fn close(&self) {
self.inner.as_ref().close()
}
}

View File

@ -17,7 +17,7 @@ macro_rules! console_log {
extern "C" {
fn setInterval(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)]
pub fn log(s: &str);
pub fn prompt(s: &str) -> String;
@ -25,6 +25,39 @@ extern "C" {
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) {
let out = vnc.get_output();
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) {
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 => {
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);
};
let handler = Box::new(refresh) as Box<dyn FnMut()>;
let refersher = Interval::new(20, refresh);
let cb = Closure::wrap(handler);
setInterval(&cb, 20);
cb.forget();
unsafe {
REFRESHER = Some(refersher);
}
}
vnc::VncOutput::SetClipboard(text) => {
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> {
// connect
let url = format!(
@ -117,13 +167,15 @@ fn start_websocket() -> Result<(), JsValue> {
ws.set_binary_type(web_sys::BinaryType::Arraybuffer);
// on message
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| {
if let Ok(abuf) = e.data().dyn_into::<js_sys::ArrayBuffer>() {
let array = js_sys::Uint8Array::new(&abuf);
// let mut canvas_ctx = None;
vnc.do_input(array.to_vec());
vnc_out_handler(&cloned_ws, &vnc, &canvas);
vnc_cloned.do_input(array.to_vec());
vnc_out_handler(&cloned_ws, &vnc_cloned, &canvas_cloned);
} else {
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 || {
console_log!("socket close");
vnc_close_handle(&vnc, &canvas);
});
ws.set_onclose(Some(onclose_callback.as_ref().unchecked_ref()));
onclose_callback.forget();

View File

@ -67,6 +67,10 @@ impl Vnc {
pub fn mouse_event(&self, mouse: web_sys::MouseEvent, et: MouseEventType) {
self.inner.lock().unwrap().mouse_event(mouse, et);
}
pub fn close(&self) {
self.inner.lock().unwrap().close();
}
}
impl Clone for Vnc {

View File

@ -166,6 +166,10 @@ impl Vnc {
}
pub fn set_clipboard(&mut self, text: &str) {
if self.state != VncState::Connected {
return;
}
self.send_client_cut_text(text);
}
@ -186,6 +190,10 @@ impl Vnc {
}
pub fn require_frame(&mut self, incremental: u8) {
if self.state != VncState::Connected {
return;
}
if 0 == incremental {
// first frame
// set the client encoding
@ -195,6 +203,10 @@ impl Vnc {
self.framebuffer_update_request(incremental)
}
}
pub fn close(&mut self) {
self.state = VncState::Disconnected;
}
}
#[allow(dead_code)]