browser/devtools/app-manager/webapps-store.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 const ObservableObject = require("devtools/shared/observable-object");
michael@0 6 const promise = require("devtools/toolkit/deprecated-sync-thenables");
michael@0 7 const {Connection} = require("devtools/client/connection-manager");
michael@0 8
michael@0 9 const {Cu} = require("chrome");
michael@0 10 const dbgClient = Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
michael@0 11 const _knownWebappsStores = new WeakMap();
michael@0 12
michael@0 13 let WebappsStore;
michael@0 14
michael@0 15 module.exports = WebappsStore = function(connection) {
michael@0 16 // If we already know about this connection,
michael@0 17 // let's re-use the existing store.
michael@0 18 if (_knownWebappsStores.has(connection)) {
michael@0 19 return _knownWebappsStores.get(connection);
michael@0 20 }
michael@0 21
michael@0 22 _knownWebappsStores.set(connection, this);
michael@0 23
michael@0 24 ObservableObject.call(this, {});
michael@0 25
michael@0 26 this._resetStore();
michael@0 27
michael@0 28 this.destroy = this.destroy.bind(this);
michael@0 29 this._onStatusChanged = this._onStatusChanged.bind(this);
michael@0 30
michael@0 31 this._connection = connection;
michael@0 32 this._connection.once(Connection.Events.DESTROYED, this.destroy);
michael@0 33 this._connection.on(Connection.Events.STATUS_CHANGED, this._onStatusChanged);
michael@0 34 this._onStatusChanged();
michael@0 35 return this;
michael@0 36 }
michael@0 37
michael@0 38 WebappsStore.prototype = {
michael@0 39 destroy: function() {
michael@0 40 if (this._connection) {
michael@0 41 // While this.destroy is bound using .once() above, that event may not
michael@0 42 // have occurred when the WebappsStore client calls destroy, so we
michael@0 43 // manually remove it here.
michael@0 44 this._connection.off(Connection.Events.DESTROYED, this.destroy);
michael@0 45 this._connection.off(Connection.Events.STATUS_CHANGED, this._onStatusChanged);
michael@0 46 _knownWebappsStores.delete(this._connection);
michael@0 47 this._connection = null;
michael@0 48 }
michael@0 49 },
michael@0 50
michael@0 51 _resetStore: function() {
michael@0 52 this.object.all = []; // list of app objects
michael@0 53 this.object.running = []; // list of manifests
michael@0 54 },
michael@0 55
michael@0 56 _getAppFromManifest: function(manifest) {
michael@0 57 for (let app of this.object.all) {
michael@0 58 if (app.manifestURL == manifest) {
michael@0 59 return app;
michael@0 60 }
michael@0 61 }
michael@0 62 return null;
michael@0 63 },
michael@0 64
michael@0 65 _onStatusChanged: function() {
michael@0 66 if (this._connection.status == Connection.Status.CONNECTED) {
michael@0 67 this._listTabs();
michael@0 68 } else {
michael@0 69 this._resetStore();
michael@0 70 }
michael@0 71 },
michael@0 72
michael@0 73 _listTabs: function() {
michael@0 74 this._connection.client.listTabs((resp) => {
michael@0 75 this._webAppsActor = resp.webappsActor;
michael@0 76 this._feedStore();
michael@0 77 });
michael@0 78 },
michael@0 79
michael@0 80 _feedStore: function(deviceFront, webAppsActor) {
michael@0 81 this._listenToApps();
michael@0 82 this._getAllApps()
michael@0 83 .then(this._getRunningApps.bind(this))
michael@0 84 .then(this._getAppsIcons.bind(this))
michael@0 85 },
michael@0 86
michael@0 87 _listenToApps: function() {
michael@0 88 let deferred = promise.defer();
michael@0 89 let client = this._connection.client;
michael@0 90
michael@0 91 let request = {
michael@0 92 to: this._webAppsActor,
michael@0 93 type: "watchApps"
michael@0 94 };
michael@0 95
michael@0 96 client.request(request, (res) => {
michael@0 97 if (res.error) {
michael@0 98 return deferred.reject(res.error);
michael@0 99 }
michael@0 100
michael@0 101 client.addListener("appOpen", (type, { manifestURL }) => {
michael@0 102 this._onAppOpen(manifestURL);
michael@0 103 });
michael@0 104
michael@0 105 client.addListener("appClose", (type, { manifestURL }) => {
michael@0 106 this._onAppClose(manifestURL);
michael@0 107 });
michael@0 108
michael@0 109 client.addListener("appInstall", (type, { manifestURL }) => {
michael@0 110 this._onAppInstall(manifestURL);
michael@0 111 });
michael@0 112
michael@0 113 client.addListener("appUninstall", (type, { manifestURL }) => {
michael@0 114 this._onAppUninstall(manifestURL);
michael@0 115 });
michael@0 116
michael@0 117 return deferred.resolve();
michael@0 118 })
michael@0 119 return deferred.promise;
michael@0 120 },
michael@0 121
michael@0 122 _getAllApps: function() {
michael@0 123 let deferred = promise.defer();
michael@0 124 let request = {
michael@0 125 to: this._webAppsActor,
michael@0 126 type: "getAll"
michael@0 127 };
michael@0 128
michael@0 129 this._connection.client.request(request, (res) => {
michael@0 130 if (res.error) {
michael@0 131 return deferred.reject(res.error);
michael@0 132 }
michael@0 133 let apps = res.apps;
michael@0 134 for (let a of apps) {
michael@0 135 a.running = false;
michael@0 136 }
michael@0 137 this.object.all = apps;
michael@0 138 return deferred.resolve();
michael@0 139 });
michael@0 140 return deferred.promise;
michael@0 141 },
michael@0 142
michael@0 143 _getRunningApps: function() {
michael@0 144 let deferred = promise.defer();
michael@0 145 let request = {
michael@0 146 to: this._webAppsActor,
michael@0 147 type: "listRunningApps"
michael@0 148 };
michael@0 149
michael@0 150 this._connection.client.request(request, (res) => {
michael@0 151 if (res.error) {
michael@0 152 return deferred.reject(res.error);
michael@0 153 }
michael@0 154
michael@0 155 let manifests = res.apps;
michael@0 156 this.object.running = manifests;
michael@0 157
michael@0 158 for (let m of manifests) {
michael@0 159 let a = this._getAppFromManifest(m);
michael@0 160 if (a) {
michael@0 161 a.running = true;
michael@0 162 } else {
michael@0 163 return deferred.reject("Unexpected manifest: " + m);
michael@0 164 }
michael@0 165 }
michael@0 166
michael@0 167 return deferred.resolve();
michael@0 168 });
michael@0 169 return deferred.promise;
michael@0 170 },
michael@0 171
michael@0 172 _getAppsIcons: function() {
michael@0 173 let deferred = promise.defer();
michael@0 174 let allApps = this.object.all;
michael@0 175
michael@0 176 let request = {
michael@0 177 to: this._webAppsActor,
michael@0 178 type: "getIconAsDataURL"
michael@0 179 };
michael@0 180
michael@0 181 let client = this._connection.client;
michael@0 182
michael@0 183 let idx = 0;
michael@0 184 (function getIcon() {
michael@0 185 if (idx == allApps.length) {
michael@0 186 return deferred.resolve();
michael@0 187 }
michael@0 188 let a = allApps[idx++];
michael@0 189 request.manifestURL = a.manifestURL;
michael@0 190 return client.request(request, (res) => {
michael@0 191 if (res.error) {
michael@0 192 Cu.reportError(res.message || res.error);
michael@0 193 }
michael@0 194
michael@0 195 if (res.url) {
michael@0 196 a.iconURL = res.url;
michael@0 197 }
michael@0 198 getIcon();
michael@0 199 });
michael@0 200 })();
michael@0 201
michael@0 202 return deferred.promise;
michael@0 203 },
michael@0 204
michael@0 205 _onAppOpen: function(manifest) {
michael@0 206 let a = this._getAppFromManifest(manifest);
michael@0 207 a.running = true;
michael@0 208 let running = this.object.running;
michael@0 209 if (running.indexOf(manifest) < 0) {
michael@0 210 this.object.running.push(manifest);
michael@0 211 }
michael@0 212 },
michael@0 213
michael@0 214 _onAppClose: function(manifest) {
michael@0 215 let a = this._getAppFromManifest(manifest);
michael@0 216 a.running = false;
michael@0 217 let running = this.object.running;
michael@0 218 this.object.running = running.filter((m) => {
michael@0 219 return m != manifest;
michael@0 220 });
michael@0 221 },
michael@0 222
michael@0 223 _onAppInstall: function(manifest) {
michael@0 224 let client = this._connection.client;
michael@0 225 let request = {
michael@0 226 to: this._webAppsActor,
michael@0 227 type: "getApp",
michael@0 228 manifestURL: manifest
michael@0 229 };
michael@0 230
michael@0 231 client.request(request, (res) => {
michael@0 232 if (res.error) {
michael@0 233 if (res.error == "forbidden") {
michael@0 234 // We got a notification for an app we don't have access to.
michael@0 235 // Ignore.
michael@0 236 return;
michael@0 237 }
michael@0 238 Cu.reportError(res.message || res.error);
michael@0 239 return;
michael@0 240 }
michael@0 241
michael@0 242 let app = res.app;
michael@0 243 app.running = false;
michael@0 244
michael@0 245 let notFound = true;
michael@0 246 let proxifiedApp;
michael@0 247 for (let i = 0; i < this.object.all.length; i++) {
michael@0 248 let storedApp = this.object.all[i];
michael@0 249 if (storedApp.manifestURL == app.manifestURL) {
michael@0 250 this.object.all[i] = app;
michael@0 251 proxifiedApp = this.object.all[i];
michael@0 252 notFound = false;
michael@0 253 break;
michael@0 254 }
michael@0 255 }
michael@0 256 if (notFound) {
michael@0 257 this.object.all.push(app);
michael@0 258 proxifiedApp = this.object.all[this.object.all.length - 1];
michael@0 259 }
michael@0 260
michael@0 261 request.type = "getIconAsDataURL";
michael@0 262 client.request(request, (res) => {
michael@0 263 if (res.url) {
michael@0 264 proxifiedApp.iconURL = res.url;
michael@0 265 }
michael@0 266 });
michael@0 267
michael@0 268 // This app may have been running while being installed, so check the list
michael@0 269 // of running apps again to get the right answer.
michael@0 270 this._getRunningApps();
michael@0 271 });
michael@0 272 },
michael@0 273
michael@0 274 _onAppUninstall: function(manifest) {
michael@0 275 this.object.all = this.object.all.filter((app) => {
michael@0 276 return (app.manifestURL != manifest);
michael@0 277 });
michael@0 278 },
michael@0 279 }

mercurial