Avoid possible exception when leaving/reconnecting in a MUC
- Unregister nickname before sending unavailable presence - Send unavailable presence before destroying state - Call `leave` after unregistering, otherwise the disco entry for the MUC gets removed in `leave` while it's still necessary to unregister - Wrap `this.leave` in try/except in `onConnectionStatusChanged` handler - Add new MUC connection status, `CLOSING` to avoid `this.leave()` being called when `hidden` gets set to `true` while the MUC is in the process of being closed.
This commit is contained in:
parent
93e1758a0b
commit
a60127e66f
@ -117,6 +117,7 @@ converse.ROOMSTATUS = {
|
||||
ENTERED: 5,
|
||||
DESTROYED: 6,
|
||||
BANNED: 7,
|
||||
CLOSING: 8
|
||||
};
|
||||
|
||||
converse.plugins.add('converse-muc', {
|
||||
|
@ -259,19 +259,20 @@ const ChatRoomMixin = {
|
||||
* @method _converse.ChatRoom#onHiddenChange
|
||||
*/
|
||||
async onHiddenChange () {
|
||||
const roomstatus = converse.ROOMSTATUS;
|
||||
const conn_status = this.session.get('connection_status');
|
||||
if (this.get('hidden')) {
|
||||
if (conn_status === converse.ROOMSTATUS.ENTERED &&
|
||||
if (conn_status === roomstatus.ENTERED &&
|
||||
api.settings.get('muc_subscribe_to_rai') &&
|
||||
this.getOwnAffiliation() !== 'none') {
|
||||
if (conn_status !== converse.ROOMSTATUS.DISCONNECTED) {
|
||||
if (conn_status !== roomstatus.DISCONNECTED && conn_status !== roomstatus.CLOSING) {
|
||||
this.sendMarkerForLastMessage('received', true);
|
||||
await this.leave();
|
||||
}
|
||||
this.enableRAI();
|
||||
}
|
||||
} else {
|
||||
if (conn_status === converse.ROOMSTATUS.DISCONNECTED) {
|
||||
if (conn_status === roomstatus.DISCONNECTED) {
|
||||
this.rejoin();
|
||||
}
|
||||
this.clearUnreadMsgCounter();
|
||||
@ -339,7 +340,11 @@ const ChatRoomMixin = {
|
||||
async onConnectionStatusChanged () {
|
||||
if (this.session.get('connection_status') === converse.ROOMSTATUS.ENTERED) {
|
||||
if (this.get('hidden') && api.settings.get('muc_subscribe_to_rai') && this.getOwnAffiliation() !== 'none') {
|
||||
try {
|
||||
await this.leave();
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
}
|
||||
this.enableRAI();
|
||||
} else {
|
||||
await this.onRoomEntered();
|
||||
@ -852,28 +857,35 @@ const ChatRoomMixin = {
|
||||
* @param { string } [exit_msg] - Message to indicate your reason for leaving
|
||||
*/
|
||||
async leave (exit_msg) {
|
||||
this.features.destroy();
|
||||
api.connection.connected() && api.user.presence.send('unavailable', this.getRoomJIDAndNick(), exit_msg);
|
||||
|
||||
// Delete the features model
|
||||
if (this.features) {
|
||||
await new Promise(resolve =>
|
||||
this.features.destroy({
|
||||
'success': resolve,
|
||||
'error': (m, e) => { log.error(e); resolve(); }
|
||||
})
|
||||
);
|
||||
}
|
||||
// Delete disco entity
|
||||
const disco_entity = _converse.disco_entities?.get(this.get('jid'));
|
||||
if (disco_entity) {
|
||||
await new Promise((success, error) => disco_entity.destroy({ success, error }));
|
||||
}
|
||||
if (api.connection.connected()) {
|
||||
api.user.presence.send('unavailable', this.getRoomJIDAndNick(), exit_msg);
|
||||
await new Promise(resolve => disco_entity.destroy({
|
||||
'success': resolve,
|
||||
'error': (m, e) => { log.error(e); resolve(); }
|
||||
}));
|
||||
}
|
||||
u.safeSave(this.session, { 'connection_status': converse.ROOMSTATUS.DISCONNECTED });
|
||||
},
|
||||
|
||||
async close (ev) {
|
||||
u.safeSave(this.session, { 'connection_status': converse.ROOMSTATUS.CLOSING });
|
||||
this.sendMarkerForLastMessage('received', true);
|
||||
await this.unregisterNickname();
|
||||
await this.leave();
|
||||
if (
|
||||
api.settings.get('auto_register_muc_nickname') === 'unregister' &&
|
||||
(await api.disco.supports(Strophe.NS.MUC_REGISTER, this.get('jid')))
|
||||
) {
|
||||
this.unregisterNickname();
|
||||
}
|
||||
this.occupants.clearStore();
|
||||
|
||||
this.occupants.clearStore();
|
||||
if (ev?.name !== 'closeAllChatBoxes' && api.settings.get('muc_clear_messages_on_leave')) {
|
||||
this.clearMessages();
|
||||
}
|
||||
@ -882,20 +894,7 @@ const ChatRoomMixin = {
|
||||
await new Promise(resolve =>
|
||||
this.session.destroy({
|
||||
'success': resolve,
|
||||
'error': (m, e) => {
|
||||
log.error(e);
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
);
|
||||
// Delete the features model
|
||||
await new Promise(resolve =>
|
||||
this.features.destroy({
|
||||
'success': resolve,
|
||||
'error': (m, e) => {
|
||||
log.error(e);
|
||||
resolve();
|
||||
}
|
||||
'error': (m, e) => { log.error(e); resolve(); }
|
||||
})
|
||||
);
|
||||
return _converse.ChatBox.prototype.close.call(this);
|
||||
@ -1647,15 +1646,31 @@ const ChatRoomMixin = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check whether we should unregister the user from this MUC, and if so,
|
||||
* call { @link _converse.ChatRoom#sendUnregistrationIQ }
|
||||
* @method _converse.ChatRoom#unregisterNickname
|
||||
*/
|
||||
async unregisterNickname () {
|
||||
if (api.settings.get('auto_register_muc_nickname') === 'unregister') {
|
||||
try {
|
||||
if (await api.disco.supports(Strophe.NS.MUC_REGISTER, this.get('jid'))) {
|
||||
await this.sendUnregistrationIQ();
|
||||
}
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Send an IQ stanza to the MUC to unregister this user's nickname.
|
||||
* If the user had a 'member' affiliation, it'll be removed and their
|
||||
* nickname will no longer be reserved and can instead be used (and
|
||||
* registered) by other users.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#unregisterNickname
|
||||
* @method _converse.ChatRoom#sendUnregistrationIQ
|
||||
*/
|
||||
unregisterNickname () {
|
||||
sendUnregistrationIQ () {
|
||||
const iq = $iq({ 'to': this.get('jid'), 'type': 'set' })
|
||||
.c('query', { 'xmlns': Strophe.NS.MUC_REGISTER })
|
||||
.c('remove');
|
||||
@ -2588,7 +2603,10 @@ const ChatRoomMixin = {
|
||||
async onOwnPresence (stanza) {
|
||||
await this.occupants.fetched;
|
||||
const old_status = this.session.get('connection_status');
|
||||
if (stanza.getAttribute('type') !== 'unavailable' && old_status !== converse.ROOMSTATUS.ENTERED) {
|
||||
if (stanza.getAttribute('type') !== 'unavailable' &&
|
||||
old_status !== converse.ROOMSTATUS.ENTERED &&
|
||||
old_status !== converse.ROOMSTATUS.CLOSING
|
||||
) {
|
||||
// Set connection_status before creating the occupant, but
|
||||
// only trigger afterwards, so that plugins can access the
|
||||
// occupant in their event handlers.
|
||||
@ -2627,7 +2645,6 @@ const ChatRoomMixin = {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.session.save({ 'connection_status': converse.ROOMSTATUS.ENTERED });
|
||||
},
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user