| OLD | NEW | 
| (Empty) |  | 
 |    1 /* | 
 |    2  * This file is part of Adblock Plus <http://adblockplus.org/>, | 
 |    3  * Copyright (C) 2006-2014 Eyeo GmbH | 
 |    4  * | 
 |    5  * Adblock Plus is free software: you can redistribute it and/or modify | 
 |    6  * it under the terms of the GNU General Public License version 3 as | 
 |    7  * published by the Free Software Foundation. | 
 |    8  * | 
 |    9  * Adblock Plus is distributed in the hope that it will be useful, | 
 |   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |   12  * GNU General Public License for more details. | 
 |   13  * | 
 |   14  * You should have received a copy of the GNU General Public License | 
 |   15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
 |   16  */ | 
 |   17  | 
 |   18 let {IO} = require("io"); | 
 |   19 let {Utils} = require("utils"); | 
 |   20 let {Prefs} = require("prefs"); | 
 |   21 let {TimeLine} = require("timeline"); | 
 |   22 let {Filter} = require("filterClasses"); | 
 |   23  | 
 |   24 /** | 
 |   25  * This class reads filter hits statistics from disk, manages them in memory and
      writes them back.W | 
 |   26  * @class | 
 |   27  */ | 
 |   28 let FilterHits = exports.FilterHits = | 
 |   29 { | 
 |   30   statistics: {}, | 
 |   31    | 
 |   32   _loading: false, | 
 |   33   _saving: false, | 
 |   34   _needsSave: false, | 
 |   35    | 
 |   36   /** | 
 |   37    * File that the filter hits statistics has been loaded from and should be sav
     ed to | 
 |   38    * @type nsIFile | 
 |   39    */ | 
 |   40   get filterHitsFile() | 
 |   41   { | 
 |   42     let file = null; | 
 |   43     if (!file) | 
 |   44     { | 
 |   45       // Place the file in the data dir | 
 |   46       file = IO.resolveFilePath(Prefs.data_directory); | 
 |   47       if (file) | 
 |   48         file.append("filter-hits.ini"); | 
 |   49     } | 
 |   50     if (!file) | 
 |   51     { | 
 |   52       // Data directory pref misconfigured? Try the default value | 
 |   53       try | 
 |   54       { | 
 |   55         file = IO.resolveFilePath(Services.prefs.getDefaultBranch("extensions.ad
     blockplus.").getCharPref("data_directory")); | 
 |   56         if (file) | 
 |   57           file.append("filter-hits.ini"); | 
 |   58       } catch(e) {} | 
 |   59     } | 
 |   60  | 
 |   61     if (!file) | 
 |   62       Cu.reportError("Adblock Plus: Failed to resolve filter-hits file"); | 
 |   63  | 
 |   64     this.__defineGetter__("filterHitsFile", function() file); | 
 |   65     return this.filterHitsFile; | 
 |   66   }, | 
 |   67    | 
 |   68   /** | 
 |   69    * Increases the filter hit count by one | 
 |   70    * @param {Filter} filter | 
 |   71    * @param {Window} window  Window that the match originated in (required to ge
     t host name) | 
 |   72    */ | 
 |   73   increaseFilterHits: function(filter, wnd) | 
 |   74   { | 
 |   75     if(!filter.text) | 
 |   76       return; | 
 |   77        | 
 |   78     if(filter.text in this.statistics) | 
 |   79       this.statistics[filter.text].statsHitCount++; | 
 |   80     else | 
 |   81       this.statistics[filter.text] = {statsHitCount:1, lastHit: 0, domainsCount:
     {}}; | 
 |   82      | 
 |   83     if(filter.lastHit) | 
 |   84       this.statistics[filter.text].lastHit = filter.lastHit; | 
 |   85      | 
 |   86     // Get hostname from window object | 
 |   87     let wndLocation = Utils.getOriginWindow(wnd).location.href; | 
 |   88     let host = Utils.unwrapURL(wndLocation).host; | 
 |   89      | 
 |   90     this._increaseDomainHit(this.statistics[filter.text], host); | 
 |   91   }, | 
 |   92    | 
 |   93   /** | 
 |   94    * Increases Domain hit count by one | 
 |   95    * @param {statisticFilterObj} statisticFilterObj statistic's filter object | 
 |   96    * @param {host} host String | 
 |   97    */ | 
 |   98   _increaseDomainHit: function(statisticFilterObj, host) | 
 |   99   { | 
 |  100     if(host in statisticFilterObj.domainsCount) | 
 |  101       statisticFilterObj.domainsCount[host]++; | 
 |  102     else | 
 |  103       statisticFilterObj.domainsCount[host] = 1; | 
 |  104   }, | 
 |  105    | 
 |  106   resetFilterHits: function() | 
 |  107   { | 
 |  108     this.statistics = {}; | 
 |  109   }, | 
 |  110    | 
 |  111   /** | 
 |  112    * send filter hits statistics to ABP sever and reset filter hits count | 
 |  113    */ | 
 |  114   sendFilterHitsToServer: function() | 
 |  115   { | 
 |  116     //TODO implement ajax request to server sending this.statistics | 
 |  117     //append user subscriptions and browser info before sending | 
 |  118     //and reset filterhits on 200 response | 
 |  119     this.resetFilterHits(); | 
 |  120     this.saveFilterHitsToDisk(); | 
 |  121   }, | 
 |  122    | 
 |  123   /** | 
 |  124    * Loads Filter hit statistics from the disk | 
 |  125    */ | 
 |  126   loadFilterHitsFromDisk: function() | 
 |  127   { | 
 |  128     if (this._loading) | 
 |  129       return; | 
 |  130  | 
 |  131     let sourceFile = FilterHits.filterHitsFile; | 
 |  132     if(!sourceFile) | 
 |  133       return; | 
 |  134  | 
 |  135     TimeLine.enter("Entered FilterHits.loadFilterHitsFromDisk()"); | 
 |  136     this._loading = true; | 
 |  137  | 
 |  138     let readFile = function() | 
 |  139     { | 
 |  140       TimeLine.enter("FilterHits.loadFilterHitsFromDisk() -> readFile()"); | 
 |  141       let parser = new FilterHitsParser(); | 
 |  142       IO.readFromFile(sourceFile, true, parser, function(e) | 
 |  143       { | 
 |  144         TimeLine.enter("FilterHits.loadFilterHitsFromDisk() read callback"); | 
 |  145         if (e) | 
 |  146           Cu.reportError(e); | 
 |  147  | 
 |  148         doneReading(parser); | 
 |  149       }.bind(this), "FilterHitsRead"); | 
 |  150  | 
 |  151       TimeLine.leave("FilterHits.loadFilterHitsFromDisk() <- readFile()", "Filte
     rHitsRead"); | 
 |  152     }.bind(this); | 
 |  153  | 
 |  154     var doneReading = function(parser) | 
 |  155     { | 
 |  156       FilterHits.statistics = parser.statistics; | 
 |  157       this._loading = false; | 
 |  158       TimeLine.leave("FilterHits.loadFilterHitsFromDisk() read callback done"); | 
 |  159     }.bind(this); | 
 |  160  | 
 |  161     readFile(sourceFile); | 
 |  162     TimeLine.leave("FilterHits.loadFilterHitsFromDisk() done"); | 
 |  163   }, | 
 |  164    | 
 |  165   /** | 
 |  166    * Stringify filter hits statistics object | 
 |  167    */ | 
 |  168   _generateFilterHitData: function() | 
 |  169   { | 
 |  170     yield JSON.stringify(FilterHits.statistics); | 
 |  171   }, | 
 |  172    | 
 |  173   /** | 
 |  174    * Save Filters hit statistics to the disk | 
 |  175    */ | 
 |  176   saveFilterHitsToDisk: function() | 
 |  177   { | 
 |  178     let targetFile = FilterHits.filterHitsFile; | 
 |  179     if (!targetFile) | 
 |  180       return; | 
 |  181  | 
 |  182     if (this._saving) | 
 |  183     { | 
 |  184       this._needsSave = true; | 
 |  185       return; | 
 |  186     } | 
 |  187     TimeLine.enter("Entered FilterHits.saveFilterHitsToDisk()"); | 
 |  188     // Make sure the file's parent directory exists | 
 |  189     try { | 
 |  190       targetFile.parent.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECT
     ORY); | 
 |  191     } catch (e) {} | 
 |  192  | 
 |  193     let writeStats = function() | 
 |  194     { | 
 |  195       TimeLine.enter("FilterHits.saveFilterHitsToDisk() -> writeStats()"); | 
 |  196       IO.writeToFile(targetFile, true, this._generateFilterHitData(), function(e
     ) | 
 |  197       { | 
 |  198         TimeLine.enter("FilterHits.saveFilterHitsToDisk() write callback"); | 
 |  199         this._saving = false; | 
 |  200  | 
 |  201         if (e) | 
 |  202           Cu.reportError(e); | 
 |  203  | 
 |  204         if (this._needsSave) | 
 |  205         { | 
 |  206           this._needsSave = false; | 
 |  207           this.saveFilterHitsToDisk(); | 
 |  208         } | 
 |  209         TimeLine.leave("FilterHits.saveFilterHitsToDisk() write callback done"); | 
 |  210       }.bind(this), "FilterHitsWriteStats"); | 
 |  211       TimeLine.leave("FilterHits.saveFilterHitsToDisk() -> writeStats()", "Filte
     rStorageWriteStats"); | 
 |  212     }.bind(this); | 
 |  213  | 
 |  214     this._saving = true; | 
 |  215     writeStats(); | 
 |  216     TimeLine.leave("FilterHits.saveFilterHitsToDisk() done"); | 
 |  217   } | 
 |  218 }; | 
 |  219  | 
 |  220 /** | 
 |  221  * IO.readFromFile() listener to parse filter-hits data. | 
 |  222  * @constructor | 
 |  223  */ | 
 |  224 function FilterHitsParser() | 
 |  225 { | 
 |  226   this.statistics = {__proto__: null}; | 
 |  227 } | 
 |  228 FilterHitsParser.prototype = | 
 |  229 { | 
 |  230   process: function(val) | 
 |  231   { | 
 |  232     if (val === null) | 
 |  233        return; | 
 |  234     this.statistics = JSON.parse(val); | 
 |  235   } | 
 |  236 }; | 
| OLD | NEW |