In a following patch, all DevTools moz.build files will use DevToolsModules to install JS modules at a path that corresponds directly to their source tree location. Here we rewrite all require and import calls to match the new location that these files are installed to.
284 lines
7.2 KiB
JavaScript
284 lines
7.2 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/client/shared/observable-object");
|
|
const promise = require("devtools/shared/deprecated-sync-thenables");
|
|
const {Connection} = require("devtools/shared/client/connection-manager");
|
|
|
|
const {Cu} = require("chrome");
|
|
const _knownWebappsStores = new WeakMap();
|
|
|
|
var 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() {
|
|
if (this._connection) {
|
|
// While this.destroy is bound using .once() above, that event may not
|
|
// have occurred when the WebappsStore client calls destroy, so we
|
|
// manually remove it here.
|
|
this._connection.off(Connection.Events.DESTROYED, this.destroy);
|
|
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().then(() => {
|
|
this.emit("store-ready");
|
|
});
|
|
});
|
|
},
|
|
|
|
_feedStore: function() {
|
|
if (!this._webAppsActor) {
|
|
return promise.resolve();
|
|
}
|
|
this._listenToApps();
|
|
return 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);
|
|
});
|
|
|
|
client.addListener("appInstall", (type, { manifestURL }) => {
|
|
this._onAppInstall(manifestURL);
|
|
});
|
|
|
|
client.addListener("appUninstall", (type, { manifestURL }) => {
|
|
this._onAppUninstall(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.error) {
|
|
Cu.reportError(res.message || res.error);
|
|
}
|
|
|
|
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;
|
|
});
|
|
},
|
|
|
|
_onAppInstall: function(manifest) {
|
|
let client = this._connection.client;
|
|
let request = {
|
|
to: this._webAppsActor,
|
|
type: "getApp",
|
|
manifestURL: manifest
|
|
};
|
|
|
|
client.request(request, (res) => {
|
|
if (res.error) {
|
|
if (res.error == "forbidden") {
|
|
// We got a notification for an app we don't have access to.
|
|
// Ignore.
|
|
return;
|
|
}
|
|
Cu.reportError(res.message || res.error);
|
|
return;
|
|
}
|
|
|
|
let app = res.app;
|
|
app.running = false;
|
|
|
|
let notFound = true;
|
|
let proxifiedApp;
|
|
for (let i = 0; i < this.object.all.length; i++) {
|
|
let storedApp = this.object.all[i];
|
|
if (storedApp.manifestURL == app.manifestURL) {
|
|
this.object.all[i] = app;
|
|
proxifiedApp = this.object.all[i];
|
|
notFound = false;
|
|
break;
|
|
}
|
|
}
|
|
if (notFound) {
|
|
this.object.all.push(app);
|
|
proxifiedApp = this.object.all[this.object.all.length - 1];
|
|
}
|
|
|
|
request.type = "getIconAsDataURL";
|
|
client.request(request, (res) => {
|
|
if (res.url) {
|
|
proxifiedApp.iconURL = res.url;
|
|
}
|
|
});
|
|
|
|
// This app may have been running while being installed, so check the list
|
|
// of running apps again to get the right answer.
|
|
this._getRunningApps();
|
|
});
|
|
},
|
|
|
|
_onAppUninstall: function(manifest) {
|
|
this.object.all = this.object.all.filter((app) => {
|
|
return (app.manifestURL != manifest);
|
|
});
|
|
},
|
|
}
|