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

Unified Diff: lib/filterHits.js

Issue 6337686776315904: Issue 394 - hit statistics tool data collection (Closed)
Patch Set: subscriptions and thirdparty filter hit added to statistics Created April 9, 2014, 4:36 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 | « defaults/prefs.js ('k') | lib/filterListener.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/filterHits.js
===================================================================
new file mode 100644
--- /dev/null
+++ b/lib/filterHits.js
@@ -0,0 +1,242 @@
+/*
+ * This file is part of Adblock Plus <http://adblockplus.org/>,
+ * Copyright (C) 2006-2014 Eyeo GmbH
+ *
+ * Adblock Plus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Adblock Plus 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 Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+let {IO} = require("io");
+let {Utils} = require("utils");
+let {Prefs} = require("prefs");
+let {TimeLine} = require("timeline");
+let {Filter} = require("filterClasses");
+
+/**
+ * This class reads filter hits statistics from disk, manages them in memory and writes them back.W
+ * @class
+ */
+let FilterHits = exports.FilterHits =
+{
+ statistics: {},
+
+ _loading: false,
+ _saving: false,
+ _needsSave: false,
+
+ /**
+ * File that the filter hits statistics has been loaded from and should be saved to
+ * @type nsIFile
+ */
+ get filterHitsFile()
+ {
+ let file = null;
+ if (!file)
+ {
+ // Place the file in the data dir
+ file = IO.resolveFilePath(Prefs.data_directory);
+ if (file)
+ file.append("filter-hits.ini");
+ }
+ if (!file)
+ {
+ // Data directory pref misconfigured? Try the default value
+ try
+ {
+ file = IO.resolveFilePath(Services.prefs.getDefaultBranch("extensions.adblockplus.").getCharPref("data_directory"));
+ if (file)
+ file.append("filter-hits.ini");
+ } catch(e) {}
+ }
+
+ if (!file)
+ Cu.reportError("Adblock Plus: Failed to resolve filter-hits file");
+
+ this.__defineGetter__("filterHitsFile", function() file);
+ return this.filterHitsFile;
+ },
+
+ /**
+ * Increases the filter hit count by one
+ * @param {Filter} filter
+ * @param {Window} window Window that the match originated in (required to get host name)
+ */
+ increaseFilterHits: function(filter, wnd)
+ {
+ if (!filter.text)
+ return;
+
+ if (filter.text in this.statistics)
+ this.statistics[filter.text].statsHitCount++;
+ else
+ this.statistics[filter.text] = {statsHitCount:1, lastHit: 0, domainsCount:{},
+ thirdParty: false, subscriptions: []};
+
+ let increaseHits = function(filterStats)
+ {
+ if (filter.lastHit)
+ filterStats.lastHit = filter.lastHit;
+
+ if (filter.subscriptions)
+ {
+ for (let i = 0; i < filter.subscriptions.length; i++)
+ {
+ if (filterStats.subscriptions.indexOf(filter.subscriptions[i]._title) == -1)
+ filterStats.subscriptions.push(filter.subscriptions[i]._title);
+ }
+ }
+
+ if (filter.thirdParty)
+ filterStats.thirdParty = true;
+
+ // Get hostname from window object
+ let wndLocation = Utils.getOriginWindow(wnd).location.href;
+ let host = Utils.unwrapURL(wndLocation).host;
+
+ if (host in filterStats.domainsCount)
+ filterStats.domainsCount[host]++;
+ else
+ filterStats.domainsCount[host] = 1;
+ };
+
+ increaseHits(this.statistics[filter.text]);
+ },
+
+ /**
+ * send filter hits statistics to ABP sever and reset filter hits count
+ */
+ sendFilterHitsToServer: function()
+ {
+ //TODO implement ajax request to server sending this.statistics
+ //clear statics on 200 response
+ this.resetFilterHits();
+ this.saveFilterHitsToDisk();
+ },
+
+ /**
+ * Loads Filter hit statistics from the disk
+ */
+ loadFilterHitsFromDisk: function()
+ {
+ if (this._loading)
+ return;
+
+ let sourceFile = FilterHits.filterHitsFile;
+ if (!sourceFile)
+ return;
+
+ TimeLine.enter("Entered FilterHits.loadFilterHitsFromDisk()");
+ this._loading = true;
+
+ let readFile = function()
+ {
+ TimeLine.enter("FilterHits.loadFilterHitsFromDisk() -> readFile()");
+ let parser = new FilterHitsParser();
+ IO.readFromFile(sourceFile, true, parser, function(e)
+ {
+ TimeLine.enter("FilterHits.loadFilterHitsFromDisk() read callback");
+ if (e)
+ Cu.reportError(e);
+
+ doneReading(parser);
+ }.bind(this), "FilterHitsRead");
+
+ TimeLine.leave("FilterHits.loadFilterHitsFromDisk() <- readFile()", "FilterHitsRead");
+ }.bind(this);
+
+ var doneReading = function(parser)
+ {
+ FilterHits.statistics = parser.statistics;
+ this._loading = false;
+ TimeLine.leave("FilterHits.loadFilterHitsFromDisk() read callback done");
+ }.bind(this);
+
+ IO.statFile(sourceFile, function(e, statData)
+ {
+ if (!e && statData.exists)
+ readFile(sourceFile);
+ });
+ TimeLine.leave("FilterHits.loadFilterHitsFromDisk() done");
+ },
+
+ /**
+ * Stringify filter hits statistics object
+ */
+ _generateFilterHitData: function()
+ {
+ yield JSON.stringify(FilterHits.statistics);
+ },
+
+ /**
+ * Save Filters hit statistics to the disk
+ */
+ saveFilterHitsToDisk: function()
+ {
+ let targetFile = FilterHits.filterHitsFile;
+ if (!targetFile)
+ return;
+
+ if (this._saving)
+ {
+ this._needsSave = true;
+ return;
+ }
+ TimeLine.enter("Entered FilterHits.saveFilterHitsToDisk()");
+ // Make sure the file's parent directory exists
+ try {
+ targetFile.parent.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
+ } catch (e) {}
+
+ let writeStats = function()
+ {
+ TimeLine.enter("FilterHits.saveFilterHitsToDisk() -> writeStats()");
+ IO.writeToFile(targetFile, true, this._generateFilterHitData(), function(e)
+ {
+ TimeLine.enter("FilterHits.saveFilterHitsToDisk() write callback");
+ this._saving = false;
+
+ if (e)
+ Cu.reportError(e);
+
+ if (this._needsSave)
+ {
+ this._needsSave = false;
+ this.saveFilterHitsToDisk();
+ }
+ TimeLine.leave("FilterHits.saveFilterHitsToDisk() write callback done");
+ }.bind(this), "FilterHitsWriteStats");
+ TimeLine.leave("FilterHits.saveFilterHitsToDisk() -> writeStats()", "FilterStorageWriteStats");
+ }.bind(this);
+
+ this._saving = true;
+ writeStats();
+ TimeLine.leave("FilterHits.saveFilterHitsToDisk() done");
+ }
+};
+
+/**
+ * IO.readFromFile() listener to parse filter-hits data.
+ * @constructor
+ */
+function FilterHitsParser()
+{
+ this.statistics = {__proto__: null};
+}
+FilterHitsParser.prototype =
+{
+ process: function(val)
+ {
+ if (val === null)
+ return;
+ this.statistics = JSON.parse(val);
+ }
+};
« no previous file with comments | « defaults/prefs.js ('k') | lib/filterListener.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld