diff -r 000000000000 -r 6474c204b198 dom/apps/src/FreeSpaceWatcher.jsm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/apps/src/FreeSpaceWatcher.jsm Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,118 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/FileUtils.jsm"); + +this.EXPORTED_SYMBOLS = ["FreeSpaceWatcher"]; + +function debug(aMsg) { + //dump("-*-*- FreeSpaceWatcher.jsm : " + aMsg + "\n"); +} + +// Polling delay for free space, in ms. +const DEFAULT_WATCHER_DELAY = 1000; + +this.FreeSpaceWatcher = { + timers: {}, + id: 0, + + /** + * This function will call aOnStatusChange + * each time the free space for apps crosses aThreshold, checking + * every aDelay milliseconds, or every second by default. + * aOnStatusChange is called with either "free" or "full" and will + * always be called at least one to get the initial status. + * @param aThreshold The amount of space in bytes to watch for. + * @param aOnStatusChange The function called when the state changes. + * @param aDelay How often (in ms) we check free space. Defaults + * to DEFAULT_WATCHER_DELAY. + * @return An opaque value to use with stop(). + */ + create: function spaceWatcher_create(aThreshold, aOnStatusChange, aDelay) { + let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + debug("Creating new FreeSpaceWatcher"); + let callback = { + currentStatus: null, + notify: function(aTimer) { + try { + let checkFreeSpace = function (freeBytes) { + debug("Free bytes: " + freeBytes); + let newStatus = freeBytes > aThreshold; + if (newStatus != callback.currentStatus) { + debug("New status: " + (newStatus ? "free" : "full")); + aOnStatusChange(newStatus ? "free" : "full"); + callback.currentStatus = newStatus; + } + }; + + let navigator = Services.wm.getMostRecentWindow("navigator:browser") + .navigator; + let deviceStorage = null; + + if (navigator.getDeviceStorage) { + deviceStorage = navigator.getDeviceStorage("apps"); + } + + if (deviceStorage) { + let req = deviceStorage.freeSpace(); + req.onsuccess = req.onerror = function statResult(e) { + if (!e.target.result) { + return; + } + + let freeBytes = e.target.result; + checkFreeSpace(freeBytes); + } + } else { + // deviceStorage isn't available, so use the webappsDir instead. + // This needs to be moved from a hardcoded string to DIRECTORY_NAME + // in AppsUtils. See bug 852685. + let dir = FileUtils.getDir("webappsDir", ["webapps"], true, true); + let freeBytes; + try { + freeBytes = dir.diskSpaceAvailable; + } catch(e) { + // If disk space information isn't available, we should assume + // that there is enough free space, and that we'll fail when + // we actually run out of disk space. + callback.currentStatus = true; + } + if (freeBytes) { + // We have disk space information. Call this here so that + // any exceptions are caught in the outer catch block. + checkFreeSpace(freeBytes); + } + } + } catch(e) { + // If the aOnStatusChange callback has errored we'll end up here. + debug(e); + } + } + } + + timer.initWithCallback(callback, aDelay || DEFAULT_WATCHER_DELAY, + Ci.nsITimer.TYPE_REPEATING_SLACK); + let id = "timer-" + this.id++; + this.timers[id] = timer; + return id; + }, + + /** + * This function stops a running watcher. + * @param aId The opaque timer id returned by create(). + */ + stop: function spaceWatcher_stop(aId) { + if (this.timers[aId]) { + this.timers[aId].cancel(); + delete this.timers[aId]; + } + } +}