Skip to content

Commit

Permalink
Refactoring: Replace DOM events with broadcast channels
Browse files Browse the repository at this point in the history
Broadcast channels are more suited to uBO than DOM events to dispatch
notifications to different parts of uBO.

DOM events can only be dispatched to local context, broadcast channels
dispatch to all contexts (i.e. background process, workers, auxiliary
pages) -- this last behavior is better suited to uBO to communicate
internal changes to all potential listeners, not just those in the local
context.

Additionally, broadcasting to content scripts is now done through
tabs.sendMessage() instead of through potentially opened message
ports, this simplifies broadcasting to content scripts, and this
doesn't require to have long-lived message ports in content
scripts.
  • Loading branch information
gorhill committed Dec 1, 2023
1 parent c4de555 commit 67fb969
Show file tree
Hide file tree
Showing 16 changed files with 186 additions and 185 deletions.
54 changes: 3 additions & 51 deletions platform/common/vapi-client-extra.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,9 @@
(( ) => {
// >>>>>>>> start of private namespace

if (
typeof vAPI !== 'object' ||
vAPI.messaging instanceof Object === false ||
vAPI.MessagingConnection instanceof Function
) {
return;
}
if ( typeof vAPI !== 'object' ) { return; }
if ( vAPI.messaging instanceof Object === false ) { return; }
if ( vAPI.MessagingConnection instanceof Function ) { return; }

const listeners = new Set();
const connections = new Map();
Expand Down Expand Up @@ -247,50 +243,6 @@ vAPI.messaging.extensions.push(vAPI.MessagingConnection);

/******************************************************************************/

// Broadcast listening ability

(( ) => {
// >>>>>>>> start of private namespace

if (
typeof vAPI !== 'object' ||
vAPI.messaging instanceof Object === false ||
vAPI.broadcastListener instanceof Object
) {
return;
}

const listeners = new Set();

vAPI.broadcastListener = {
add: function(listener) {
listeners.add(listener);
vAPI.messaging.getPort();
},
remove: function(listener) {
listeners.delete(listener);
},
canDestroyPort() {
return listeners.size === 0;
},
mustDestroyPort() {
listeners.clear();
},
canProcessMessage(details) {
if ( details.broadcast === false ) { return; }
for ( const listener of listeners ) {
listener(details.msg);
}
},
};

vAPI.messaging.extensions.push(vAPI.broadcastListener);

// <<<<<<<< end of private namespace
})();

/******************************************************************************/




Expand Down
2 changes: 2 additions & 0 deletions platform/common/vapi-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

// For non-background page

/* globals browser */

'use strict';

/******************************************************************************/
Expand Down
5 changes: 3 additions & 2 deletions src/js/1p-filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@

'use strict';

import { i18n$ } from './i18n.js';
import { onBroadcast } from './broadcast.js';
import { dom, qs$ } from './dom.js';
import { i18n$ } from './i18n.js';
import './codemirror/ubo-static-filtering.js';

/******************************************************************************/
Expand Down Expand Up @@ -310,7 +311,7 @@ dom.on('#userFiltersRevert', 'click', revertChanges);

// https://github.com/gorhill/uBlock/issues/3704
// Merge changes to user filters occurring in the background
vAPI.broadcastListener.add(msg => {
onBroadcast(msg => {
switch ( msg.what ) {
case 'userFiltersUpdated': {
cmEditor.startOperation();
Expand Down
25 changes: 12 additions & 13 deletions src/js/3p-filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@

'use strict';

import { i18n, i18n$ } from './i18n.js';
import { onBroadcast } from './broadcast.js';
import { dom, qs$, qsa$ } from './dom.js';
import { i18n, i18n$ } from './i18n.js';

/******************************************************************************/

Expand All @@ -35,9 +36,7 @@ let listsetDetails = {};

/******************************************************************************/

const messaging = vAPI.messaging;

vAPI.broadcastListener.add(msg => {
onBroadcast(msg => {
switch ( msg.what ) {
case 'assetUpdated':
updateAssetStatus(msg);
Expand Down Expand Up @@ -277,7 +276,7 @@ const renderFilterLists = ( ) => {
renderWidgets();
};

messaging.send('dashboard', {
vAPI.messaging.send('dashboard', {
what: 'getLists',
}).then(response => {
onListsReceived(response);
Expand Down Expand Up @@ -510,7 +509,7 @@ const onPurgeClicked = ev => {
dom.cl.remove(listLeaf, 'cached');
}

messaging.send('dashboard', {
vAPI.messaging.send('dashboard', {
what: 'purgeCaches',
assetKeys,
});
Expand All @@ -534,15 +533,15 @@ dom.on('#lists', 'click', 'span.cache', onPurgeClicked);
const selectFilterLists = async ( ) => {
// Cosmetic filtering switch
let checked = qs$('#parseCosmeticFilters').checked;
messaging.send('dashboard', {
vAPI.messaging.send('dashboard', {
what: 'userSettings',
name: 'parseAllABPHideFilters',
value: checked,
});
listsetDetails.parseCosmeticFilters = checked;

checked = qs$('#ignoreGenericCosmeticFilters').checked;
messaging.send('dashboard', {
vAPI.messaging.send('dashboard', {
what: 'userSettings',
name: 'ignoreGenericCosmeticFilters',
value: checked,
Expand Down Expand Up @@ -581,7 +580,7 @@ const selectFilterLists = async ( ) => {

hashFromListsetDetails();

await messaging.send('dashboard', {
await vAPI.messaging.send('dashboard', {
what: 'applyFilterListSelection',
toSelect,
toImport,
Expand All @@ -596,7 +595,7 @@ const buttonApplyHandler = async ( ) => {
dom.cl.add(dom.body, 'working');
dom.cl.remove('#lists .listEntry.stickied', 'stickied');
renderWidgets();
await messaging.send('dashboard', { what: 'reloadAllFilters' });
await vAPI.messaging.send('dashboard', { what: 'reloadAllFilters' });
dom.cl.remove(dom.body, 'working');
};

Expand All @@ -609,15 +608,15 @@ const buttonUpdateHandler = async ( ) => {
await selectFilterLists();
dom.cl.add(dom.body, 'updating');
renderWidgets();
messaging.send('dashboard', { what: 'forceUpdateAssets' });
vAPI.messaging.send('dashboard', { what: 'forceUpdateAssets' });
};

dom.on('#buttonUpdate', 'click', ( ) => { buttonUpdateHandler(); });

/******************************************************************************/

const buttonPurgeAllHandler = async hard => {
await messaging.send('dashboard', {
await vAPI.messaging.send('dashboard', {
what: 'purgeAllCaches',
hard,
});
Expand All @@ -630,7 +629,7 @@ dom.on('#buttonPurgeAll', 'click', ev => { buttonPurgeAllHandler(ev.shiftKey); }

const userSettingCheckboxChanged = ( ) => {
const target = event.target;
messaging.send('dashboard', {
vAPI.messaging.send('dashboard', {
what: 'userSettings',
name: target.id,
value: target.checked,
Expand Down
9 changes: 5 additions & 4 deletions src/js/assets.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@

/******************************************************************************/

import cacheStorage from './cachestorage.js';
import logger from './logger.js';
import µb from './background.js';
import { broadcast } from './broadcast.js';
import cacheStorage from './cachestorage.js';
import { ubolog } from './console.js';
import { i18n$ } from './i18n.js';
import logger from './logger.js';
import * as sfp from './static-filtering-parser.js';
import { orphanizeString, } from './text-utils.js';

Expand Down Expand Up @@ -1234,7 +1235,7 @@ async function diffUpdater() {
assetCacheSetDetails(data.assetKey, metadata);
};
bc.onmessage = ev => {
const data = ev.data;
const data = ev.data || {};
if ( data.what === 'ready' ) {
ubolog('Diff updater: hard updating', toHardUpdate.map(v => v.assetKey).join());
while ( toHardUpdate.length !== 0 ) {
Expand Down Expand Up @@ -1279,7 +1280,7 @@ async function diffUpdater() {
} else if ( data.status === 'nopatch-yet' || data.status === 'nodiff' ) {
ubolog(`Diff updater: skip update of ${data.assetKey} using ${data.patchPath}\n\treason: ${data.status}`);
assetCacheSetDetails(data.assetKey, { writeTime: data.writeTime });
vAPI.messaging.broadcast({
broadcast({
what: 'assetUpdated',
key: data.assetKey,
cached: true,
Expand Down
75 changes: 75 additions & 0 deletions src/js/broadcast.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*******************************************************************************
uBlock Origin - a browser extension to block requests.
Copyright (C) 2014-present Raymond Hill
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uBlock
*/

/* globals browser */

'use strict';

/******************************************************************************/

// Broadcast a message to all uBO contexts

let broadcastChannel;

export function broadcast(message) {
if ( broadcastChannel === undefined ) {
broadcastChannel = new self.BroadcastChannel('uBO');
}
broadcastChannel.postMessage(message);
}

/******************************************************************************/

// Broadcast a message to all uBO contexts and all uBO's content scripts

export async function broadcastToAll(message) {
broadcast(message);
const tabs = await vAPI.tabs.query({
discarded: false,
});
const bcmessage = Object.assign({ broadcast: true }, message);
for ( const tab of tabs ) {
browser.tabs.sendMessage(tab.id, bcmessage);
}
}

/******************************************************************************/

export function onBroadcast(listener) {
const bc = new self.BroadcastChannel('uBO');
bc.onmessage = ev => listener(ev.data || {});
return bc;
}

/******************************************************************************/

export function filteringBehaviorChanged(details = {}) {
if ( typeof details.direction !== 'number' || details.direction >= 0 ) {
filteringBehaviorChanged.throttle.offon(727);
}
broadcast(Object.assign({ what: 'filteringBehaviorChanged' }, details));
}

filteringBehaviorChanged.throttle = vAPI.defer.create(( ) => {
vAPI.net.handlerBehaviorChanged();
});

/******************************************************************************/
2 changes: 1 addition & 1 deletion src/js/diff-updater.js
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ async function fetchAndApplyAllPatches(assetDetails) {
const bc = new globalThis.BroadcastChannel('diffUpdater');

bc.onmessage = ev => {
const message = ev.data;
const message = ev.data || {};
switch ( message.what ) {
case 'update':
fetchAndApplyAllPatches(message).then(response => {
Expand Down
6 changes: 5 additions & 1 deletion src/js/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@

/******************************************************************************/

import { broadcastToAll } from './broadcast.js';

/******************************************************************************/

let buffer = null;
let lastReadTime = 0;
let writePtr = 0;
Expand All @@ -40,7 +44,7 @@ const janitorTimer = vAPI.defer.create(( ) => {
buffer = null;
writePtr = 0;
logger.ownerId = undefined;
vAPI.messaging.broadcast({ what: 'loggerDisabled' });
broadcastToAll({ what: 'loggerDisabled' });
});

const boxEntry = function(details) {
Expand Down
3 changes: 2 additions & 1 deletion src/js/messaging.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import publicSuffixList from '../lib/publicsuffixlist/publicsuffixlist.js';
import punycode from '../lib/punycode.js';

import { filteringBehaviorChanged } from './broadcast.js';
import cacheStorage from './cachestorage.js';
import cosmeticFilteringEngine from './cosmetic-filtering.js';
import htmlFilteringEngine from './html-filtering.js';
Expand Down Expand Up @@ -346,7 +347,7 @@ const onMessage = function(request, sender, callback) {
case 'setWhitelist':
µb.netWhitelist = µb.whitelistFromString(request.whitelist);
µb.saveWhitelist();
µb.filteringBehaviorChanged();
filteringBehaviorChanged();
break;

case 'toggleHostnameSwitch':
Expand Down
11 changes: 5 additions & 6 deletions src/js/scriptlet-filtering.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
/******************************************************************************/

import µb from './background.js';
import { onBroadcast } from './broadcast.js';
import { redirectEngine as reng } from './redirect-engine.js';
import { sessionFirewall } from './filtering-engines.js';
import { StaticExtFilteringHostnameDB } from './static-ext-filtering-db.js';
Expand Down Expand Up @@ -67,12 +68,10 @@ const contentScriptRegisterer = new (class {
constructor() {
this.hostnameToDetails = new Map();
if ( browser.contentScripts === undefined ) { return; }
µb.onEvent('filteringBehaviorChanged', ev => {
const details = ev.detail;
if ( details instanceof Object ) {
if ( details.direction > 0 ) { return; }
if ( details.hostname ) { return this.flush(details.hostname); }
}
onBroadcast(msg => {
if ( msg.what !== 'filteringBehaviorChanged' ) { return; }
if ( msg.direction > 0 ) { return; }
if ( msg.hostname ) { return this.flush(msg.hostname); }
this.reset();
});
}
Expand Down
Loading

0 comments on commit 67fb969

Please sign in to comment.