[IMP] bus: allow tabs to have differents channels
This commit prepares the ground for the collaborative feature. Before this commit, it was impossible to have different channels for each tabs. In collaboration, multiples tabs could listen to differents set of channels. Example: One tab X could be subscribed to channel [a, b] and tab Y on channel [a, b] and a tab Z on [a, c]. Before this commit, only the channels of the master tab were listened. So in this case it was either [a, b] or [a, c] depending on which tab is the master. So either channel b or channel c were not listened depending on which tab is the master. Now, each time a tab listens or stops listens to a channel, the master tab listen all channels for all tabs. task-2497931 odoo pr: 75768 Part-of: odoo/odoo#75768
This commit is contained in:
@@ -46,6 +46,7 @@ var CrossTabBus = Longpolling.extend({
|
||||
var now = new Date().getTime();
|
||||
// used to prefix localStorage keys
|
||||
this._sanitizedOrigin = session.origin.replace(/:\/{0,2}/g, '_');
|
||||
this._currentTabChannels = new Set();
|
||||
// prevents collisions between different tabs and in tests
|
||||
this._id = _.uniqueId(this.LOCAL_STORAGE_PREFIX) + ':' + now;
|
||||
if (this._callLocalStorage('getItem', 'last_ts', 0) + 50000 < now) {
|
||||
@@ -66,18 +67,20 @@ var CrossTabBus = Longpolling.extend({
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
addChannel: function () {
|
||||
addChannel: function (channel) {
|
||||
this._currentTabChannels.add(channel);
|
||||
this._super.apply(this, arguments);
|
||||
this._callLocalStorage('setItem', 'channels', this._channels);
|
||||
this._updateChannels();
|
||||
},
|
||||
/**
|
||||
* Share the bus channels with the others tab by the local storage
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
deleteChannel: function () {
|
||||
deleteChannel: function (channel) {
|
||||
this._currentTabChannels.delete(channel);
|
||||
this._super.apply(this, arguments);
|
||||
this._callLocalStorage('setItem', 'channels', this._channels);
|
||||
this._updateChannels();
|
||||
},
|
||||
/**
|
||||
* @return {string}
|
||||
@@ -118,12 +121,11 @@ var CrossTabBus = Longpolling.extend({
|
||||
this._heartbeat();
|
||||
|
||||
if (this._isMasterTab) {
|
||||
this._callLocalStorage('setItem', 'channels', this._channels);
|
||||
this._callLocalStorage('setItem', 'options', this._options);
|
||||
} else {
|
||||
this._channels = this._callLocalStorage('getItem', 'channels', this._channels);
|
||||
this._options = this._callLocalStorage('getItem', 'options', this._options);
|
||||
}
|
||||
this._updateChannels();
|
||||
return; // startPolling will be called again on tab registration
|
||||
}
|
||||
|
||||
@@ -274,6 +276,45 @@ var CrossTabBus = Longpolling.extend({
|
||||
this._callLocalStorage('setItem', 'peers', peers);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Update localstorage channels of with the channels of this tab.
|
||||
*
|
||||
* @private
|
||||
* @return {boolean} true if the aggregated channels has changed.
|
||||
*/
|
||||
_updateChannels: function () {
|
||||
const currentPeerIds = new Set(Object.keys(this._callLocalStorage('getItem', 'peers') || {}));
|
||||
const peerChannels = this._callLocalStorage('getItem', 'channels') || {};
|
||||
const peerChannelsBefore = JSON.stringify(peerChannels);
|
||||
peerChannels[this._id] = Array.from(this._currentTabChannels);
|
||||
|
||||
// Clean outdated channels.
|
||||
for (const channelPeerId of Object.keys(peerChannels)) {
|
||||
if (!currentPeerIds.has(channelPeerId)) {
|
||||
delete peerChannels[channelPeerId];
|
||||
}
|
||||
}
|
||||
|
||||
const peerChannelsAfter = JSON.stringify(peerChannels);
|
||||
if (peerChannelsBefore === peerChannelsAfter) {
|
||||
return false;
|
||||
}
|
||||
this._callLocalStorage('setItem', 'channels', peerChannels);
|
||||
|
||||
const allChannels = new Set();
|
||||
for (const channels of Object.values(peerChannels)) {
|
||||
for (const channel of channels) {
|
||||
allChannels.add(channel);
|
||||
}
|
||||
}
|
||||
// Insure the current tab channels are always in the aggregated channels
|
||||
// in case this tab is not in the currentPeerIds nor peerChannels.
|
||||
for (const channel of this._currentTabChannels) {
|
||||
allChannels.add(channel);
|
||||
}
|
||||
this._channels = Array.from(allChannels);
|
||||
return true;
|
||||
},
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -327,7 +368,9 @@ var CrossTabBus = Longpolling.extend({
|
||||
}
|
||||
// update channels
|
||||
else if (key === this._generateKey('channels')) {
|
||||
this._channels = value;
|
||||
if (this._updateChannels()) {
|
||||
this._restartPolling();
|
||||
};
|
||||
}
|
||||
// update options
|
||||
else if (key === this._generateKey('options')) {
|
||||
@@ -349,6 +392,8 @@ var CrossTabBus = Longpolling.extend({
|
||||
var peers = this._callLocalStorage('getItem', 'peers') || {};
|
||||
delete peers[this._id];
|
||||
this._callLocalStorage('setItem', 'peers', peers);
|
||||
this._currentTabChannels.clear();
|
||||
this._updateChannels();
|
||||
|
||||
// unload master
|
||||
if (this._isMasterTab) {
|
||||
|
||||
@@ -75,11 +75,7 @@ var LongpollingBus = Bus.extend(ServicesMixin, {
|
||||
addChannel: function (channel) {
|
||||
if (this._channels.indexOf(channel) === -1) {
|
||||
this._channels.push(channel);
|
||||
if (this._pollRpc) {
|
||||
this._pollRpc.abort();
|
||||
} else {
|
||||
this.startPolling();
|
||||
}
|
||||
this._restartPolling();
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -255,6 +251,18 @@ var LongpollingBus = Bus.extend(ServicesMixin, {
|
||||
_onPresence: function () {
|
||||
this._lastPresenceTime = new Date().getTime();
|
||||
},
|
||||
/**
|
||||
* Restart polling.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_restartPolling() {
|
||||
if (this._pollRpc) {
|
||||
this._pollRpc.abort();
|
||||
} else {
|
||||
this.startPolling();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return LongpollingBus;
|
||||
|
||||
Reference in New Issue
Block a user