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

208 lines
5.1 KiB
JavaScript

/* 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/. */
const ObservableObject = require("devtools/shared/observable-object");
const promise = require("sdk/core/promise");
const {Connection} = require("devtools/client/connection-manager");
const {Cu} = require("chrome");
const dbgClient = Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
dbgClient.UnsolicitedNotifications.appOpen = "appOpen";
dbgClient.UnsolicitedNotifications.appClose = "appClose"
const _knownWebappsStores = new WeakMap();
let WebappsStore;
module.exports = WebappsStore = function(connection) {
// If we already know about this connection,
// let's re-use the existing store.
if (_knownWebappsStores.has(connection)) {
return _knownWebappsStores.get(connection);
}
_knownWebappsStores.set(connection, this);
ObservableObject.call(this, {});
this._resetStore();
this._destroy = this._destroy.bind(this);
this._onStatusChanged = this._onStatusChanged.bind(this);
this._connection = connection;
this._connection.once(Connection.Events.DESTROYED, this._destroy);
this._connection.on(Connection.Events.STATUS_CHANGED, this._onStatusChanged);
this._onStatusChanged();
return this;
}
WebappsStore.prototype = {
_destroy: function() {
this._connection.off(Connection.Events.STATUS_CHANGED, this._onStatusChanged);
_knownWebappsStores.delete(this._connection);
this._connection = null;
},
_resetStore: function() {
this.object.all = []; // list of app objects
this.object.running = []; // list of manifests
},
_getAppFromManifest: function(manifest) {
for (let app of this.object.all) {
if (app.manifestURL == manifest) {
return app;
}
}
return null;
},
_onStatusChanged: function() {
if (this._connection.status == Connection.Status.CONNECTED) {
this._listTabs();
} else {
this._resetStore();
}
},
_listTabs: function() {
this._connection.client.listTabs((resp) => {
this._webAppsActor = resp.webappsActor;
this._feedStore();
});
},
_feedStore: function(deviceFront, webAppsActor) {
this._listenToApps();
this._getAllApps()
.then(this._getRunningApps.bind(this))
.then(this._getAppsIcons.bind(this))
},
_listenToApps: function() {
let deferred = promise.defer();
let client = this._connection.client;
let request = {
to: this._webAppsActor,
type: "watchApps"
};
client.request(request, (res) => {
if (res.error) {
return deferred.reject(res.error);
}
client.addListener("appOpen", (type, { manifestURL }) => {
this._onAppOpen(manifestURL);
});
client.addListener("appClose", (type, { manifestURL }) => {
this._onAppClose(manifestURL);
});
return deferred.resolve();
})
return deferred.promise;
},
_getAllApps: function() {
let deferred = promise.defer();
let request = {
to: this._webAppsActor,
type: "getAll"
};
this._connection.client.request(request, (res) => {
if (res.error) {
return deferred.reject(res.error);
}
let apps = res.apps;
for (let a of apps) {
a.running = false;
}
this.object.all = apps;
return deferred.resolve();
});
return deferred.promise;
},
_getRunningApps: function() {
let deferred = promise.defer();
let request = {
to: this._webAppsActor,
type: "listRunningApps"
};
this._connection.client.request(request, (res) => {
if (res.error) {
return deferred.reject(res.error);
}
let manifests = res.apps;
this.object.running = manifests;
for (let m of manifests) {
let a = this._getAppFromManifest(m);
if (a) {
a.running = true;
} else {
return deferred.reject("Unexpected manifest: " + m);
}
}
return deferred.resolve();
});
return deferred.promise;
},
_getAppsIcons: function() {
let deferred = promise.defer();
let allApps = this.object.all;
let request = {
to: this._webAppsActor,
type: "getIconAsDataURL"
};
let client = this._connection.client;
let idx = 0;
(function getIcon() {
if (idx == allApps.length) {
return deferred.resolve();
}
let a = allApps[idx++];
request.manifestURL = a.manifestURL;
return client.request(request, (res) => {
if (res.url) {
a.iconURL = res.url;
}
getIcon();
});
})();
return deferred.promise;
},
_onAppOpen: function(manifest) {
let a = this._getAppFromManifest(manifest);
a.running = true;
let running = this.object.running;
if (running.indexOf(manifest) < 0) {
this.object.running.push(manifest);
}
},
_onAppClose: function(manifest) {
let a = this._getAppFromManifest(manifest);
a.running = false;
let running = this.object.running;
this.object.running = running.filter((m) => {
return m != manifest;
});
},
}