/* 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]; } } }