Commit 44e6b0f0 authored by Philipp Hörist's avatar Philipp Hörist

MUC: Refactor auto-rejoin

- Rewrite auto-rejoin code and move it into muc module
parent 94b058cd
Pipeline #4275 passed with stages
in 2 minutes and 51 seconds
...@@ -24,6 +24,7 @@ from datetime import timezone ...@@ -24,6 +24,7 @@ from datetime import timezone
import nbxmpp import nbxmpp
from nbxmpp.const import InviteType from nbxmpp.const import InviteType
from nbxmpp.const import PresenceType from nbxmpp.const import PresenceType
from nbxmpp.const import StatusCode
from nbxmpp.structs import StanzaHandler from nbxmpp.structs import StanzaHandler
from nbxmpp.util import is_error_result from nbxmpp.util import is_error_result
...@@ -31,6 +32,7 @@ from gi.repository import GLib ...@@ -31,6 +32,7 @@ from gi.repository import GLib
from gajim.common import app from gajim.common import app
from gajim.common import helpers from gajim.common import helpers
from gajim.common import ged
from gajim.common.const import KindConstant from gajim.common.const import KindConstant
from gajim.common.const import MUCJoinedState from gajim.common.const import MUCJoinedState
from gajim.common.const import SyncThreshold from gajim.common.const import SyncThreshold
...@@ -38,6 +40,7 @@ from gajim.common.helpers import AdditionalDataDict ...@@ -38,6 +40,7 @@ from gajim.common.helpers import AdditionalDataDict
from gajim.common.helpers import get_default_muc_config from gajim.common.helpers import get_default_muc_config
from gajim.common.helpers import get_sync_threshold from gajim.common.helpers import get_sync_threshold
from gajim.common.helpers import to_user_string from gajim.common.helpers import to_user_string
from gajim.common.helpers import event_filter
from gajim.common import idle from gajim.common import idle
from gajim.common.nec import NetworkEvent from gajim.common.nec import NetworkEvent
from gajim.common.modules.bits_of_binary import store_bob_data from gajim.common.modules.bits_of_binary import store_bob_data
...@@ -106,8 +109,17 @@ class MUC(BaseModule): ...@@ -106,8 +109,17 @@ class MUC(BaseModule):
priority=49) priority=49)
] ]
self._event_handlers = [
('account-disconnected', ged.CORE, self._on_account_disconnected),
]
for handler in self._event_handlers:
app.ged.register_event_handler(*handler)
self._muc_data = {} self._muc_data = {}
self._rejoin_muc = set()
self._join_timeouts = {} self._join_timeouts = {}
self._rejoin_timeouts = {}
def pass_disco(self, info): def pass_disco(self, info):
for identity in info.identities: for identity in info.identities:
...@@ -187,6 +199,13 @@ class MUC(BaseModule): ...@@ -187,6 +199,13 @@ class MUC(BaseModule):
self._set_muc_state(muc_data.jid, MUCJoinedState.JOINING) self._set_muc_state(muc_data.jid, MUCJoinedState.JOINING)
self._con.connection.send(presence) self._con.connection.send(presence)
def _rejoin(self, room_jid):
muc_data = self._get_muc_data(room_jid)
if muc_data.state == MUCJoinedState.NOT_JOINED:
self._log.info('Rejoin %s', room_jid)
self._join(muc_data)
return True
def _create(self, muc_data): def _create(self, muc_data):
show = helpers.get_xmpp_show(app.SHOW_LIST[self._con.connected]) show = helpers.get_xmpp_show(app.SHOW_LIST[self._con.connected])
...@@ -204,6 +223,7 @@ class MUC(BaseModule): ...@@ -204,6 +223,7 @@ class MUC(BaseModule):
def leave(self, room_jid, reason=None): def leave(self, room_jid, reason=None):
self._log.info('Leave MUC: %s', room_jid) self._log.info('Leave MUC: %s', room_jid)
self._remove_join_timeout(room_jid) self._remove_join_timeout(room_jid)
self._remove_rejoin_timeout(room_jid)
self._set_muc_state(room_jid, MUCJoinedState.NOT_JOINED) self._set_muc_state(room_jid, MUCJoinedState.NOT_JOINED)
muc_data = self._get_muc_data(room_jid) muc_data = self._get_muc_data(room_jid)
self._con.get_module('Presence').send_presence( self._con.get_module('Presence').send_presence(
...@@ -361,20 +381,23 @@ class MUC(BaseModule): ...@@ -361,20 +381,23 @@ class MUC(BaseModule):
if muc_data.state == MUCJoinedState.JOINING: if muc_data.state == MUCJoinedState.JOINING:
if properties.error.condition == 'conflict': if properties.error.condition == 'conflict':
self._remove_rejoin_timeout(room_jid)
muc_data.nick += '_' muc_data.nick += '_'
self._log.info('Nickname conflict: %s change to %s', self._log.info('Nickname conflict: %s change to %s',
muc_data.jid, muc_data.nick) muc_data.jid, muc_data.nick)
self._join(muc_data) self._join(muc_data)
elif properties.error.condition == 'not-authorized': elif properties.error.condition == 'not-authorized':
self._remove_rejoin_timeout(room_jid)
self._set_muc_state(room_jid, MUCJoinedState.NOT_JOINED) self._set_muc_state(room_jid, MUCJoinedState.NOT_JOINED)
self._raise_muc_event('muc-password-required', properties) self._raise_muc_event('muc-password-required', properties)
else: else:
self._set_muc_state(room_jid, MUCJoinedState.NOT_JOINED) self._set_muc_state(room_jid, MUCJoinedState.NOT_JOINED)
app.nec.push_incoming_event( if room_jid not in self._rejoin_muc:
NetworkEvent('muc-join-failed', app.nec.push_incoming_event(
account=self._account, NetworkEvent('muc-join-failed',
room_jid=room_jid, account=self._account,
error=properties.error)) room_jid=room_jid,
error=properties.error))
elif muc_data.state == MUCJoinedState.CREATING: elif muc_data.state == MUCJoinedState.CREATING:
self._set_muc_state(room_jid, MUCJoinedState.NOT_JOINED) self._set_muc_state(room_jid, MUCJoinedState.NOT_JOINED)
...@@ -467,6 +490,9 @@ class MUC(BaseModule): ...@@ -467,6 +490,9 @@ class MUC(BaseModule):
if properties.is_muc_self_presence and properties.is_kicked: if properties.is_muc_self_presence and properties.is_kicked:
self._set_muc_state(room_jid, MUCJoinedState.NOT_JOINED) self._set_muc_state(room_jid, MUCJoinedState.NOT_JOINED)
self._raise_muc_event('muc-self-kicked', properties) self._raise_muc_event('muc-self-kicked', properties)
status_codes = properties.muc_status_codes or []
if StatusCode.REMOVED_SERVICE_SHUTDOWN in status_codes:
self._start_rejoin_timeout(room_jid)
return return
if properties.is_muc_self_presence and properties.type.is_unavailable: if properties.is_muc_self_presence and properties.type.is_unavailable:
...@@ -527,6 +553,21 @@ class MUC(BaseModule): ...@@ -527,6 +553,21 @@ class MUC(BaseModule):
properties.show) properties.show)
self._raise_muc_event('muc-user-status-show-changed', properties) self._raise_muc_event('muc-user-status-show-changed', properties)
def _start_rejoin_timeout(self, room_jid):
self._remove_rejoin_timeout(room_jid)
self._rejoin_muc.add(room_jid)
self._log.info('Start rejoin timeout for: %s', room_jid)
id_ = GLib.timeout_add_seconds(2, self._rejoin, room_jid)
self._rejoin_timeouts[room_jid] = id_
def _remove_rejoin_timeout(self, room_jid):
self._rejoin_muc.discard(room_jid)
id_ = self._rejoin_timeouts.get(room_jid)
if id_ is not None:
self._log.info('Remove rejoin timeout for: %s', room_jid)
GLib.source_remove(id_)
del self._rejoin_timeouts[room_jid]
def _start_join_timeout(self, room_jid): def _start_join_timeout(self, room_jid):
self._remove_join_timeout(room_jid) self._remove_join_timeout(room_jid)
self._log.info('Start join timeout for: %s', room_jid) self._log.info('Start join timeout for: %s', room_jid)
...@@ -644,6 +685,7 @@ class MUC(BaseModule): ...@@ -644,6 +685,7 @@ class MUC(BaseModule):
def _room_join_complete(self, muc_data): def _room_join_complete(self, muc_data):
self._remove_join_timeout(muc_data.jid) self._remove_join_timeout(muc_data.jid)
self._set_muc_state(muc_data.jid, MUCJoinedState.JOINED) self._set_muc_state(muc_data.jid, MUCJoinedState.JOINED)
self._remove_rejoin_timeout(muc_data.jid)
# We successfully joined a MUC, set add bookmark with autojoin # We successfully joined a MUC, set add bookmark with autojoin
self._con.get_module('Bookmarks').modify(muc_data.jid, self._con.get_module('Bookmarks').modify(muc_data.jid,
...@@ -695,6 +737,7 @@ class MUC(BaseModule): ...@@ -695,6 +737,7 @@ class MUC(BaseModule):
muc_data.captcha_id = properties.id muc_data.captcha_id = properties.id
self._set_muc_state(properties.jid, MUCJoinedState.CAPTCHA_REQUEST) self._set_muc_state(properties.jid, MUCJoinedState.CAPTCHA_REQUEST)
self._remove_rejoin_timeout(properties.jid)
app.nec.push_incoming_event( app.nec.push_incoming_event(
NetworkEvent('muc-captcha-challenge', NetworkEvent('muc-captcha-challenge',
...@@ -792,10 +835,18 @@ class MUC(BaseModule): ...@@ -792,10 +835,18 @@ class MUC(BaseModule):
self._log.info('Invite %s to %s', to, room) self._log.info('Invite %s to %s', to, room)
self._nbxmpp('MUC').invite(room, to, reason, password, continue_, type_) self._nbxmpp('MUC').invite(room, to, reason, password, continue_, type_)
def cleanup(self): @event_filter(['account'])
def _on_account_disconnected(self, event):
for room_jid in list(self._rejoin_timeouts.keys()):
self._remove_rejoin_timeout(room_jid)
for room_jid in list(self._join_timeouts.keys()): for room_jid in list(self._join_timeouts.keys()):
self._remove_join_timeout(room_jid) self._remove_join_timeout(room_jid)
def cleanup(self):
for handler in self._event_handlers:
app.ged.remove_event_handler(*handler)
def get_instance(*args, **kwargs): def get_instance(*args, **kwargs):
return MUC(*args, **kwargs), 'MUC' return MUC(*args, **kwargs), 'MUC'
...@@ -94,14 +94,6 @@ class GroupchatControl(ChatControlBase): ...@@ -94,14 +94,6 @@ class GroupchatControl(ChatControlBase):
self.is_continued = is_continued self.is_continued = is_continued
self.is_anonymous = True self.is_anonymous = True
# Controls the state of autorejoin.
# None - autorejoin is neutral.
# False - autorejoin is to be prevented (gets reset to initial state in
# got_connected()).
# int - autorejoin is being active and working (gets reset to initial
# state in got_connected()).
self.autorejoin = None
# Keep error dialog instance to be sure to have only once at a time # Keep error dialog instance to be sure to have only once at a time
self.error_dialog = None self.error_dialog = None
...@@ -1194,10 +1186,6 @@ class GroupchatControl(ChatControlBase): ...@@ -1194,10 +1186,6 @@ class GroupchatControl(ChatControlBase):
def got_connected(self): def got_connected(self):
self.roster.draw() self.roster.draw()
# Make autorejoin stop.
if self.autorejoin:
GLib.source_remove(self.autorejoin)
self.autorejoin = None
if self.disco_info.has_mam: if self.disco_info.has_mam:
# Request MAM # Request MAM
...@@ -1252,14 +1240,6 @@ class GroupchatControl(ChatControlBase): ...@@ -1252,14 +1240,6 @@ class GroupchatControl(ChatControlBase):
if self.parent_win: if self.parent_win:
self.parent_win.redraw_tab(self) self.parent_win.redraw_tab(self)
# Autorejoin stuff goes here.
# Notice that we don't need to activate autorejoin if connection is lost
# or in progress.
if self.autorejoin is None and app.account_is_connected(self.account):
ar_to = app.config.get('muc_autorejoin_timeout')
if ar_to:
self.autorejoin = GLib.timeout_add_seconds(ar_to, self.rejoin)
self.update_actions() self.update_actions()
def leave(self, reason=None): def leave(self, reason=None):
...@@ -1267,10 +1247,7 @@ class GroupchatControl(ChatControlBase): ...@@ -1267,10 +1247,7 @@ class GroupchatControl(ChatControlBase):
self._close_control(reason=reason) self._close_control(reason=reason)
def rejoin(self): def rejoin(self):
if not self.autorejoin:
return False
app.connections[self.account].get_module('MUC').join(self._muc_data) app.connections[self.account].get_module('MUC').join(self._muc_data)
return True
def send_pm(self, nick, message=None): def send_pm(self, nick, message=None):
ctrl = self._start_private_message(nick) ctrl = self._start_private_message(nick)
...@@ -1421,8 +1398,6 @@ class GroupchatControl(ChatControlBase): ...@@ -1421,8 +1398,6 @@ class GroupchatControl(ChatControlBase):
@event_filter(['account', 'room_jid']) @event_filter(['account', 'room_jid'])
def _on_self_kicked(self, event): def _on_self_kicked(self, event):
self.autorejoin = False
status_codes = event.properties.muc_status_codes or [] status_codes = event.properties.muc_status_codes or []
reason = event.properties.muc_user.reason reason = event.properties.muc_user.reason
...@@ -1473,7 +1448,6 @@ class GroupchatControl(ChatControlBase): ...@@ -1473,7 +1448,6 @@ class GroupchatControl(ChatControlBase):
reason = ': System shutdown' reason = ': System shutdown'
message = message.format(actor=actor, reason=reason) message = message.format(actor=actor, reason=reason)
self.add_info_message(message) self.add_info_message(message)
self.autorejoin = True
self.got_disconnected() self.got_disconnected()
...@@ -1566,7 +1540,6 @@ class GroupchatControl(ChatControlBase): ...@@ -1566,7 +1540,6 @@ class GroupchatControl(ChatControlBase):
def _on_muc_join_failed(self, event): def _on_muc_join_failed(self, event):
self.xml.error_label.set_text(to_user_string(event.error)) self.xml.error_label.set_text(to_user_string(event.error))
self._show_page('error') self._show_page('error')
self.autorejoin = False
@event_filter(['account', 'room_jid']) @event_filter(['account', 'room_jid'])
def _on_muc_creation_failed(self, event): def _on_muc_creation_failed(self, event):
...@@ -1594,7 +1567,6 @@ class GroupchatControl(ChatControlBase): ...@@ -1594,7 +1567,6 @@ class GroupchatControl(ChatControlBase):
'instead: xmpp:%s?join') % alternate 'instead: xmpp:%s?join') % alternate
self.add_info_message(join_message) self.add_info_message(join_message)
self.autorejoin = False
self.got_disconnected() self.got_disconnected()
con = app.connections[self.account] con = app.connections[self.account]
...@@ -1695,9 +1667,6 @@ class GroupchatControl(ChatControlBase): ...@@ -1695,9 +1667,6 @@ class GroupchatControl(ChatControlBase):
del win._controls[self.account][self.contact.jid] del win._controls[self.account][self.contact.jid]
def shutdown(self, reason=None): def shutdown(self, reason=None):
# Preventing autorejoin from being activated
self.autorejoin = False
# Leave MUC if we are still joined # Leave MUC if we are still joined
if self._muc_data.state != MUCJoinedState.NOT_JOINED: if self._muc_data.state != MUCJoinedState.NOT_JOINED:
self.got_disconnected() self.got_disconnected()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment