From a91781a4959c0381c8ab3230545e4e0f579d4a2c Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Wed, 14 Dec 2022 16:04:45 -0500 Subject: [PATCH] Rewrite logger's "exceptor" feature Related issue: - https://github.com/uBlockOrigin/uBlock-issues/issues/1861 The "exceptor" feature has been rewritten, with the following changes as a result: - The excepted filters cease to exist when closing the logger - It's now possible to temporary except network filters When toggling on/off a temporary exception, filter lists are now fully reloaded. This simplified managing temporary exceptions, and made it easy to implement temporary exception for network filters, but this also means there might be a perceptible delay when adding/removing temporary exceptions. At this point I consider this an acceptable side-effect just to bring the ability to easily create temporary exception for network filters, while this simplified the existing temporary exception code throughout. --- platform/common/vapi-background.js | 3 + src/css/logger-ui.css | 3 + src/js/background.js | 3 + src/js/cosmetic-filtering.js | 30 +------- src/js/html-filtering.js | 20 +----- src/js/httpheader-filtering.js | 20 +----- src/js/logger-ui.js | 32 ++++----- src/js/logger.js | 20 +++--- src/js/messaging.js | 59 +++++---------- src/js/scriptlet-filtering.js | 20 +----- src/js/static-ext-filtering-db.js | 47 ------------ src/js/static-ext-filtering.js | 13 ---- src/js/storage.js | 112 +++++++++++++++++++---------- 13 files changed, 127 insertions(+), 255 deletions(-) diff --git a/platform/common/vapi-background.js b/platform/common/vapi-background.js index 20e8e29e0..6e3aa86c5 100644 --- a/platform/common/vapi-background.js +++ b/platform/common/vapi-background.js @@ -919,6 +919,9 @@ vAPI.messaging = { this.onPortDisconnect(port); } } + if ( this.defaultHandler ) { + this.defaultHandler(message, null, ( ) => { }); + } }, onFrameworkMessage: function(request, port, callback) { diff --git a/src/css/logger-ui.css b/src/css/logger-ui.css index 44c8bffe4..ec1712065 100644 --- a/src/css/logger-ui.css +++ b/src/css/logger-ui.css @@ -678,6 +678,9 @@ body[dir="rtl"] #netFilteringDialog > .panes > .details > div > span:nth-of-type background-color: rgb(var(--primary-50) / 50%); } #netFilteringDialog > .panes > .details .exceptor::before { + content: '@@'; + } +#netFilteringDialog.extendedRealm > .panes > .details .exceptor::before { content: '#@#'; } #netFilteringDialog > div.panes > .dynamic > .toolbar { diff --git a/src/js/background.js b/src/js/background.js index a381fac6c..b91a2fb69 100644 --- a/src/js/background.js +++ b/src/js/background.js @@ -211,6 +211,9 @@ const µBlock = { // jshint ignore:line availableFilterLists: {}, badLists: new Map(), + inMemoryFilters: [], + inMemoryFiltersCompiled: '', + // https://github.com/uBlockOrigin/uBlock-issues/issues/974 // This can be used to defer filtering decision-making. readyToFilter: false, diff --git a/src/js/cosmetic-filtering.js b/src/js/cosmetic-filtering.js index d473371db..c4dfd3992 100644 --- a/src/js/cosmetic-filtering.js +++ b/src/js/cosmetic-filtering.js @@ -27,10 +27,7 @@ import './utils.js'; import logger from './logger.js'; import µb from './background.js'; -import { - StaticExtFilteringHostnameDB, - StaticExtFilteringSessionDB, -} from './static-ext-filtering-db.js'; +import { StaticExtFilteringHostnameDB } from './static-ext-filtering-db.js'; /******************************************************************************/ /******************************************************************************/ @@ -236,10 +233,7 @@ const FilterContainer = function() { // specific filters this.specificFilters = new StaticExtFilteringHostnameDB(2); - // temporary filters - this.sessionFilterDB = new StaticExtFilteringSessionDB(); - - // low generic cosmetic filters: map of hash => array of selectors + // low generic cosmetic filters: map of hash => stringified selector list this.lowlyGeneric = new Map(); // highly generic selectors sets @@ -478,15 +472,6 @@ FilterContainer.prototype.compileSpecificSelector = function( /******************************************************************************/ -FilterContainer.prototype.compileTemporary = function(parser) { - return { - session: this.sessionFilterDB, - selector: parser.result.compiled, - }; -}; - -/******************************************************************************/ - FilterContainer.prototype.fromCompiledContent = function(reader, options) { if ( options.skipCosmetic ) { this.skipCompiledContent(reader, 'SPECIFIC'); @@ -697,12 +682,6 @@ FilterContainer.prototype.disableSurveyor = function(details) { /******************************************************************************/ -FilterContainer.prototype.getSession = function() { - return this.sessionFilterDB; -}; - -/******************************************************************************/ - FilterContainer.prototype.cssRuleFromProcedural = function(json) { const pfilter = JSON.parse(json); if ( pfilter.cssable !== true ) { return; } @@ -831,11 +810,6 @@ FilterContainer.prototype.retrieveSpecificSelectors = function( } } - // Retrieve temporary filters - if ( this.sessionFilterDB.isNotEmpty ) { - this.sessionFilterDB.retrieve([ null, exceptionSet ]); - } - // Retrieve filters with a non-empty hostname this.specificFilters.retrieve( hostname, diff --git a/src/js/html-filtering.js b/src/js/html-filtering.js index c9dc8a8f0..9867d1842 100644 --- a/src/js/html-filtering.js +++ b/src/js/html-filtering.js @@ -27,10 +27,7 @@ import logger from './logger.js'; import µb from './background.js'; import { sessionFirewall } from './filtering-engines.js'; -import { - StaticExtFilteringHostnameDB, - StaticExtFilteringSessionDB, -} from './static-ext-filtering-db.js'; +import { StaticExtFilteringHostnameDB } from './static-ext-filtering-db.js'; /******************************************************************************/ @@ -38,7 +35,6 @@ const pselectors = new Map(); const duplicates = new Set(); const filterDB = new StaticExtFilteringHostnameDB(2); -const sessionFilterDB = new StaticExtFilteringSessionDB(); let acceptedCount = 0; let discardedCount = 0; @@ -347,13 +343,6 @@ htmlFilteringEngine.compile = function(parser, writer) { } }; -htmlFilteringEngine.compileTemporary = function(parser) { - return { - session: sessionFilterDB, - selector: parser.result.compiled, - }; -}; - htmlFilteringEngine.fromCompiledContent = function(reader) { // Don't bother loading filters if stream filtering is not supported. if ( µb.canFilterResponseData === false ) { return; } @@ -373,10 +362,6 @@ htmlFilteringEngine.fromCompiledContent = function(reader) { } }; -htmlFilteringEngine.getSession = function() { - return sessionFilterDB; -}; - htmlFilteringEngine.retrieve = function(details) { const hostname = details.hostname; @@ -384,9 +369,6 @@ htmlFilteringEngine.retrieve = function(details) { const procedurals = new Set(); const exceptions = new Set(); - if ( sessionFilterDB.isNotEmpty ) { - sessionFilterDB.retrieve([ null, exceptions ]); - } filterDB.retrieve( hostname, [ plains, exceptions, procedurals, exceptions ] diff --git a/src/js/httpheader-filtering.js b/src/js/httpheader-filtering.js index c959e565e..53d10217e 100644 --- a/src/js/httpheader-filtering.js +++ b/src/js/httpheader-filtering.js @@ -28,16 +28,12 @@ import µb from './background.js'; import { entityFromDomain } from './uri-utils.js'; import { sessionFirewall } from './filtering-engines.js'; -import { - StaticExtFilteringHostnameDB, - StaticExtFilteringSessionDB, -} from './static-ext-filtering-db.js'; +import { StaticExtFilteringHostnameDB } from './static-ext-filtering-db.js'; /******************************************************************************/ const duplicates = new Set(); const filterDB = new StaticExtFilteringHostnameDB(1); -const sessionFilterDB = new StaticExtFilteringSessionDB(); const $headers = new Set(); const $exceptions = new Set(); @@ -123,13 +119,6 @@ httpheaderFilteringEngine.compile = function(parser, writer) { } }; -httpheaderFilteringEngine.compileTemporary = function(parser) { - return { - session: sessionFilterDB, - selector: parser.result.compiled.slice(15, -1), - }; -}; - // 01234567890123456789 // responseheader(name) // ^ ^ @@ -152,10 +141,6 @@ httpheaderFilteringEngine.fromCompiledContent = function(reader) { } }; -httpheaderFilteringEngine.getSession = function() { - return sessionFilterDB; -}; - httpheaderFilteringEngine.apply = function(fctxt, headers) { if ( filterDB.size === 0 ) { return; } @@ -173,9 +158,6 @@ httpheaderFilteringEngine.apply = function(fctxt, headers) { $headers.clear(); $exceptions.clear(); - if ( sessionFilterDB.isNotEmpty ) { - sessionFilterDB.retrieve([ null, $exceptions ]); - } filterDB.retrieve(hostname, [ $headers, $exceptions ]); filterDB.retrieve(entity, [ $headers, $exceptions ], 1); if ( $headers.size === 0 ) { return; } diff --git a/src/js/logger-ui.js b/src/js/logger-ui.js index aa0feb127..87f2e1167 100644 --- a/src/js/logger-ui.js +++ b/src/js/logger-ui.js @@ -1246,9 +1246,13 @@ const reloadTab = function(ev) { // Toggle temporary exception filter if ( tcl.contains('exceptor') ) { ev.stopPropagation(); + const filter = filterFromTargetRow(); + const exceptedFilter = dom.cl.has(targetRow, 'extendedRealm') + ? `#@#${filter.replace(/^.*?#@?#/, '')}` + : `@@${filter.replace(/^@@/, '')}`; const status = await messaging.send('loggerUI', { - what: 'toggleTemporaryException', - filter: filterFromTargetRow(), + what: 'toggleInMemoryFilter', + filter: exceptedFilter, }); const row = target.closest('div'); dom.cl.toggle(row, 'exceptored', status); @@ -1477,26 +1481,16 @@ const reloadTab = function(ev) { const toSummaryPaneFilterNode = async function(receiver, filter) { receiver.children[1].textContent = filter; if ( filterAuthorMode !== true ) { return; } - const match = /#@?#/.exec(filter); - if ( match === null ) { return; } - const fragment = document.createDocumentFragment(); - const pos = match.index + match[0].length; - fragment.appendChild(document.createTextNode(filter.slice(0, pos))); - const selector = filter.slice(pos); - const span = document.createElement('span'); - span.className = 'filter'; - span.textContent = selector; - fragment.appendChild(span); + if ( dom.cl.has(targetRow, 'canLookup') === false ) { return; } + const exceptedFilter = dom.cl.has(targetRow, 'extendedRealm') + ? `#@#${filter.replace(/^.*?#@?#/, '')}` + : `@@${filter.replace(/^@@/, '')}`; const isTemporaryException = await messaging.send('loggerUI', { - what: 'hasTemporaryException', - filter, + what: 'hasInMemoryFilter', + filter: exceptedFilter, }); dom.cl.toggle(receiver, 'exceptored', isTemporaryException); - if ( match[0] === '##' || isTemporaryException ) { - receiver.children[2].style.visibility = ''; - } - receiver.children[1].textContent = ''; - receiver.children[1].appendChild(fragment); + receiver.children[2].style.visibility = ''; }; const fillSummaryPaneFilterList = async function(rows) { diff --git a/src/js/logger.js b/src/js/logger.js index 9abf6a588..9318621b2 100644 --- a/src/js/logger.js +++ b/src/js/logger.js @@ -32,19 +32,15 @@ let writePtr = 0; const logBufferObsoleteAfter = 30 * 1000; const janitor = ( ) => { - if ( - buffer !== null && - lastReadTime < (Date.now() - logBufferObsoleteAfter) - ) { - logger.enabled = false; - buffer = null; - writePtr = 0; - logger.ownerId = undefined; - vAPI.messaging.broadcast({ what: 'loggerDisabled' }); - } - if ( buffer !== null ) { - vAPI.setTimeout(janitor, logBufferObsoleteAfter); + if ( buffer === null ) { return; } + if ( lastReadTime >= (Date.now() - logBufferObsoleteAfter) ) { + return vAPI.setTimeout(janitor, logBufferObsoleteAfter); } + logger.enabled = false; + buffer = null; + writePtr = 0; + logger.ownerId = undefined; + vAPI.messaging.broadcast({ what: 'loggerDisabled' }); }; const boxEntry = function(details) { diff --git a/src/js/messaging.js b/src/js/messaging.js index 1fd1c511e..bdc90ddd9 100644 --- a/src/js/messaging.js +++ b/src/js/messaging.js @@ -35,7 +35,6 @@ import logger from './logger.js'; import lz4Codec from './lz4.js'; import io from './assets.js'; import scriptletFilteringEngine from './scriptlet-filtering.js'; -import staticExtFilteringEngine from './static-ext-filtering.js'; import staticFilteringReverseLookup from './reverselookup.js'; import staticNetFilteringEngine from './static-net-filtering.js'; import µb from './background.js'; @@ -305,6 +304,10 @@ const onMessage = function(request, sender, callback) { µb.elementPickerExec(request.tabId, 0, request.targetURL, request.zap); break; + case 'loggerDisabled': + µb.clearInMemoryFilters(); + break; + case 'gotoURL': µb.openNewTab(request.details); break; @@ -1680,42 +1683,11 @@ const getURLFilteringData = function(details) { return response; }; -const compileTemporaryException = function(filter) { - const parser = new StaticFilteringParser({ - nativeCssHas: vAPI.webextFlavor.env.includes('native_css_has'), - }); - parser.analyze(filter); - if ( parser.shouldDiscard() ) { return; } - return staticExtFilteringEngine.compileTemporary(parser); -}; - -const toggleTemporaryException = function(details) { - const result = compileTemporaryException(details.filter); - if ( result === undefined ) { return false; } - const { session, selector } = result; - if ( session.has(1, selector) ) { - session.remove(1, selector); - return false; - } - session.add(1, selector); - return true; -}; - -const hasTemporaryException = function(details) { - const result = compileTemporaryException(details.filter); - if ( result === undefined ) { return false; } - const { session, selector } = result; - return session && session.has(1, selector); -}; - const onMessage = function(request, sender, callback) { // Async switch ( request.what ) { case 'readAll': - if ( - logger.ownerId !== undefined && - logger.ownerId !== request.ownerId - ) { + if ( logger.ownerId !== undefined && logger.ownerId !== request.ownerId ) { return callback({ unavailable: true }); } vAPI.tabs.getCurrent().then(tab => { @@ -1723,6 +1695,13 @@ const onMessage = function(request, sender, callback) { }); return; + case 'toggleInMemoryFilter': { + const promise = µb.hasInMemoryFilter(request.filter) + ? µb.removeInMemoryFilter(request.filter) + : µb.addInMemoryFilter(request.filter); + promise.then(status => { callback(status); }); + return; + } default: break; } @@ -1731,14 +1710,14 @@ const onMessage = function(request, sender, callback) { let response; switch ( request.what ) { - case 'hasTemporaryException': - response = hasTemporaryException(request); + case 'hasInMemoryFilter': + response = µb.hasInMemoryFilter(request.filter); break; case 'releaseView': - if ( request.ownerId === logger.ownerId ) { - logger.ownerId = undefined; - } + if ( request.ownerId !== logger.ownerId ) { break; } + logger.ownerId = undefined; + µb.clearInMemoryFilters(); break; case 'saveURLFilteringRules': @@ -1761,10 +1740,6 @@ const onMessage = function(request, sender, callback) { response = getURLFilteringData(request); break; - case 'toggleTemporaryException': - response = toggleTemporaryException(request); - break; - default: return vAPI.messaging.UNHANDLED; } diff --git a/src/js/scriptlet-filtering.js b/src/js/scriptlet-filtering.js index 6a8e7178e..b8a2c8f36 100644 --- a/src/js/scriptlet-filtering.js +++ b/src/js/scriptlet-filtering.js @@ -28,10 +28,7 @@ import µb from './background.js'; import { redirectEngine } from './redirect-engine.js'; import { sessionFirewall } from './filtering-engines.js'; -import { - StaticExtFilteringHostnameDB, - StaticExtFilteringSessionDB, -} from './static-ext-filtering-db.js'; +import { StaticExtFilteringHostnameDB } from './static-ext-filtering-db.js'; import { domainFromHostname, @@ -46,7 +43,6 @@ const scriptletCache = new µb.MRUCache(32); const reEscapeScriptArg = /[\\'"]/g; const scriptletDB = new StaticExtFilteringHostnameDB(1); -const sessionScriptletDB = new StaticExtFilteringSessionDB(); let acceptedCount = 0; let discardedCount = 0; @@ -262,13 +258,6 @@ scriptletFilteringEngine.compile = function(parser, writer) { } }; -scriptletFilteringEngine.compileTemporary = function(parser) { - return { - session: sessionScriptletDB, - selector: parser.result.compiled, - }; -}; - // 01234567890123456789 // +js(token[, arg[, ...]]) // ^ ^ @@ -291,10 +280,6 @@ scriptletFilteringEngine.fromCompiledContent = function(reader) { } }; -scriptletFilteringEngine.getSession = function() { - return sessionScriptletDB; -}; - const $scriptlets = new Set(); const $exceptions = new Set(); const $scriptletToCodeMap = new Map(); @@ -307,9 +292,6 @@ scriptletFilteringEngine.retrieve = function(request, options = {}) { $scriptlets.clear(); $exceptions.clear(); - if ( sessionScriptletDB.isNotEmpty ) { - sessionScriptletDB.retrieve([ null, $exceptions ]); - } scriptletDB.retrieve(hostname, [ $scriptlets, $exceptions ]); const entity = request.entity !== '' ? `${hostname.slice(0, -request.domain.length)}${request.entity}` diff --git a/src/js/static-ext-filtering-db.js b/src/js/static-ext-filtering-db.js index a118485b6..8669e4e9e 100644 --- a/src/js/static-ext-filtering-db.js +++ b/src/js/static-ext-filtering-db.js @@ -170,55 +170,8 @@ const StaticExtFilteringHostnameDB = class { /******************************************************************************/ -const StaticExtFilteringSessionDB = class { - constructor() { - this.db = new Map(); - } - compile(s) { - return s; - } - add(bits, s) { - const bucket = this.db.get(bits); - if ( bucket === undefined ) { - this.db.set(bits, new Set([ s ])); - } else { - bucket.add(s); - } - } - remove(bits, s) { - const bucket = this.db.get(bits); - if ( bucket === undefined ) { return; } - bucket.delete(s); - if ( bucket.size !== 0 ) { return; } - this.db.delete(bits); - } - retrieve(out) { - const mask = out.length - 1; - for ( const [ bits, bucket ] of this.db ) { - const i = bits & mask; - if ( out[i] instanceof Object === false ) { continue; } - for ( const s of bucket ) { - out[i].add(s); - } - } - } - has(bits, s) { - const selectors = this.db.get(bits); - return selectors !== undefined && selectors.has(s); - } - clear() { - this.db.clear(); - } - get isNotEmpty() { - return this.db.size !== 0; - } -}; - -/******************************************************************************/ - export { StaticExtFilteringHostnameDB, - StaticExtFilteringSessionDB, }; /******************************************************************************/ diff --git a/src/js/static-ext-filtering.js b/src/js/static-ext-filtering.js index d6bc851b2..4c776cfda 100644 --- a/src/js/static-ext-filtering.js +++ b/src/js/static-ext-filtering.js @@ -132,19 +132,6 @@ staticExtFilteringEngine.compile = function(parser, writer) { return true; }; -staticExtFilteringEngine.compileTemporary = function(parser) { - if ( (parser.flavorBits & parser.BITFlavorExtScriptlet) !== 0 ) { - return scriptletFilteringEngine.compileTemporary(parser); - } - if ( (parser.flavorBits & parser.BITFlavorExtResponseHeader) !== 0 ) { - return httpheaderFilteringEngine.compileTemporary(parser); - } - if ( (parser.flavorBits & parser.BITFlavorExtHTML) !== 0 ) { - return htmlFilteringEngine.compileTemporary(parser); - } - return cosmeticFilteringEngine.compileTemporary(parser); -}; - staticExtFilteringEngine.fromCompiledContent = function(reader, options) { cosmeticFilteringEngine.fromCompiledContent(reader, options); scriptletFilteringEngine.fromCompiledContent(reader, options); diff --git a/src/js/storage.js b/src/js/storage.js index 9682e4d68..47c9339ce 100644 --- a/src/js/storage.js +++ b/src/js/storage.js @@ -618,6 +618,36 @@ self.addEventListener('hiddenSettingsChanged', ( ) => { /******************************************************************************/ +µb.hasInMemoryFilter = function(raw) { + return this.inMemoryFilters.includes(raw); +}; + +µb.addInMemoryFilter = async function(raw) { + if ( this.inMemoryFilters.includes(raw) ){ return true; } + this.inMemoryFilters.push(raw); + this.inMemoryFiltersCompiled = ''; + await this.loadFilterLists(); + return true; +}; + +µb.removeInMemoryFilter = async function(raw) { + const pos = this.inMemoryFilters.indexOf(raw); + if ( pos === -1 ) { return false; } + this.inMemoryFilters.splice(pos, 1); + this.inMemoryFiltersCompiled = ''; + await this.loadFilterLists(); + return false; +}; + +µb.clearInMemoryFilters = async function() { + if ( this.inMemoryFilters.length === 0 ) { return; } + this.inMemoryFilters = []; + this.inMemoryFiltersCompiled = ''; + await this.loadFilterLists(); +}; + +/******************************************************************************/ + µb.getAvailableLists = async function() { let oldAvailableLists = {}, newAvailableLists = {}; @@ -760,12 +790,12 @@ self.addEventListener('hiddenSettingsChanged', ( ) => { /******************************************************************************/ -µb.loadFilterLists = (( ) => { +{ const loadedListKeys = []; let loadingPromise; let t0 = 0; - const onDone = function() { + const onDone = ( ) => { ubolog(`loadFilterLists() took ${Date.now()-t0} ms`); staticNetFilteringEngine.freeze(); @@ -773,30 +803,30 @@ self.addEventListener('hiddenSettingsChanged', ( ) => { redirectEngine.freeze(); vAPI.net.unsuspend(); - vAPI.storage.set({ 'availableFilterLists': this.availableFilterLists }); + vAPI.storage.set({ 'availableFilterLists': µb.availableFilterLists }); vAPI.messaging.broadcast({ what: 'staticFilteringDataChanged', - parseCosmeticFilters: this.userSettings.parseAllABPHideFilters, - ignoreGenericCosmeticFilters: this.userSettings.ignoreGenericCosmeticFilters, + parseCosmeticFilters: µb.userSettings.parseAllABPHideFilters, + ignoreGenericCosmeticFilters: µb.userSettings.ignoreGenericCosmeticFilters, listKeys: loadedListKeys }); - this.selfieManager.destroy(); + µb.selfieManager.destroy(); lz4Codec.relinquish(); - this.compiledFormatChanged = false; + µb.compiledFormatChanged = false; loadingPromise = undefined; }; - const applyCompiledFilters = function(assetKey, compiled) { + const applyCompiledFilters = (assetKey, compiled) => { const snfe = staticNetFilteringEngine; const sxfe = staticExtFilteringEngine; - let acceptedCount = snfe.acceptedCount + sxfe.acceptedCount, - discardedCount = snfe.discardedCount + sxfe.discardedCount; - this.applyCompiledFilters(compiled, assetKey === this.userFiltersPath); - if ( this.availableFilterLists.hasOwnProperty(assetKey) ) { - const entry = this.availableFilterLists[assetKey]; + let acceptedCount = snfe.acceptedCount + sxfe.acceptedCount; + let discardedCount = snfe.discardedCount + sxfe.discardedCount; + µb.applyCompiledFilters(compiled, assetKey === µb.userFiltersPath); + if ( µb.availableFilterLists.hasOwnProperty(assetKey) ) { + const entry = µb.availableFilterLists[assetKey]; entry.entryCount = snfe.acceptedCount + sxfe.acceptedCount - acceptedCount; entry.entryUsedCount = entry.entryCount - @@ -805,8 +835,8 @@ self.addEventListener('hiddenSettingsChanged', ( ) => { loadedListKeys.push(assetKey); }; - const onFilterListsReady = function(lists) { - this.availableFilterLists = lists; + const onFilterListsReady = lists => { + µb.availableFilterLists = lists; if ( vAPI.Net.canSuspend() ) { vAPI.net.suspend(); @@ -814,7 +844,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => { redirectEngine.reset(); staticExtFilteringEngine.reset(); staticNetFilteringEngine.reset(); - this.selfieManager.destroy(); + µb.selfieManager.destroy(); staticFilteringReverseLookup.resetLists(); // We need to build a complete list of assets to pull first: this is @@ -825,37 +855,44 @@ self.addEventListener('hiddenSettingsChanged', ( ) => { for ( const assetKey in lists ) { if ( lists.hasOwnProperty(assetKey) === false ) { continue; } if ( lists[assetKey].off ) { continue; } - toLoad.push( - this.getCompiledFilterList(assetKey).then(details => { - applyCompiledFilters.call( - this, - details.assetKey, - details.content - ); + µb.getCompiledFilterList(assetKey).then(details => { + applyCompiledFilters(details.assetKey, details.content); }) ); } + if ( µb.inMemoryFilters.length !== 0 ) { + if ( µb.inMemoryFiltersCompiled === '' ) { + µb.inMemoryFiltersCompiled = + µb.compileFilters( + µb.inMemoryFilters.join('\n'), + { assetKey: 'in-memory'} + ); + } + if ( µb.inMemoryFiltersCompiled !== '' ) { + toLoad.push( + µb.applyCompiledFilters(µb.inMemoryFiltersCompiled, true) + ); + } + } + return Promise.all(toLoad); }; - return function() { - if ( loadingPromise instanceof Promise === false ) { - t0 = Date.now(); - loadedListKeys.length = 0; - loadingPromise = Promise.all([ - this.getAvailableLists().then(lists => - onFilterListsReady.call(this, lists) - ), - this.loadRedirectResources(), - ]).then(( ) => { - onDone.call(this); - }); - } + µb.loadFilterLists = function() { + if ( loadingPromise instanceof Promise ) { return loadingPromise; } + t0 = Date.now(); + loadedListKeys.length = 0; + loadingPromise = Promise.all([ + this.getAvailableLists().then(lists => onFilterListsReady(lists)), + this.loadRedirectResources(), + ]).then(( ) => { + onDone(); + }); return loadingPromise; }; -})(); +} /******************************************************************************/ @@ -1158,6 +1195,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => { // memory usage at selfie-load time. For some reasons. const create = async function() { + if ( µb.inMemoryFilters.length !== 0 ) { return; } await Promise.all([ io.put( 'selfie/main',