Fix clients are disconnecting GRACEFULLY by removing the Disconnect Request from a client, a client now sends a TERMINATE message directly

This commit is contained in:
Marcel Märtens 2020-10-23 01:45:19 +02:00
parent 37d08e93ca
commit 6bb74c9c6f
8 changed files with 26 additions and 49 deletions

View File

@ -500,9 +500,9 @@ impl Client {
| ClientGeneral::RefundSkill(_)
| ClientGeneral::UnlockSkillGroup(_) => &mut self.in_game_stream,
//Always possible
ClientGeneral::ChatMsg(_)
| ClientGeneral::Disconnect
| ClientGeneral::Terminate => &mut self.general_stream,
ClientGeneral::ChatMsg(_) | ClientGeneral::Terminate => {
&mut self.general_stream
},
};
stream.send(msg)
},
@ -552,9 +552,11 @@ impl Client {
}
/// Send disconnect message to the server
pub fn request_logout(&mut self) {
debug!("Requesting logout from server");
self.send_msg(ClientGeneral::Disconnect);
pub fn logout(&mut self) {
debug!("Sending logout from server");
self.send_msg(ClientGeneral::Terminate);
self.registered = false;
self.in_game = None;
}
/// Request a state transition to `ClientState::Registered` from an ingame
@ -1133,11 +1135,6 @@ impl Client {
match msg {
ServerGeneral::Disconnect(reason) => match reason {
DisconnectReason::Shutdown => return Err(Error::ServerShutdown),
DisconnectReason::Requested => {
debug!("finally sending ClientMsg::Terminate");
frontend_events.push(Event::Disconnect);
self.send_msg_err(ClientGeneral::Terminate)?;
},
DisconnectReason::Kicked(reason) => {
debug!("sending ClientMsg::Terminate because we got kicked");
frontend_events.push(Event::Kicked(reason));
@ -1840,7 +1837,7 @@ impl Drop for Client {
fn drop(&mut self) {
trace!("Dropping client");
if self.registered {
if let Err(e) = self.send_msg_err(ClientGeneral::Disconnect) {
if let Err(e) = self.send_msg_err(ClientGeneral::Terminate) {
warn!(
?e,
"Error during drop of client, couldn't send disconnect package, is the \

View File

@ -78,7 +78,6 @@ pub enum ClientGeneral {
UnlockSkillGroup(SkillGroupType),
//Always possible
ChatMsg(String),
Disconnect,
Terminate,
}
@ -119,9 +118,7 @@ impl ClientMsg {
c_type == ClientType::Game && in_game.is_some()
},
//Always possible
ClientGeneral::ChatMsg(_)
| ClientGeneral::Disconnect
| ClientGeneral::Terminate => true,
ClientGeneral::ChatMsg(_) | ClientGeneral::Terminate => true,
}
},
ClientMsg::Ping(_) => true,

View File

@ -163,8 +163,6 @@ pub enum Notification {
pub enum DisconnectReason {
/// Server shut down
Shutdown,
/// Client sent disconnect message
Requested,
/// Client was kicked
Kicked(String),
}

View File

@ -12,6 +12,7 @@ pub struct Client {
pub participant: Option<Participant>,
pub last_ping: f64,
pub login_msg_sent: bool,
pub terminate_msg_recv: bool,
}
impl Component for Client {

View File

@ -143,6 +143,7 @@ impl ConnectionHandler {
participant: Some(participant),
last_ping: server_data.time,
login_msg_sent: false,
terminate_msg_recv: false,
};
let package = IncomingClient {

View File

@ -1,16 +1,9 @@
use super::super::SysTimer;
use crate::{
client::Client,
metrics::PlayerMetrics,
streams::{GeneralStream, GetStream},
};
use crate::{client::Client, metrics::PlayerMetrics, streams::GeneralStream};
use common::{
comp::{ChatMode, UnresolvedChatMsg},
event::{EventBus, ServerEvent},
msg::{
validate_chat_msg, ChatMsgValidationError, ClientGeneral, DisconnectReason, ServerGeneral,
MAX_BYTES_CHAT_MSG,
},
msg::{validate_chat_msg, ChatMsgValidationError, ClientGeneral, MAX_BYTES_CHAT_MSG},
span,
state::Time,
sync::Uid,
@ -25,7 +18,6 @@ impl Sys {
new_chat_msgs: &mut Vec<(Option<specs::Entity>, UnresolvedChatMsg)>,
entity: specs::Entity,
client: &mut Client,
general_stream: &mut GeneralStream,
player_metrics: &ReadExpect<'_, PlayerMetrics>,
uids: &ReadStorage<'_, Uid>,
chat_modes: &ReadStorage<'_, ChatMode>,
@ -52,17 +44,13 @@ impl Sys {
}
}
},
ClientGeneral::Disconnect => {
general_stream.send(ServerGeneral::Disconnect(DisconnectReason::Requested))?;
},
ClientGeneral::Terminate => {
debug!(?entity, "Client send message to termitate session");
player_metrics
.clients_disconnected
.with_label_values(&["gracefully"])
.inc();
client.registered = false;
client.in_game = None;
client.terminate_msg_recv = true;
server_emitter.emit(ServerEvent::ClientDisconnect(entity));
},
_ => unreachable!("not a client_general msg"),
@ -110,13 +98,12 @@ impl<'a> System<'a> for Sys {
for (entity, client, general_stream) in
(&entities, &mut clients, &mut general_streams).join()
{
let res = super::try_recv_all(general_stream, |general_stream, msg| {
let res = super::try_recv_all(general_stream, |_, msg| {
Self::handle_general_msg(
&mut server_emitter,
&mut new_chat_msgs,
entity,
client,
general_stream,
&player_metrics,
&uids,
&chat_modes,

View File

@ -67,20 +67,14 @@ impl<'a> System<'a> for Sys {
match res {
Err(e) => {
let reg = client.registered;
debug!(
?entity,
?e,
?reg,
"network error with client, disconnecting"
);
if reg {
if !client.terminate_msg_recv {
debug!(?entity, ?e, "network error with client, disconnecting");
player_metrics
.clients_disconnected
.with_label_values(&["network_error"])
.inc();
server_emitter.emit(ServerEvent::ClientDisconnect(entity));
}
server_emitter.emit(ServerEvent::ClientDisconnect(entity));
},
Ok(1_u64..=u64::MAX) => {
// Update client ping.
@ -90,15 +84,14 @@ impl<'a> System<'a> for Sys {
if time.0 - client.last_ping > settings.client_timeout.as_secs() as f64
// Timeout
{
let reg = client.registered;
info!(?entity, ?reg, "timeout error with client, disconnecting");
if reg {
if !client.terminate_msg_recv {
info!(?entity, "timeout error with client, disconnecting");
player_metrics
.clients_disconnected
.with_label_values(&["timeout"])
.inc();
server_emitter.emit(ServerEvent::ClientDisconnect(entity));
}
server_emitter.emit(ServerEvent::ClientDisconnect(entity));
} else if time.0 - client.last_ping
> settings.client_timeout.as_secs() as f64 * 0.5
{

View File

@ -763,7 +763,10 @@ impl PlayState for SessionState {
HudEvent::CharacterSelection => {
self.client.borrow_mut().request_remove_character()
},
HudEvent::Logout => self.client.borrow_mut().request_logout(),
HudEvent::Logout => {
self.client.borrow_mut().logout();
return PlayStateResult::Pop;
},
HudEvent::Quit => {
return PlayStateResult::Shutdown;
},