mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 911785 - Implement a webapps actor front to ease app install r=paul
This commit is contained in:
parent
c92c39403a
commit
5e6b2ae299
@ -55,6 +55,7 @@ var BuiltinProvider = {
|
|||||||
"devtools": "resource:///modules/devtools",
|
"devtools": "resource:///modules/devtools",
|
||||||
"devtools/server": "resource://gre/modules/devtools/server",
|
"devtools/server": "resource://gre/modules/devtools/server",
|
||||||
"devtools/toolkit/webconsole": "resource://gre/modules/devtools/toolkit/webconsole",
|
"devtools/toolkit/webconsole": "resource://gre/modules/devtools/toolkit/webconsole",
|
||||||
|
"devtools/app-actor-front": "resource://gre/modules/devtools/app-actor-front.js",
|
||||||
"devtools/styleinspector/css-logic": "resource://gre/modules/devtools/styleinspector/css-logic",
|
"devtools/styleinspector/css-logic": "resource://gre/modules/devtools/styleinspector/css-logic",
|
||||||
"devtools/client": "resource://gre/modules/devtools/client",
|
"devtools/client": "resource://gre/modules/devtools/client",
|
||||||
|
|
||||||
@ -95,6 +96,7 @@ var SrcdirProvider = {
|
|||||||
let toolkitURI = this.fileURI(OS.Path.join(srcdir, "toolkit", "devtools"));
|
let toolkitURI = this.fileURI(OS.Path.join(srcdir, "toolkit", "devtools"));
|
||||||
let serverURI = this.fileURI(OS.Path.join(srcdir, "toolkit", "devtools", "server"));
|
let serverURI = this.fileURI(OS.Path.join(srcdir, "toolkit", "devtools", "server"));
|
||||||
let webconsoleURI = this.fileURI(OS.Path.join(srcdir, "toolkit", "devtools", "webconsole"));
|
let webconsoleURI = this.fileURI(OS.Path.join(srcdir, "toolkit", "devtools", "webconsole"));
|
||||||
|
let appActorURI = this.fileURI(OS.Path.join(srcdir, "toolkit", "devtools", "apps", "app-actor-front.js"));
|
||||||
let cssLogicURI = this.fileURI(OS.Path.join(toolkitURI, "styleinspector", "css-logic"));
|
let cssLogicURI = this.fileURI(OS.Path.join(toolkitURI, "styleinspector", "css-logic"));
|
||||||
let clientURI = this.fileURI(OS.Path.join(srcdir, "toolkit", "devtools", "client"));
|
let clientURI = this.fileURI(OS.Path.join(srcdir, "toolkit", "devtools", "client"));
|
||||||
let mainURI = this.fileURI(OS.Path.join(srcdir, "browser", "devtools", "main.js"));
|
let mainURI = this.fileURI(OS.Path.join(srcdir, "browser", "devtools", "main.js"));
|
||||||
@ -107,6 +109,7 @@ var SrcdirProvider = {
|
|||||||
"": "resource://gre/modules/commonjs/",
|
"": "resource://gre/modules/commonjs/",
|
||||||
"devtools/server": serverURI,
|
"devtools/server": serverURI,
|
||||||
"devtools/toolkit/webconsole": webconsoleURI,
|
"devtools/toolkit/webconsole": webconsoleURI,
|
||||||
|
"devtools/app-actor-front": appActorURI,
|
||||||
"devtools/client": clientURI,
|
"devtools/client": clientURI,
|
||||||
"devtools": devtoolsURI,
|
"devtools": devtoolsURI,
|
||||||
"devtools/styleinspector/css-logic": cssLogicURI,
|
"devtools/styleinspector/css-logic": cssLogicURI,
|
||||||
|
216
toolkit/devtools/apps/app-actor-front.js
Normal file
216
toolkit/devtools/apps/app-actor-front.js
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
const {Ci, Cc, Cu, Cr} = require("chrome");
|
||||||
|
Cu.import("resource://gre/modules/osfile.jsm");
|
||||||
|
const {Services} = Cu.import("resource://gre/modules/Services.jsm");
|
||||||
|
const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||||
|
const promise = require("sdk/core/promise");
|
||||||
|
|
||||||
|
// XXX: bug 912476 make this module a real protocol.js front
|
||||||
|
// by converting webapps actor to protocol.js
|
||||||
|
|
||||||
|
const PR_USEC_PER_MSEC = 1000;
|
||||||
|
const PR_RDWR = 0x04;
|
||||||
|
const PR_CREATE_FILE = 0x08;
|
||||||
|
const PR_TRUNCATE = 0x20;
|
||||||
|
|
||||||
|
const CHUNK_SIZE = 10000;
|
||||||
|
|
||||||
|
function addDirToZip(writer, dir, basePath) {
|
||||||
|
let files = dir.directoryEntries;
|
||||||
|
|
||||||
|
while (files.hasMoreElements()) {
|
||||||
|
let file = files.getNext().QueryInterface(Ci.nsIFile);
|
||||||
|
|
||||||
|
if (file.isHidden() ||
|
||||||
|
file.isSymlink() ||
|
||||||
|
file.isSpecial() ||
|
||||||
|
file.equals(writer.file))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
writer.addEntryDirectory(basePath + file.leafName + "/",
|
||||||
|
file.lastModifiedTime * PR_USEC_PER_MSEC,
|
||||||
|
true);
|
||||||
|
addDirToZip(writer, file, basePath + file.leafName + "/");
|
||||||
|
} else {
|
||||||
|
writer.addEntryFile(basePath + file.leafName,
|
||||||
|
Ci.nsIZipWriter.COMPRESSION_DEFAULT,
|
||||||
|
file,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an XPConnect result code to its name and message.
|
||||||
|
* We have to extract them from an exception per bug 637307 comment 5.
|
||||||
|
*/
|
||||||
|
function getResultTest(code) {
|
||||||
|
let regexp =
|
||||||
|
/^\[Exception... "(.*)" nsresult: "0x[0-9a-fA-F]* \((.*)\)" location: ".*" data: .*\]$/;
|
||||||
|
let ex = Cc["@mozilla.org/js/xpc/Exception;1"].
|
||||||
|
createInstance(Ci.nsIXPCException);
|
||||||
|
ex.initialize(null, code, null, null, null, null);
|
||||||
|
let [, message, name] = regexp.exec(ex.toString());
|
||||||
|
return { name: name, message: message };
|
||||||
|
}
|
||||||
|
|
||||||
|
function zipDirectory(zipFile, dirToArchive) {
|
||||||
|
let deferred = promise.defer();
|
||||||
|
let writer = Cc["@mozilla.org/zipwriter;1"].createInstance(Ci.nsIZipWriter);
|
||||||
|
writer.open(zipFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE);
|
||||||
|
|
||||||
|
this.addDirToZip(writer, dirToArchive, "");
|
||||||
|
|
||||||
|
writer.processQueue({
|
||||||
|
onStartRequest: function onStartRequest(request, context) {},
|
||||||
|
onStopRequest: (request, context, status) => {
|
||||||
|
if (status == Cr.NS_OK) {
|
||||||
|
writer.close();
|
||||||
|
deferred.resolve(zipFile);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let { name, message } = getResultText(status);
|
||||||
|
deferred.reject(name + ": " + message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, null);
|
||||||
|
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
function uploadPackage(client, webappsActor, packageFile) {
|
||||||
|
let deferred = promise.defer();
|
||||||
|
|
||||||
|
let request = {
|
||||||
|
to: webappsActor,
|
||||||
|
type: "uploadPackage"
|
||||||
|
};
|
||||||
|
client.request(request, (res) => {
|
||||||
|
openFile(res.actor);
|
||||||
|
});
|
||||||
|
|
||||||
|
function openFile(actor) {
|
||||||
|
OS.File.open(packageFile.path)
|
||||||
|
.then(function (file) {
|
||||||
|
uploadChunk(actor, file);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function uploadChunk(actor, file) {
|
||||||
|
file.read(CHUNK_SIZE)
|
||||||
|
.then(function (bytes) {
|
||||||
|
// To work around the fact that JSON.stringify translates the typed
|
||||||
|
// array to object, we are encoding the typed array here into a string
|
||||||
|
let chunk = String.fromCharCode.apply(null, bytes);
|
||||||
|
|
||||||
|
let request = {
|
||||||
|
to: actor,
|
||||||
|
type: "chunk",
|
||||||
|
chunk: chunk
|
||||||
|
};
|
||||||
|
client.request(request, (res) => {
|
||||||
|
if (bytes.length == CHUNK_SIZE) {
|
||||||
|
uploadChunk(actor, file);
|
||||||
|
} else {
|
||||||
|
file.close().then(function () {
|
||||||
|
endsUpload(actor);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function endsUpload(actor) {
|
||||||
|
let request = {
|
||||||
|
to: actor,
|
||||||
|
type: "done"
|
||||||
|
};
|
||||||
|
client.request(request, (res) => {
|
||||||
|
deferred.resolve(actor);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeServerTemporaryFile(client, fileActor) {
|
||||||
|
let request = {
|
||||||
|
to: fileActor,
|
||||||
|
type: "remove"
|
||||||
|
};
|
||||||
|
client.request(request, function (aResponse) {
|
||||||
|
console.error("Failed removing server side temporary package file", aResponse);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function installPackaged(client, webappsActor, packagePath, appId) {
|
||||||
|
let deferred = promise.defer();
|
||||||
|
let file = FileUtils.File(packagePath);
|
||||||
|
let packagePromise;
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
let tmpZipFile = FileUtils.getDir("TmpD", [], true);
|
||||||
|
tmpZipFile.append("application.zip");
|
||||||
|
tmpZipFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("666", 8));
|
||||||
|
packagePromise = zipDirectory(tmpZipFile, file)
|
||||||
|
} else {
|
||||||
|
packagePromise = promise.resolve(file);
|
||||||
|
}
|
||||||
|
packagePromise.then((zipFile) => {
|
||||||
|
uploadPackage(client, webappsActor, zipFile)
|
||||||
|
.then((fileActor) => {
|
||||||
|
let request = {
|
||||||
|
to: webappsActor,
|
||||||
|
type: "install",
|
||||||
|
appId: appId,
|
||||||
|
upload: fileActor
|
||||||
|
};
|
||||||
|
client.request(request, (res) => {
|
||||||
|
// If the install method immediatly fails,
|
||||||
|
// reject immediatly the installPackaged promise.
|
||||||
|
// Otherwise, wait for webappsEvent for completion
|
||||||
|
if (res.error) {
|
||||||
|
deferred.reject(res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
client.addOneTimeListener("webappsEvent", function (aState, aType, aPacket) {
|
||||||
|
if ("error" in aType)
|
||||||
|
deferred.reject({error: aType.error, message: aType.message});
|
||||||
|
else
|
||||||
|
deferred.resolve({appId: aType.appId});
|
||||||
|
});
|
||||||
|
// Ensure deleting the temporary package file, but only if that a temporary
|
||||||
|
// package created when we pass a directory as `packagePath`
|
||||||
|
if (zipFile != file)
|
||||||
|
zipFile.remove(false);
|
||||||
|
// In case of success or error, ensure deleting the temporary package file
|
||||||
|
// also created on the device, but only once install request is done
|
||||||
|
deferred.promise.then(removeServerTemporaryFile, removeServerTemporaryFile);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
exports.installPackaged = installPackaged;
|
||||||
|
|
||||||
|
function installHosted(client, webappsActor, appId, metadata, manifest) {
|
||||||
|
let deferred = promise.defer();
|
||||||
|
let request = {
|
||||||
|
to: webappsActor,
|
||||||
|
type: "install",
|
||||||
|
appId: appId,
|
||||||
|
metadata: metadata,
|
||||||
|
manifest: manifest
|
||||||
|
};
|
||||||
|
client.request(request, (res) => {
|
||||||
|
if (res.error) {
|
||||||
|
deferred.reject(res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
client.addOneTimeListener("webappsEvent", function (aState, aType, aPacket) {
|
||||||
|
if ("error" in aType)
|
||||||
|
deferred.reject({error: aType.error, message: aType.message});
|
||||||
|
else
|
||||||
|
deferred.resolve({appId: aType.appId});
|
||||||
|
});
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
exports.installHosted = installHosted;
|
||||||
|
|
@ -8,5 +8,6 @@ TEST_DIRS += ['tests']
|
|||||||
JS_MODULES_PATH = 'modules/devtools'
|
JS_MODULES_PATH = 'modules/devtools'
|
||||||
|
|
||||||
EXTRA_JS_MODULES += [
|
EXTRA_JS_MODULES += [
|
||||||
'Simulator.jsm'
|
'Simulator.jsm',
|
||||||
|
'app-actor-front.js'
|
||||||
]
|
]
|
||||||
|
@ -98,12 +98,13 @@ function do_get_webappsdir() {
|
|||||||
var webappsDir = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
|
var webappsDir = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
|
||||||
webappsDir.append("test_webapps");
|
webappsDir.append("test_webapps");
|
||||||
if (!webappsDir.exists())
|
if (!webappsDir.exists())
|
||||||
webappsDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
|
webappsDir.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("755", 8));
|
||||||
|
|
||||||
var coreAppsDir = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
|
var coreAppsDir = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
|
||||||
coreAppsDir.append("test_coreapps");
|
coreAppsDir.append("test_coreapps");
|
||||||
if (!coreAppsDir.exists())
|
if (!coreAppsDir.exists())
|
||||||
coreAppsDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
|
coreAppsDir.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("755", 8));
|
||||||
|
var tmpDir = Services.dirsvc.get("TmpD", Ci.nsILocalFile);
|
||||||
|
|
||||||
// Register our own provider for the profile directory.
|
// Register our own provider for the profile directory.
|
||||||
// It will return our special docshell profile directory.
|
// It will return our special docshell profile directory.
|
||||||
@ -116,6 +117,7 @@ function do_get_webappsdir() {
|
|||||||
else if (prop == "coreAppsDir") {
|
else if (prop == "coreAppsDir") {
|
||||||
return coreAppsDir.clone();
|
return coreAppsDir.clone();
|
||||||
}
|
}
|
||||||
|
return tmpDir.clone();
|
||||||
throw Cr.NS_ERROR_FAILURE;
|
throw Cr.NS_ERROR_FAILURE;
|
||||||
},
|
},
|
||||||
QueryInterface: function(iid) {
|
QueryInterface: function(iid) {
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/osfile.jsm");
|
Cu.import("resource://gre/modules/osfile.jsm");
|
||||||
|
const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||||
|
const {require} = devtools;
|
||||||
|
const {installHosted, installPackaged} = require("devtools/app-actor-front");
|
||||||
|
|
||||||
let gAppId = "actor-test";
|
let gAppId = "actor-test";
|
||||||
const APP_ORIGIN = "app://" + gAppId;
|
const APP_ORIGIN = "app://" + gAppId;
|
||||||
@ -177,105 +180,35 @@ add_test(function testUninstall() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
add_test(function testFileUploadInstall() {
|
add_test(function testFileUploadInstall() {
|
||||||
function createUpload() {
|
let packageFile = do_get_file("data/app.zip");
|
||||||
let request = {
|
installPackaged(gClient, gActor, packageFile.path, gAppId)
|
||||||
type: "uploadPackage"
|
.then(function ({ appId }) {
|
||||||
};
|
do_check_eq(appId, gAppId);
|
||||||
webappActorRequest(request, function (aResponse) {
|
|
||||||
getPackageContent(aResponse.actor);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function getPackageContent(uploadActor) {
|
|
||||||
let packageFile = do_get_file("data/app.zip");
|
|
||||||
OS.File.read(packageFile.path)
|
|
||||||
.then(function (bytes) {
|
|
||||||
// To work around the fact that JSON.stringify translates the typed
|
|
||||||
// array to object, we are encoding the typed array here into a string
|
|
||||||
let content = String.fromCharCode.apply(null, bytes);
|
|
||||||
uploadChunk(uploadActor, content);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function uploadChunk(uploadActor, content) {
|
|
||||||
let request = {
|
|
||||||
to: uploadActor,
|
|
||||||
type: "chunk",
|
|
||||||
chunk: content
|
|
||||||
};
|
|
||||||
gClient.request(request, function (aResponse) {
|
|
||||||
endsUpload(uploadActor);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function endsUpload(uploadActor, content) {
|
|
||||||
let request = {
|
|
||||||
to: uploadActor,
|
|
||||||
type: "done"
|
|
||||||
};
|
|
||||||
gClient.request(request, function (aResponse) {
|
|
||||||
installApp(uploadActor);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function installApp(uploadActor) {
|
|
||||||
let request = {type: "install", appId: gAppId, upload: uploadActor};
|
|
||||||
webappActorRequest(request, function (aResponse) {
|
|
||||||
do_check_eq(aResponse.appId, gAppId);
|
|
||||||
});
|
|
||||||
gClient.addOneTimeListener("webappsEvent", function listener(aState, aType, aPacket) {
|
|
||||||
do_check_eq(aType.appId, gAppId);
|
|
||||||
if ("error" in aType) {
|
|
||||||
do_print("Error: " + aType.error);
|
|
||||||
}
|
|
||||||
if ("message" in aType) {
|
|
||||||
do_print("Error message: " + aType.message);
|
|
||||||
}
|
|
||||||
do_check_eq("error" in aType, false);
|
|
||||||
|
|
||||||
removeUpload(uploadActor);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function removeUpload(uploadActor, content) {
|
|
||||||
let request = {
|
|
||||||
to: uploadActor,
|
|
||||||
type: "remove"
|
|
||||||
};
|
|
||||||
gClient.request(request, function (aResponse) {
|
|
||||||
run_next_test();
|
run_next_test();
|
||||||
|
}, function (e) {
|
||||||
|
do_throw("Failed install uploaded packaged app: " + e.error + ": " + e.message);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
createUpload();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
add_test(function testInstallHosted() {
|
add_test(function testInstallHosted() {
|
||||||
gAppId = "hosted-app";
|
gAppId = "hosted-app";
|
||||||
let request = {
|
let metadata = {
|
||||||
type: "install",
|
origin: "http://foo.com",
|
||||||
appId: gAppId,
|
installOrigin: "http://metadata.foo.com",
|
||||||
manifest: {
|
manifestURL: "http://foo.com/metadata/manifest.webapp"
|
||||||
name: "My hosted app"
|
|
||||||
},
|
|
||||||
metadata: {
|
|
||||||
origin: "http://foo.com",
|
|
||||||
installOrigin: "http://metadata.foo.com",
|
|
||||||
manifestURL: "http://foo.com/metadata/manifest.webapp"
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
webappActorRequest(request, function (aResponse) {
|
let manifest = {
|
||||||
do_check_eq(aResponse.appId, gAppId);
|
name: "My hosted app"
|
||||||
});
|
};
|
||||||
|
installHosted(gClient, gActor, gAppId, metadata, manifest).then(
|
||||||
// The install request is asynchronous and send back an event to tell
|
function ({ appId }) {
|
||||||
// if the installation succeed or failed
|
do_check_eq(appId, gAppId);
|
||||||
gClient.addOneTimeListener("webappsEvent", function listener(aState, aType, aPacket) {
|
run_next_test();
|
||||||
do_check_eq(aType.appId, gAppId);
|
},
|
||||||
if ("error" in aType) {
|
function (e) {
|
||||||
do_print("Error: " + aType.error);
|
do_throw("Failed installing hosted app: " + e.error + ": " + e.message);
|
||||||
}
|
}
|
||||||
if ("message" in aType) {
|
);
|
||||||
do_print("Error message: " + aType.message);
|
|
||||||
}
|
|
||||||
do_check_eq("error" in aType, false);
|
|
||||||
|
|
||||||
run_next_test();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
add_test(function testCheckHostedApp() {
|
add_test(function testCheckHostedApp() {
|
||||||
|
Loading…
Reference in New Issue
Block a user