Refactor MAM and clear private chats upon reconnection
- Add `onReconnected` method for chatboxes to clear messages - Move MAM models to headless build. - New event `onChatReconnected`
This commit is contained in:
parent
271c79eae8
commit
7ab59ad63e
@ -26,6 +26,7 @@
|
||||
"split", "trim", "forEach", "toUpperCase", "includes", "values"
|
||||
]
|
||||
}],
|
||||
"lodash/import-scope": "off",
|
||||
"lodash/prefer-invoke-map": "off",
|
||||
"lodash/prefer-startswith": "off",
|
||||
"lodash/prefer-constant": "off",
|
||||
|
@ -14,6 +14,8 @@
|
||||
- New API method [\_converse.api.disco.features.get](https://conversejs.org/docs/html/api/-_converse.api.disco.features.html#.get)
|
||||
- New config setting [muc_show_join_leave_status](https://conversejs.org/docs/html/configuration.html#muc-show-join-leave-status)
|
||||
- New event: `chatBoxBlurred`.
|
||||
- New event: [chatBoxBlurred](https://conversejs.org/docs/html/api/-_converse.html#event:chatBoxBlurred)
|
||||
- New event: [chatReconnected](https://conversejs.org/docs/html/api/-_converse.html#event:chatReconnected)
|
||||
- Properly handle message correction being received before the corrected message
|
||||
- #1296: `embedded` view mode shows `chatbox-navback` arrow in header
|
||||
- #1465: When highlighting a roster contact, they're incorrectly shown as online
|
||||
|
@ -10,8 +10,8 @@
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
<link type="text/css" rel="stylesheet" href="/docs/source/_static/api.css">
|
||||
<link type="text/css" rel="stylesheet" href="/css/converse.min.css">
|
||||
<link rel="shortcut icon" href="/css/images/favicon.ico"/>
|
||||
<link type="text/css" rel="stylesheet" href="/dist/converse.min.css">
|
||||
<link rel="shortcut icon" href="/images/favicon.ico"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -2,7 +2,7 @@
|
||||
{% extends "!layout.html" %}
|
||||
|
||||
{# Custom CSS overrides #}
|
||||
{% set css_files = css_files + ['_static/style.css', "../../css/converse.min.css"] %}
|
||||
{% set css_files = css_files + ['_static/style.css', "../../dist/converse.min.css"] %}
|
||||
{% set script_files = script_files + ["../../dist/converse.min.js", "../../analytics.js"] %}
|
||||
|
||||
{# Add some extra stuff before and use existing with 'super()' call. #}
|
||||
|
@ -18,7 +18,7 @@ which hosts its JavaScript and CSS files.
|
||||
The latest versions of these files are available at these URLs:
|
||||
|
||||
* https://cdn.conversejs.org/dist/converse.min.js
|
||||
* https://cdn.conversejs.org/css/converse.min.css
|
||||
* https://cdn.conversejs.org/dist/converse.min.css
|
||||
|
||||
If you are integrating Converse into an existing website or app, then we recommend
|
||||
that you load a specific version of Converse. Otherwise your website or app
|
||||
@ -26,15 +26,15 @@ might break when a new backwards-incompatible version of Converse is released.
|
||||
|
||||
To load a specific version of Converse you can put the version in the URL:
|
||||
|
||||
* https://cdn.conversejs.org/4.2.0/dist/converse.min.js
|
||||
* https://cdn.conversejs.org/4.2.0/css/converse.min.css
|
||||
* https://cdn.conversejs.org/5.0.0/dist/converse.min.js
|
||||
* https://cdn.conversejs.org/5.0.0/dist/converse.min.css
|
||||
|
||||
You can include these two URLs inside the *<head>* element of your website
|
||||
via the *script* and *link* tags:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="https://cdn.conversejs.org/4.2.0/css/converse.min.css">
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="https://cdn.conversejs.org/4.2.0/dist/converse.min.css">
|
||||
<script src="https://cdn.conversejs.org/4.2.0/dist/converse.min.js" charset="utf-8"></script>
|
||||
|
||||
|
||||
|
@ -199,7 +199,9 @@ converse.plugins.add('converse-controlbox', {
|
||||
'type': _converse.CONTROLBOX_TYPE,
|
||||
'url': ''
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onReconnection: _.noop
|
||||
});
|
||||
|
||||
|
||||
|
@ -7,16 +7,12 @@
|
||||
// Views for XEP-0313 Message Archive Management
|
||||
|
||||
import converse from "@converse/headless/converse-core";
|
||||
|
||||
|
||||
const CHATROOMS_TYPE = 'chatroom';
|
||||
const { Strophe, _ } = converse.env;
|
||||
const u = converse.env.utils;
|
||||
import { debounce } from 'lodash'
|
||||
|
||||
|
||||
converse.plugins.add('converse-mam-views', {
|
||||
|
||||
dependencies: ['converse-disco', 'converse-mam', 'converse-chatview', 'converse-muc-views'],
|
||||
dependencies: ['converse-mam', 'converse-chatview', 'converse-muc-views'],
|
||||
|
||||
overrides: {
|
||||
// Overrides mentioned here will be picked up by converse.js's
|
||||
@ -25,73 +21,11 @@ converse.plugins.add('converse-mam-views', {
|
||||
//
|
||||
// New functions which don't exist yet can also be added.
|
||||
|
||||
|
||||
ChatBox: {
|
||||
fetchNewestMessages () {
|
||||
/* Fetches messages that might have been archived *after*
|
||||
* the last archived message in our local cache.
|
||||
*/
|
||||
if (this.disable_mam) {
|
||||
return;
|
||||
}
|
||||
const { _converse } = this.__super__;
|
||||
const most_recent_msg = u.getMostRecentMessage(this);
|
||||
|
||||
if (_.isNil(most_recent_msg)) {
|
||||
this.fetchArchivedMessages();
|
||||
} else {
|
||||
const stanza_id = most_recent_msg.get(`stanza_id ${this.get('jid')}`);
|
||||
if (stanza_id) {
|
||||
this.fetchArchivedMessages({'after': stanza_id});
|
||||
} else {
|
||||
this.fetchArchivedMessages({'start': most_recent_msg.get('time')});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async fetchArchivedMessages (options) {
|
||||
if (this.disable_mam) {
|
||||
return;
|
||||
}
|
||||
const { _converse } = this.__super__;
|
||||
const is_groupchat = this.get('type') === CHATROOMS_TYPE;
|
||||
const mam_jid = is_groupchat ? this.get('jid') : _converse.bare_jid;
|
||||
if (!(await _converse.api.disco.supports(Strophe.NS.MAM, mam_jid))) {
|
||||
return;
|
||||
}
|
||||
let message_handler;
|
||||
if (is_groupchat) {
|
||||
message_handler = this.onMessage.bind(this);
|
||||
} else {
|
||||
message_handler = _converse.chatboxes.onMessage.bind(_converse.chatboxes)
|
||||
}
|
||||
let result = {};
|
||||
try {
|
||||
result = await _converse.api.archive.query(
|
||||
Object.assign({
|
||||
'groupchat': is_groupchat,
|
||||
'before': '', // Page backwards from the most recent message
|
||||
'max': _converse.archived_messages_page_size,
|
||||
'with': this.get('jid'),
|
||||
}, options));
|
||||
} catch (e) {
|
||||
_converse.log(
|
||||
"Error or timeout while trying to fetch "+
|
||||
"archived messages", Strophe.LogLevel.ERROR);
|
||||
_converse.log(e, Strophe.LogLevel.ERROR);
|
||||
}
|
||||
if (result.messages) {
|
||||
result.messages.forEach(message_handler);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ChatBoxView: {
|
||||
|
||||
render () {
|
||||
const result = this.__super__.render.apply(this, arguments);
|
||||
if (!this.disable_mam) {
|
||||
this.content.addEventListener('scroll', _.debounce(this.onScroll.bind(this), 100));
|
||||
this.content.addEventListener('scroll', debounce(this.onScroll.bind(this), 100));
|
||||
}
|
||||
return result;
|
||||
},
|
||||
@ -115,52 +49,14 @@ converse.plugins.add('converse-mam-views', {
|
||||
}
|
||||
},
|
||||
|
||||
ChatRoom: {
|
||||
|
||||
initialize () {
|
||||
this.__super__.initialize.apply(this, arguments);
|
||||
this.on('change:mam_enabled', this.fetchArchivedMessagesIfNecessary, this);
|
||||
this.on('change:connection_status', this.fetchArchivedMessagesIfNecessary, this);
|
||||
},
|
||||
|
||||
fetchArchivedMessagesIfNecessary () {
|
||||
if (this.get('connection_status') !== converse.ROOMSTATUS.ENTERED ||
|
||||
!this.get('mam_enabled') ||
|
||||
this.get('mam_initialized')) {
|
||||
return;
|
||||
}
|
||||
this.fetchArchivedMessages();
|
||||
this.save({'mam_initialized': true});
|
||||
}
|
||||
},
|
||||
|
||||
ChatRoomView: {
|
||||
|
||||
renderChatArea () {
|
||||
const result = this.__super__.renderChatArea.apply(this, arguments);
|
||||
if (!this.disable_mam) {
|
||||
this.content.addEventListener('scroll', _.debounce(this.onScroll.bind(this), 100));
|
||||
this.content.addEventListener('scroll', debounce(this.onScroll.bind(this), 100));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
initialize () {
|
||||
/* The initialize function gets called as soon as the plugin is
|
||||
* loaded by Converse.js's plugin machinery.
|
||||
*/
|
||||
const { _converse } = this;
|
||||
|
||||
/************************ BEGIN Event Handlers ************************/
|
||||
_converse.api.listen.on('afterMessagesFetched', chatbox => chatbox.fetchNewestMessages());
|
||||
|
||||
_converse.api.listen.on('reconnected', () => {
|
||||
const private_chats = _converse.chatboxviews.filter(
|
||||
view => _.at(view, 'model.attributes.type')[0] === 'chatbox'
|
||||
);
|
||||
_.each(private_chats, view => view.model.fetchNewestMessages())
|
||||
});
|
||||
/************************ END Event Handlers ************************/
|
||||
}
|
||||
});
|
||||
|
@ -352,6 +352,17 @@ converse.plugins.add('converse-chatboxes', {
|
||||
}
|
||||
},
|
||||
|
||||
onReconnection () {
|
||||
this.clearMessages();
|
||||
/**
|
||||
* Triggered whenever a `_converse.ChatBox` instance has reconnected after an outage
|
||||
* @event _converse#onChatReconnected
|
||||
* @type {_converse.ChatBox | _converse.ChatRoom}
|
||||
* @example _converse.api.listen.on('onChatReconnected', chatbox => { ... });
|
||||
*/
|
||||
_converse.api.trigger('chatReconnected', this);
|
||||
},
|
||||
|
||||
validate (attrs, options) {
|
||||
const { _converse } = this.__super__;
|
||||
if (!attrs.jid) {
|
||||
@ -1150,6 +1161,8 @@ converse.plugins.add('converse-chatboxes', {
|
||||
_converse.api.trigger('chatBoxesInitialized');
|
||||
});
|
||||
_converse.api.listen.on('presencesInitialized', () => _converse.chatboxes.onConnected());
|
||||
|
||||
_converse.api.listen.on('reconnected', () => _converse.chatboxes.forEach(m => m.onReconnection()));
|
||||
/************************ END Event Handlers ************************/
|
||||
|
||||
|
||||
|
@ -23,7 +23,7 @@ const MAM_ATTRIBUTES = ['with', 'start', 'end'];
|
||||
|
||||
converse.plugins.add('converse-mam', {
|
||||
|
||||
dependencies: ['converse-muc'],
|
||||
dependencies: ['converse-disco', 'converse-muc'],
|
||||
|
||||
overrides: {
|
||||
// Overrides mentioned here will be picked up by converse.js's
|
||||
@ -33,6 +33,64 @@ converse.plugins.add('converse-mam', {
|
||||
// New functions which don't exist yet can also be added.
|
||||
ChatBox: {
|
||||
|
||||
fetchNewestMessages () {
|
||||
/* Fetches messages that might have been archived *after*
|
||||
* the last archived message in our local cache.
|
||||
*/
|
||||
if (this.disable_mam) {
|
||||
return;
|
||||
}
|
||||
const { _converse } = this.__super__;
|
||||
const most_recent_msg = u.getMostRecentMessage(this);
|
||||
|
||||
if (_.isNil(most_recent_msg)) {
|
||||
this.fetchArchivedMessages();
|
||||
} else {
|
||||
const stanza_id = most_recent_msg.get(`stanza_id ${this.get('jid')}`);
|
||||
if (stanza_id) {
|
||||
this.fetchArchivedMessages({'after': stanza_id});
|
||||
} else {
|
||||
this.fetchArchivedMessages({'start': most_recent_msg.get('time')});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async fetchArchivedMessages (options) {
|
||||
if (this.disable_mam) {
|
||||
return;
|
||||
}
|
||||
const { _converse } = this.__super__;
|
||||
const is_groupchat = this.get('type') === CHATROOMS_TYPE;
|
||||
const mam_jid = is_groupchat ? this.get('jid') : _converse.bare_jid;
|
||||
if (!(await _converse.api.disco.supports(Strophe.NS.MAM, mam_jid))) {
|
||||
return;
|
||||
}
|
||||
let message_handler;
|
||||
if (is_groupchat) {
|
||||
message_handler = this.onMessage.bind(this);
|
||||
} else {
|
||||
message_handler = _converse.chatboxes.onMessage.bind(_converse.chatboxes)
|
||||
}
|
||||
let result = {};
|
||||
try {
|
||||
result = await _converse.api.archive.query(
|
||||
Object.assign({
|
||||
'groupchat': is_groupchat,
|
||||
'before': '', // Page backwards from the most recent message
|
||||
'max': _converse.archived_messages_page_size,
|
||||
'with': this.get('jid'),
|
||||
}, options));
|
||||
} catch (e) {
|
||||
_converse.log(
|
||||
"Error or timeout while trying to fetch "+
|
||||
"archived messages", Strophe.LogLevel.ERROR);
|
||||
_converse.log(e, Strophe.LogLevel.ERROR);
|
||||
}
|
||||
if (result.messages) {
|
||||
result.messages.forEach(message_handler);
|
||||
}
|
||||
},
|
||||
|
||||
async findDuplicateFromArchiveID (stanza) {
|
||||
const { _converse } = this.__super__;
|
||||
const result = sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, stanza).pop();
|
||||
@ -66,7 +124,26 @@ converse.plugins.add('converse-mam', {
|
||||
}
|
||||
return attrs;
|
||||
}
|
||||
},
|
||||
|
||||
ChatRoom: {
|
||||
initialize () {
|
||||
this.__super__.initialize.apply(this, arguments);
|
||||
this.on('change:mam_enabled', this.fetchArchivedMessagesIfNecessary, this);
|
||||
this.on('change:connection_status', this.fetchArchivedMessagesIfNecessary, this);
|
||||
},
|
||||
|
||||
fetchArchivedMessagesIfNecessary () {
|
||||
if (this.get('connection_status') !== converse.ROOMSTATUS.ENTERED ||
|
||||
!this.get('mam_enabled') ||
|
||||
this.get('mam_initialized')) {
|
||||
return;
|
||||
}
|
||||
this.fetchArchivedMessages();
|
||||
this.save({'mam_initialized': true});
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
initialize () {
|
||||
@ -139,6 +216,8 @@ converse.plugins.add('converse-mam', {
|
||||
}
|
||||
});
|
||||
|
||||
_converse.api.listen.on('afterMessagesFetched', chat => chat.fetchNewestMessages());
|
||||
_converse.api.listen.on('chatReconnected', chat => chat.fetchNewestMessages());
|
||||
_converse.api.listen.on('addClientFeatures', () => _converse.api.disco.own.features.add(Strophe.NS.MAM));
|
||||
/************************ END Event Handlers ************************/
|
||||
|
||||
|
@ -240,7 +240,6 @@ converse.plugins.add('converse-muc', {
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
async onConnectionStatusChanged () {
|
||||
if (this.get('connection_status') === converse.ROOMSTATUS.ENTERED) {
|
||||
this.occupants.fetchMembers();
|
||||
@ -254,6 +253,14 @@ converse.plugins.add('converse-muc', {
|
||||
}
|
||||
},
|
||||
|
||||
onReconnection () {
|
||||
this.save('connection_status', converse.ROOMSTATUS.DISCONNECTED);
|
||||
this.clearMessages();
|
||||
this.registerHandlers();
|
||||
this.fetchMessages();
|
||||
this.join();
|
||||
},
|
||||
|
||||
initFeatures () {
|
||||
const storage = _converse.config.get('storage');
|
||||
const id = `converse.muc-features-${_converse.bare_jid}-${this.get('jid')}`;
|
||||
@ -1559,22 +1566,6 @@ converse.plugins.add('converse-muc', {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function reconnectToChatRooms () {
|
||||
/* Upon a reconnection event from converse, join again
|
||||
* all the open groupchats.
|
||||
*/
|
||||
_converse.chatboxes
|
||||
.filter(m => (m.get('type') === _converse.CHATROOMS_TYPE))
|
||||
.forEach(room => {
|
||||
room.save('connection_status', converse.ROOMSTATUS.DISCONNECTED);
|
||||
room.clearMessages();
|
||||
room.registerHandlers();
|
||||
room.fetchMessages();
|
||||
room.join();
|
||||
});
|
||||
}
|
||||
_converse.api.listen.on('reconnected', reconnectToChatRooms);
|
||||
/************************ END Event Handlers ************************/
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user