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