Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: lib/filterStorage.js

Issue 29912619: Issue 6891, 6741 - Rename FilterStorage to filterStorage (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Patch Set: Minor update Created Oct. 16, 2018, 10:02 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/filterListener.js ('k') | lib/synchronizer.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/filterStorage.js
===================================================================
--- a/lib/filterStorage.js
+++ b/lib/filterStorage.js
@@ -13,224 +13,250 @@
*
* You should have received a copy of the GNU General Public License
* along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
*/
"use strict";
/**
- * @fileOverview FilterStorage class responsible for managing user's
- * subscriptions and filters.
+ * @fileOverview <code>filterStorage</code> object responsible for managing the
+ * user's subscriptions and filters.
*/
const {IO} = require("io");
const {Prefs} = require("prefs");
const {Filter, ActiveFilter} = require("./filterClasses");
const {Subscription, SpecialSubscription,
ExternalSubscription} = require("./subscriptionClasses");
const {filterNotifier} = require("./filterNotifier");
const {INIParser} = require("./iniParser");
/**
* Version number of the filter storage file format.
* @type {number}
*/
-let formatVersion = 5;
+const FORMAT_VERSION = 5;
/**
- * This class reads user's filters from disk, manages them in memory
- * and writes them back.
- * @class
+ * {@link filterStorage} implementation.
*/
-let FilterStorage = exports.FilterStorage =
+class FilterStorage
{
/**
- * Will be set to true after the initial loadFromDisk() call completes.
- * @type {boolean}
+ * @hideconstructor
*/
- initialized: false,
+ constructor()
+ {
+ /**
+ * Will be set to true after the initial {@link FilterStorage#loadFromDisk}
+ * call completes.
+ * @type {boolean}
+ */
+ this.initialized = false;
+
+ /**
+ * Will be set to <code>true</code> if no <code>patterns.ini</code> file
+ * exists.
+ * @type {boolean}
+ */
+ this.firstRun = false;
+
+ /**
+ * Map of properties listed in the filter storage file before the sections
+ * start. Right now this should be only the format version.
+ * @type {object}
+ */
+ this.fileProperties = Object.create(null);
+
+ /**
+ * Map of subscriptions already on the list, by their URL/identifier.
+ * @type {Map.<string,Subscription>}
+ */
+ this.knownSubscriptions = new Map();
+
+ /**
+ * Will be set to true if {@link FilterStorage#saveToDisk} is running
+ * (reentrance protection).
+ * @type {boolean}
+ * @private
+ */
+ this._saving = false;
+
+ /**
+ * Will be set to true if a {@link FilterStorage#saveToDisk} call arrives
+ * while {@link FilterStorage#saveToDisk} is already running (delayed
+ * execution).
+ * @type {boolean}
+ * @private
+ */
+ this._needsSave = false;
+ }
/**
- * Version number of the patterns.ini format used.
+ * The version number of the <code>patterns.ini</code> format used.
* @type {number}
*/
get formatVersion()
{
- return formatVersion;
- },
+ return FORMAT_VERSION;
+ }
/**
- * File containing the filter list
+ * The file containing the subscriptions.
* @type {string}
*/
get sourceFile()
{
return "patterns.ini";
- },
+ }
/**
- * Will be set to true if no patterns.ini file exists.
- * @type {boolean}
- */
- firstRun: false,
-
- /**
- * Map of properties listed in the filter storage file before the sections
- * start. Right now this should be only the format version.
- */
- fileProperties: Object.create(null),
-
- /**
- * Yields subscriptions containing all filters
+ * Yields all subscriptions in the storage.
* @yields {Subscription}
*/
*subscriptions()
{
yield* this.knownSubscriptions.values();
- },
+ }
/**
- * Number of known subscriptions.
+ * The number of subscriptions in the storage.
* @type {number}
*/
get subscriptionCount()
{
return this.knownSubscriptions.size;
- },
-
- /**
- * Map of subscriptions already on the list, by their URL/identifier
- * @type {Map.<string,Subscription>}
- */
- knownSubscriptions: new Map(),
+ }
/**
* Finds the filter group that a filter should be added to by default. Will
- * return null if this group doesn't exist yet.
+ * return <code>null</code> if this group doesn't exist yet.
* @param {Filter} filter
- * @return {?SpecialSubscription}
+ * @returns {?SpecialSubscription}
*/
getGroupForFilter(filter)
{
let generalSubscription = null;
- for (let subscription of FilterStorage.knownSubscriptions.values())
+ for (let subscription of this.knownSubscriptions.values())
{
if (subscription instanceof SpecialSubscription && !subscription.disabled)
{
// Always prefer specialized subscriptions
if (subscription.isDefaultFor(filter))
return subscription;
// If this is a general subscription - store it as fallback
if (!generalSubscription &&
(!subscription.defaults || !subscription.defaults.length))
{
generalSubscription = subscription;
}
}
}
return generalSubscription;
- },
+ }
/**
- * Adds a filter subscription to the list
- * @param {Subscription} subscription filter subscription to be added
+ * Adds a subscription to the storage.
+ * @param {Subscription} subscription The subscription to be added.
*/
addSubscription(subscription)
{
- if (FilterStorage.knownSubscriptions.has(subscription.url))
+ if (this.knownSubscriptions.has(subscription.url))
return;
- FilterStorage.knownSubscriptions.set(subscription.url, subscription);
- addSubscriptionFilters(subscription);
+ this.knownSubscriptions.set(subscription.url, subscription);
+ connectSubscriptionFilters(subscription);
filterNotifier.emit("subscription.added", subscription);
- },
+ }
/**
- * Removes a filter subscription from the list
- * @param {Subscription} subscription filter subscription to be removed
+ * Removes a subscription from the storage.
+ * @param {Subscription} subscription The subscription to be removed.
*/
removeSubscription(subscription)
{
- if (!FilterStorage.knownSubscriptions.has(subscription.url))
+ if (!this.knownSubscriptions.has(subscription.url))
return;
- removeSubscriptionFilters(subscription);
+ disconnectSubscriptionFilters(subscription);
- FilterStorage.knownSubscriptions.delete(subscription.url);
+ this.knownSubscriptions.delete(subscription.url);
// This should be the last remaining reference to the Subscription
// object.
Subscription.knownSubscriptions.delete(subscription.url);
filterNotifier.emit("subscription.removed", subscription);
- },
+ }
/**
- * Replaces the list of filters in a subscription by a new list
- * @param {Subscription} subscription filter subscription to be updated
- * @param {Filter[]} filters new filter list
+ * Replaces the list of filters in a subscription with a new list.
+ * @param {Subscription} subscription The subscription to be updated.
+ * @param {Array.<Filter>} filters The new list of filters.
*/
updateSubscriptionFilters(subscription, filters)
{
- removeSubscriptionFilters(subscription);
+ disconnectSubscriptionFilters(subscription);
let oldFilters = subscription.filters;
subscription.filters = filters;
- addSubscriptionFilters(subscription);
+ connectSubscriptionFilters(subscription);
filterNotifier.emit("subscription.updated", subscription, oldFilters);
- },
+ }
/**
- * Adds a user-defined filter to the list
+ * Adds a user-defined filter to the storage.
* @param {Filter} filter
- * @param {SpecialSubscription} [subscription]
- * particular group that the filter should be added to
- * @param {number} [position]
- * position within the subscription at which the filter should be added
+ * @param {?SpecialSubscription} [subscription] The subscription that the
+ * filter should be added to.
+ * @param {number} [position] The position within the subscription at which
+ * the filter should be added. If not specified, the filter is added at the
+ * end of the subscription.
*/
addFilter(filter, subscription, position)
{
if (!subscription)
{
for (let currentSubscription of filter.subscriptions())
{
if (currentSubscription instanceof SpecialSubscription &&
!currentSubscription.disabled)
{
return; // No need to add
}
}
- subscription = FilterStorage.getGroupForFilter(filter);
+ subscription = this.getGroupForFilter(filter);
}
if (!subscription)
{
// No group for this filter exists, create one
subscription = SpecialSubscription.createForFilter(filter);
this.addSubscription(subscription);
return;
}
if (typeof position == "undefined")
position = subscription.filters.length;
filter.addSubscription(subscription);
subscription.filters.splice(position, 0, filter);
filterNotifier.emit("filter.added", filter, subscription, position);
- },
+ }
/**
- * Removes a user-defined filter from the list
+ * Removes a user-defined filter from the storage.
* @param {Filter} filter
- * @param {SpecialSubscription} [subscription] a particular filter group that
- * the filter should be removed from (if ommited will be removed from all
- * subscriptions)
- * @param {number} [position] position inside the filter group at which the
- * filter should be removed (if ommited all instances will be removed)
+ * @param {?SpecialSubscription} [subscription] The subscription that the
+ * filter should be removed from. If not specified, the filter will be
+ * removed from all subscriptions.
+ * @param {number} [position] The position within the subscription at which
+ * the filter should be removed. If not specified, all instances of the
+ * filter will be removed.
*/
removeFilter(filter, subscription, position)
{
let subscriptions = (
subscription ? [subscription] : filter.subscriptions()
);
for (let currentSubscription of subscriptions)
{
@@ -259,25 +285,25 @@
if (currentSubscription.filters.indexOf(filter) < 0)
filter.removeSubscription(currentSubscription);
filterNotifier.emit("filter.removed", filter, currentSubscription,
currentPosition);
}
}
}
}
- },
+ }
/**
- * Moves a user-defined filter to a new position
+ * Moves a user-defined filter to a new position.
* @param {Filter} filter
- * @param {SpecialSubscription} subscription filter group where the filter is
- * located
- * @param {number} oldPosition current position of the filter
- * @param {number} newPosition new position of the filter
+ * @param {SpecialSubscription} subscription The subscription where the
+ * filter is located.
+ * @param {number} oldPosition The current position of the filter.
+ * @param {number} newPosition The new position of the filter.
*/
moveFilter(filter, subscription, oldPosition, newPosition)
{
if (!(subscription instanceof SpecialSubscription) ||
subscription.filters[oldPosition] != filter)
{
return;
}
@@ -286,61 +312,60 @@
subscription.filters.length - 1);
if (oldPosition == newPosition)
return;
subscription.filters.splice(oldPosition, 1);
subscription.filters.splice(newPosition, 0, filter);
filterNotifier.emit("filter.moved", filter, subscription, oldPosition,
newPosition);
- },
+ }
/**
- * Increases the hit count for a filter by one
+ * Increases the hit count for a filter by one.
* @param {Filter} filter
*/
increaseHitCount(filter)
{
if (!Prefs.savestats || !(filter instanceof ActiveFilter))
return;
filter.hitCount++;
filter.lastHit = Date.now();
- },
+ }
/**
- * Resets hit count for some filters
- * @param {Filter[]} filters filters to be reset, if null all filters will
- * be reset
+ * Resets hit count for some filters.
+ * @param {?Array.<Filter>} [filters] The filters to be reset. If not
+ * specified, all filters will be reset.
*/
resetHitCounts(filters)
{
if (!filters)
filters = Filter.knownFilters.values();
for (let filter of filters)
{
filter.hitCount = 0;
filter.lastHit = 0;
}
- },
+ }
/**
* @callback TextSink
* @param {string?} line
*/
/**
* Allows importing previously serialized filter data.
- * @param {boolean} silent
- * If true, no "load" notification will be sent out.
- * @return {TextSink}
- * Function to be called for each line of data. Calling it with null as
- * parameter finalizes the import and replaces existing data. No changes
- * will be applied before finalization, so import can be "aborted" by
- * forgetting this callback.
+ * @param {boolean} silent If <code>true</code>, no "load" notification will
+ * be sent out.
+ * @returns {TextSink} The function to be called for each line of data.
+ * Calling it with <code>null</code> as the argument finalizes the import
+ * and replaces existing data. No changes will be applied before
+ * finalization, so import can be "aborted" by forgetting this callback.
*/
importData(silent)
{
let parser = new INIParser();
return line =>
{
parser.process(line);
if (line === null)
@@ -353,21 +378,21 @@
this.knownSubscriptions = knownSubscriptions;
Filter.knownFilters = parser.knownFilters;
Subscription.knownSubscriptions = parser.knownSubscriptions;
if (!silent)
filterNotifier.emit("load");
}
};
- },
+ }
/**
- * Loads all subscriptions from the disk.
- * @return {Promise} promise resolved or rejected when loading is complete
+ * Loads all subscriptions from disk.
+ * @returns {Promise} A promise resolved or rejected when loading is complete.
*/
loadFromDisk()
{
let tryBackup = backupIndex =>
{
return this.restoreBackup(backupIndex, true).then(() =>
{
if (this.knownSubscriptions.size == 0)
@@ -400,68 +425,70 @@
{
Cu.reportError(error);
return tryBackup(1);
}).then(() =>
{
this.initialized = true;
filterNotifier.emit("load");
});
- },
+ }
/**
- * Constructs the file name for a patterns.ini backup.
- * @param {number} backupIndex
- * number of the backup file (1 being the most recent)
- * @return {string} backup file name
+ * Constructs the file name for a <code>patterns.ini</code> backup.
+ * @param {number} backupIndex Number of the backup file (1 being the most
+ * recent).
+ * @returns {string} Backup file name.
*/
getBackupName(backupIndex)
{
let [name, extension] = this.sourceFile.split(".", 2);
return (name + "-backup" + backupIndex + "." + extension);
- },
+ }
/**
* Restores an automatically created backup.
- * @param {number} backupIndex
- * number of the backup to restore (1 being the most recent)
- * @param {boolean} silent
- * If true, no "load" notification will be sent out.
- * @return {Promise} promise resolved or rejected when restoring is complete
+ * @param {number} backupIndex Number of the backup to restore (1 being the
+ * most recent).
+ * @param {boolean} silent If <code>true</code>, no "load" notification will
+ * be sent out.
+ * @returns {Promise} A promise resolved or rejected when restoration is
+ * complete.
*/
restoreBackup(backupIndex, silent)
{
let backupFile = this.getBackupName(backupIndex);
let parser = this.importData(silent);
return IO.readFromFile(backupFile, parser).then(() =>
{
parser(null);
return this.saveToDisk();
});
- },
+ }
/**
* Generator serializing filter data and yielding it line by line.
+ * @yields {string}
*/
*exportData()
{
// Do not persist external subscriptions
let subscriptions = [];
for (let subscription of this.subscriptions())
{
if (!(subscription instanceof ExternalSubscription) &&
!(subscription instanceof SpecialSubscription &&
subscription.filters.length == 0))
{
subscriptions.push(subscription);
}
}
yield "# Adblock Plus preferences";
- yield "version=" + formatVersion;
+ yield "version=" + this.formatVersion;
let saved = new Set();
let buf = [];
// Save subscriptions
for (let subscription of subscriptions)
{
yield "";
@@ -487,34 +514,21 @@
filter.serialize(buf);
saved.add(filter.text);
for (let line of buf)
yield line;
buf.splice(0);
}
}
}
- },
-
- /**
- * Will be set to true if saveToDisk() is running (reentrance protection).
- * @type {boolean}
- */
- _saving: false,
+ }
/**
- * Will be set to true if a saveToDisk() call arrives while saveToDisk() is
- * already running (delayed execution).
- * @type {boolean}
- */
- _needsSave: false,
-
- /**
- * Saves all subscriptions back to disk
- * @return {Promise} promise resolved or rejected when saving is complete
+ * Saves all subscriptions back to disk.
+ * @returns {Promise} A promise resolved or rejected when saving is complete.
*/
saveToDisk()
{
if (this._saving)
{
this._needsSave = true;
return;
}
@@ -588,28 +602,28 @@
{
this._saving = false;
if (this._needsSave)
{
this._needsSave = false;
this.saveToDisk();
}
});
- },
+ }
/**
* @typedef FileInfo
* @type {object}
* @property {number} index
* @property {number} lastModified
*/
/**
* Returns a promise resolving in a list of existing backup files.
- * @return {Promise.<FileInfo[]>}
+ * @returns {Promise.<Array.<FileInfo>>}
*/
getBackupFiles()
{
let backups = [];
let checkBackupFile = index =>
{
return IO.statFile(this.getBackupName(index)).then(statData =>
@@ -627,37 +641,45 @@
// Something went wrong, return whatever data we got so far.
Cu.reportError(error);
return backups;
});
};
return checkBackupFile(1);
}
-};
+}
/**
- * Joins subscription's filters to the subscription without any notifications.
- * @param {Subscription} subscription
- * filter subscription that should be connected to its filters
+ * Reads the user's filters from disk, manages them in memory, and writes them
+ * back to disk.
*/
-function addSubscriptionFilters(subscription)
+let filterStorage = new FilterStorage();
+
+exports.filterStorage = filterStorage;
+
+/**
+ * Connects a subscription to its filters without any notifications.
+ * @param {Subscription} subscription The subscription that should be
+ * connected to its filters.
+ */
+function connectSubscriptionFilters(subscription)
{
- if (!FilterStorage.knownSubscriptions.has(subscription.url))
+ if (!filterStorage.knownSubscriptions.has(subscription.url))
return;
for (let filter of subscription.filters)
filter.addSubscription(subscription);
}
/**
- * Removes subscription's filters from the subscription without any
- * notifications.
- * @param {Subscription} subscription filter subscription to be removed
+ * Disconnects a subscription from its filters without any notifications.
+ * @param {Subscription} subscription The subscription that should be
+ * disconnected from its filters.
*/
-function removeSubscriptionFilters(subscription)
+function disconnectSubscriptionFilters(subscription)
{
- if (!FilterStorage.knownSubscriptions.has(subscription.url))
+ if (!filterStorage.knownSubscriptions.has(subscription.url))
return;
for (let filter of subscription.filters)
filter.removeSubscription(subscription);
}
« no previous file with comments | « lib/filterListener.js ('k') | lib/synchronizer.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld