From 6d2d71c09a8b790c92dad71fdedf9dbc93fce0b6 Mon Sep 17 00:00:00 2001 From: lovetox <philipp@hoerist.com> Date: Mon, 19 Apr 2021 21:47:37 +0200 Subject: [PATCH] Handle disconnect and resume-failed inside modules --- gajim/common/client.py | 7 +--- gajim/common/helpers.py | 5 ++- gajim/common/modules/chatstates.py | 53 ++++++++++++++---------------- gajim/common/modules/contacts.py | 24 +++++++++++--- gajim/common/modules/mam.py | 12 ++++++- gajim/common/modules/muc.py | 29 +++++++++++----- 6 files changed, 80 insertions(+), 50 deletions(-) diff --git a/gajim/common/client.py b/gajim/common/client.py index 18e94c8a8b..4f1177c31e 100644 --- a/gajim/common/client.py +++ b/gajim/common/client.py @@ -182,9 +182,9 @@ def _create_client(self): def _on_resume_failed(self, _client, _signal_name): log.info('Resume failed') + self.notify('resume-failed') app.nec.push_incoming_event(NetworkEvent( 'our-show', account=self._account, show='offline')) - self.get_module('Chatstate').enabled = False def _on_resume_successful(self, _client, _signal_name): self._set_state(ClientState.CONNECTED) @@ -278,11 +278,9 @@ def _on_password(password): self.notify('state-changed', SimpleClientState.RESUME_IN_PREGRESS) else: - self.get_module('Chatstate').enabled = False app.nec.push_incoming_event(NetworkEvent( 'our-show', account=self._account, show='offline')) self._after_disconnect() - self.get_module('Contacts').reset_presence() self.notify('state-changed', SimpleClientState.DISCONNECTED) def _after_disconnect(self): @@ -305,12 +303,9 @@ def _on_connection_failed(self, _client, _signal_name): def _on_connected(self, _client, _signal_name): self._set_state(ClientState.CONNECTED) - self.get_module('MUC').reset_state() self.get_module('Discovery').discover_server_info() self.get_module('Discovery').discover_account_info() self.get_module('Discovery').discover_server_items() - self.get_module('Chatstate').enabled = True - self.get_module('MAM').reset_state() def _on_stanza_sent(self, _client, _signal_name, stanza): app.nec.push_incoming_event(NetworkEvent('stanza-sent', diff --git a/gajim/common/helpers.py b/gajim/common/helpers.py index 13ddcf3c94..d851fe42d9 100644 --- a/gajim/common/helpers.py +++ b/gajim/common/helpers.py @@ -1209,10 +1209,13 @@ def multi_connect(self, signal_dict): self.connect_signal(signal_name, func) def notify(self, signal_name, *args, qualifiers=None, **kwargs): + signal_callbacks = self._callbacks.get(signal_name) + if signal_callbacks is None: + return + if self._log is not None: self._log.info('Signal: %s', signal_name) - signal_callbacks = self._callbacks.get(signal_name, {}) callbacks = signal_callbacks.get(qualifiers, []) for func in list(callbacks): if func() is None: diff --git a/gajim/common/modules/chatstates.py b/gajim/common/modules/chatstates.py index b14678e748..1059a7216d 100644 --- a/gajim/common/modules/chatstates.py +++ b/gajim/common/modules/chatstates.py @@ -29,7 +29,6 @@ from nbxmpp.const import Chatstate as State from gi.repository import GLib -from gajim.common import app from gajim.common.structs import OutgoingMessage from gajim.common.modules.base import BaseModule @@ -44,7 +43,7 @@ def ensure_enabled(func): @wraps(func) def func_wrapper(self, *args, **kwargs): - if not self.enabled: + if not self._enabled: return None return func(self, *args, **kwargs) return func_wrapper @@ -76,14 +75,22 @@ def __init__(self, con: ConnectionT) -> None: self._blocked = [] # type: List[str] self._enabled = False - @property - def enabled(self): - return self._enabled + self._con.connect_signal('state-changed', self._on_client_state_changed) + self._con.connect_signal('resume-failed', self._on_client_resume_failed) - @enabled.setter - def enabled(self, value): + def _on_client_resume_failed(self, _client, _signal_name): + self._set_enabled(False) + + def _on_client_state_changed(self, _client, _signal_name, state): + if state.is_disconnected: + self._set_enabled(False) + elif state.is_connected: + self._set_enabled(True) + + def _set_enabled(self, value): if self._enabled == value: return + self._log.info('Chatstate module %s', 'enabled' if value else 'disabled') self._enabled = value @@ -93,10 +100,7 @@ def enabled(self, value): 2, self._check_last_interaction) else: self.cleanup() - self._chatstates = {} - self._last_keyboard_activity = {} - self._last_mouse_activity = {} - self._blocked = [] + self._con.get_module('Contacts').force_chatstate_update() @ensure_enabled def _presence_received(self, @@ -171,23 +175,7 @@ def _check_last_interaction(self) -> GLib.SOURCE_CONTINUE: if new_chatstate is not None: if self._chatstates.get(jid) != new_chatstate: contact = self._get_contact(jid) - - # if contact is None: - # room, nick = app.get_room_and_nick_from_fjid(jid) - # contact = app.contacts.get_gc_contact( - # self._account, room, nick) - # if contact is not None: - # contact = contact.as_contact() - # else: - # # Contact not found, maybe we left the group chat - # # or the contact was removed from the roster - # self._log.info( - # 'Contact %s not found, reset chatstate', jid) - # self._chatstates.pop(jid, None) - # self._last_mouse_activity.pop(jid, None) - # self._last_keyboard_activity.pop(jid, None) - # continue - self.set_chatstate(contact, new_chatstate) + self.set_chatstate(contact, new_chatstate) return GLib.SOURCE_CONTINUE @@ -332,12 +320,19 @@ def remove_delay_timeout(self, contact): def remove_all_delay_timeouts(self): for timeout in self._delay_timeout_ids.values(): GLib.source_remove(timeout) - self._delay_timeout_ids = {} + self._delay_timeout_ids.clear() def cleanup(self): self.remove_all_delay_timeouts() if self._timeout_id is not None: GLib.source_remove(self._timeout_id) + self._timeout_id = None + + self._chatstates.clear() + self._remote_chatstate.clear() + self._last_keyboard_activity.clear() + self._last_mouse_activity.clear() + self._blocked = [] def get_instance(*args: Any, **kwargs: Any) -> Tuple[Chatstate, str]: diff --git a/gajim/common/modules/contacts.py b/gajim/common/modules/contacts.py index 8349d45354..334dd6f4e0 100644 --- a/gajim/common/modules/contacts.py +++ b/gajim/common/modules/contacts.py @@ -47,6 +47,15 @@ def __init__(self, con: ConnectionT) -> None: BaseModule.__init__(self, con) self._contacts = {} + self._con.connect_signal('state-changed', self._on_client_state_changed) + self._con.connect_signal('resume-failed', self._on_client_resume_failed) + + def _on_client_resume_failed(self, _client, _signal_name): + self._reset_presence() + + def _on_client_state_changed(self, _client, _signal_name, state): + if state.is_disconnected: + self._reset_presence() def add_contact(self, jid, groupchat=False): if isinstance(jid, str): @@ -90,12 +99,16 @@ def get_contacts_with_domain(self, domain): contacts.append(contact) return contacts - def reset_presence(self): + def _reset_presence(self): for contact in self._contacts.values(): if contact.is_groupchat or contact.is_pm_contact: continue contact.update_presence(UNKNOWN_PRESENCE) + def force_chatstate_update(self): + for contact in self._contacts.values(): + contact.force_chatstate_update() + class CommonContact(Observable): def __init__(self, logger, jid, account): @@ -103,6 +116,8 @@ def __init__(self, logger, jid, account): self._jid = jid self._account = account + self._resources = {} + def _module(self, name): return app.get_client(self._account).get_module(name) @@ -135,6 +150,10 @@ def is_groupchat(self): def is_pm_contact(self): return False + def force_chatstate_update(self): + for contact in self._resources.values(): + contact.notify('chatstate-update') + class BareContact(CommonContact): def __init__(self, logger, jid, account): @@ -142,7 +161,6 @@ def __init__(self, logger, jid, account): self.settings = ContactSettings(account, str(jid)) - self._resources = {} self._avatar_sha = app.storage.cache.get_contact(jid, 'avatar') def add_resource(self, resource): @@ -320,8 +338,6 @@ def __init__(self, logger, jid, account): self.settings = GroupChatSettings(account, str(jid)) - self._resources = {} - @property def is_groupchat(self): return True diff --git a/gajim/common/modules/mam.py b/gajim/common/modules/mam.py index 67b9828f24..aed6620feb 100644 --- a/gajim/common/modules/mam.py +++ b/gajim/common/modules/mam.py @@ -68,6 +68,9 @@ def __init__(self, con): # Holds archive jids where catch up was successful self._catch_up_finished = [] + self._con.connect_signal('state-changed', self._on_client_state_changed) + self._con.connect_signal('resume-failed', self._on_client_resume_failed) + def pass_disco(self, info): if Namespace.MAM_2 not in info.features: return @@ -80,7 +83,14 @@ def pass_disco(self, info): account=self._account, feature=Namespace.MAM_2)) - def reset_state(self): + def _on_client_resume_failed(self, _client, _signal_name): + self._reset_state() + + def _on_client_state_changed(self, _client, _signal_name, state): + if state.is_disconnected: + self._reset_state() + + def _reset_state(self): self._mam_query_ids.clear() self._catch_up_finished.clear() diff --git a/gajim/common/modules/muc.py b/gajim/common/modules/muc.py index 2b427a6f0e..b1e05571b8 100644 --- a/gajim/common/modules/muc.py +++ b/gajim/common/modules/muc.py @@ -30,12 +30,10 @@ from gajim.common import app from gajim.common import helpers -from gajim.common import ged from gajim.common.const import KindConstant from gajim.common.const import MUCJoinedState from gajim.common.helpers import AdditionalDataDict from gajim.common.helpers import get_default_muc_config -from gajim.common.helpers import event_filter from gajim.common.helpers import get_group_chat_nick from gajim.common.structs import MUCData from gajim.common.structs import MUCPresenceData @@ -109,6 +107,8 @@ def __init__(self, con): self._con.connect_signal('state-changed', self._on_client_state_changed) + self._con.connect_signal('resume-failed', + self._on_client_resume_failed) self._rejoin_muc = set() self._join_timeouts = {} @@ -117,6 +117,14 @@ def __init__(self, con): self._joined_users = defaultdict(dict) self._mucs = {} + + def _on_resume_failed(self, _client, _signal_name): + self._reset_presence() + + def _on_state_changed(self, _client, _signal_name, state): + if state.is_disconnected: + self._reset_presence() + @property def supported(self): return self._muc_service_jid is not None @@ -158,7 +166,13 @@ def _set_muc_state(self, room_jid, state): contact = self._get_contact(room_jid, groupchat=True) contact.notify('state-changed') - def reset_state(self): + def _reset_state(self): + for room_jid in list(self._rejoin_timeouts.keys()): + self._remove_rejoin_timeout(room_jid) + + for room_jid in list(self._join_timeouts.keys()): + self._remove_join_timeout(room_jid) + for muc in self._mucs.values(): self._joined_users.pop(muc.jid, None) self._set_muc_state(muc.jid, MUCJoinedState.NOT_JOINED) @@ -808,13 +822,10 @@ def invite(self, room, jid, reason=None, continue_=False): def _on_client_state_changed(self, _client, _signal_name, state): if state.is_disconnected: - for room_jid in list(self._rejoin_timeouts.keys()): - self._remove_rejoin_timeout(room_jid) - - for room_jid in list(self._join_timeouts.keys()): - self._remove_join_timeout(room_jid) + self._reset_state() - self.reset_state() + def _on_client_resume_failed(self, _client, _signal_name): + self._reset_state() def get_instance(*args, **kwargs): -- GitLab