front-end: fix repeated disconnects on close
When the front-end connects to the back-end, it creates a callback that sends a disconnect message with the received ID on "pagehide" and "beforeunload" events. The previous implementation did not "undo" these callbacks when the game was reset and a new ID was received. This fix prevents the front-end from resending disconnect messages with previously received IDs on browser window/tab close.
This commit is contained in:
parent
e0ed5fc5d8
commit
e77d25996d
2 changed files with 42 additions and 6 deletions
|
@ -9,7 +9,7 @@ edition = "2021"
|
||||||
yew = "0.19"
|
yew = "0.19"
|
||||||
log = "0.4.6"
|
log = "0.4.6"
|
||||||
wasm-logger = "0.2.0"
|
wasm-logger = "0.2.0"
|
||||||
web-sys = { version = "0.3.56", features = ["Window", "Document", "Element", "Request", "RequestInit", "Headers", "RequestMode", "Response", "ReadableStream", "AddEventListenerOptions", "EventTarget"] }
|
web-sys = { version = "0.3.56", features = ["Window", "Document", "Element", "Request", "RequestInit", "Headers", "RequestMode", "Response", "ReadableStream", "AddEventListenerOptions", "EventListenerOptions", "EventTarget"] }
|
||||||
js-sys = "0.3.56"
|
js-sys = "0.3.56"
|
||||||
oorandom = "11.1.3"
|
oorandom = "11.1.3"
|
||||||
wasm-bindgen = { version = "0.2.79", features = ["serde-serialize"] }
|
wasm-bindgen = { version = "0.2.79", features = ["serde-serialize"] }
|
||||||
|
|
|
@ -23,12 +23,12 @@ use crate::state::{
|
||||||
PlacedEnum, SharedState, Turn,
|
PlacedEnum, SharedState, Turn,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::{Cell, RefCell};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use js_sys::{Function, Promise};
|
use js_sys::{Function, Promise};
|
||||||
use web_sys::{AddEventListenerOptions, Document, HtmlInputElement};
|
use web_sys::{AddEventListenerOptions, Document, EventListenerOptions, HtmlInputElement};
|
||||||
|
|
||||||
use wasm_bindgen_futures::JsFuture;
|
use wasm_bindgen_futures::JsFuture;
|
||||||
|
|
||||||
|
@ -321,6 +321,7 @@ pub struct Wrapper {
|
||||||
player_id: Option<u32>,
|
player_id: Option<u32>,
|
||||||
place_request: Option<u8>,
|
place_request: Option<u8>,
|
||||||
do_backend_tick: bool,
|
do_backend_tick: bool,
|
||||||
|
cleanup_id_callback: Rc<RefCell<Option<Function>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Wrapper {
|
impl Wrapper {
|
||||||
|
@ -602,6 +603,33 @@ impl Wrapper {
|
||||||
shared.board[idx].set(slot.get());
|
shared.board[idx].set(slot.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cleanup_disconnect_callbacks(&mut self) {
|
||||||
|
let window = web_sys::window().expect("Should be able to get window");
|
||||||
|
// if previously set disconnect callback is set, unset it
|
||||||
|
if let Some(callback) = self.cleanup_id_callback.borrow_mut().take() {
|
||||||
|
let mut options = EventListenerOptions::new();
|
||||||
|
options.capture(true);
|
||||||
|
if window
|
||||||
|
.remove_event_listener_with_callback_and_event_listener_options(
|
||||||
|
"pagehide", &callback, &options,
|
||||||
|
)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
log::warn!("Failed to remove event listener for disconnect ID on pagehide");
|
||||||
|
}
|
||||||
|
if window
|
||||||
|
.remove_event_listener_with_callback_and_event_listener_options(
|
||||||
|
"beforeunload",
|
||||||
|
&callback,
|
||||||
|
&options,
|
||||||
|
)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
log::warn!("Failed to remove event listener for disconnect ID on beforeunload");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
@ -642,6 +670,7 @@ impl Component for Wrapper {
|
||||||
player_id: None,
|
player_id: None,
|
||||||
place_request: None,
|
place_request: None,
|
||||||
do_backend_tick: true,
|
do_backend_tick: true,
|
||||||
|
cleanup_id_callback: Rc::new(RefCell::new(None)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1307,11 +1336,16 @@ impl Component for Wrapper {
|
||||||
log::warn!("{}", string);
|
log::warn!("{}", string);
|
||||||
}
|
}
|
||||||
BREnum::GotID(id, turn_opt) => {
|
BREnum::GotID(id, turn_opt) => {
|
||||||
|
self.cleanup_disconnect_callbacks();
|
||||||
|
|
||||||
// set reset and disconnect on page "unload"
|
// set reset and disconnect on page "unload"
|
||||||
let player_id = id;
|
let player_id = id;
|
||||||
|
let listener_function: Rc<RefCell<Option<Function>>> =
|
||||||
|
self.cleanup_id_callback.clone();
|
||||||
ctx.link().send_future(async move {
|
ctx.link().send_future(async move {
|
||||||
|
let listener_function = listener_function;
|
||||||
let promise =
|
let promise =
|
||||||
Promise::new(&mut |resolve: js_sys::Function, _reject| {
|
Promise::new(&mut move |resolve: js_sys::Function, _reject| {
|
||||||
let window =
|
let window =
|
||||||
web_sys::window().expect("Should be able to get window");
|
web_sys::window().expect("Should be able to get window");
|
||||||
let outer_function = Function::new_with_args(
|
let outer_function = Function::new_with_args(
|
||||||
|
@ -1328,17 +1362,18 @@ impl Component for Wrapper {
|
||||||
);
|
);
|
||||||
let binded_func =
|
let binded_func =
|
||||||
outer_function.bind1(&outer_function, &resolve);
|
outer_function.bind1(&outer_function, &resolve);
|
||||||
|
listener_function.replace(Some(binded_func));
|
||||||
window
|
window
|
||||||
.add_event_listener_with_callback_and_add_event_listener_options(
|
.add_event_listener_with_callback_and_add_event_listener_options(
|
||||||
"pagehide",
|
"pagehide",
|
||||||
&binded_func,
|
listener_function.borrow().as_ref().unwrap(),
|
||||||
AddEventListenerOptions::new().capture(true).once(true)
|
AddEventListenerOptions::new().capture(true).once(true)
|
||||||
)
|
)
|
||||||
.expect("Should be able to set \"pagehide\" callback");
|
.expect("Should be able to set \"pagehide\" callback");
|
||||||
window
|
window
|
||||||
.add_event_listener_with_callback_and_add_event_listener_options(
|
.add_event_listener_with_callback_and_add_event_listener_options(
|
||||||
"beforeunload",
|
"beforeunload",
|
||||||
&binded_func,
|
listener_function.borrow().as_ref().unwrap(),
|
||||||
AddEventListenerOptions::new().capture(true).once(true)
|
AddEventListenerOptions::new().capture(true).once(true)
|
||||||
)
|
)
|
||||||
.expect("Should be able to set \"beforeunload\" callback");
|
.expect("Should be able to set \"beforeunload\" callback");
|
||||||
|
@ -1708,6 +1743,7 @@ impl Component for Wrapper {
|
||||||
)
|
)
|
||||||
.ok();
|
.ok();
|
||||||
self.do_backend_tick = false;
|
self.do_backend_tick = false;
|
||||||
|
self.cleanup_disconnect_callbacks();
|
||||||
}
|
}
|
||||||
} // match (msg)
|
} // match (msg)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue