toolkit/devtools/apps/app-actor-front.js

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:2a4e10d944dc
1 const {Ci, Cc, Cu, Cr} = require("chrome");
2 Cu.import("resource://gre/modules/osfile.jsm");
3 const {Services} = Cu.import("resource://gre/modules/Services.jsm");
4 const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm");
5 const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
6 const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
7
8 // XXX: bug 912476 make this module a real protocol.js front
9 // by converting webapps actor to protocol.js
10
11 const PR_USEC_PER_MSEC = 1000;
12 const PR_RDWR = 0x04;
13 const PR_CREATE_FILE = 0x08;
14 const PR_TRUNCATE = 0x20;
15
16 const CHUNK_SIZE = 10000;
17
18 const appTargets = new Map();
19
20 function addDirToZip(writer, dir, basePath) {
21 let files = dir.directoryEntries;
22
23 while (files.hasMoreElements()) {
24 let file = files.getNext().QueryInterface(Ci.nsIFile);
25
26 if (file.isHidden() ||
27 file.isSpecial() ||
28 file.equals(writer.file))
29 {
30 continue;
31 }
32
33 if (file.isDirectory()) {
34 writer.addEntryDirectory(basePath + file.leafName + "/",
35 file.lastModifiedTime * PR_USEC_PER_MSEC,
36 true);
37 addDirToZip(writer, file, basePath + file.leafName + "/");
38 } else {
39 writer.addEntryFile(basePath + file.leafName,
40 Ci.nsIZipWriter.COMPRESSION_DEFAULT,
41 file,
42 true);
43 }
44 }
45 }
46
47 /**
48 * Convert an XPConnect result code to its name and message.
49 * We have to extract them from an exception per bug 637307 comment 5.
50 */
51 function getResultTest(code) {
52 let regexp =
53 /^\[Exception... "(.*)" nsresult: "0x[0-9a-fA-F]* \((.*)\)" location: ".*" data: .*\]$/;
54 let ex = Cc["@mozilla.org/js/xpc/Exception;1"].
55 createInstance(Ci.nsIXPCException);
56 ex.initialize(null, code, null, null, null, null);
57 let [, message, name] = regexp.exec(ex.toString());
58 return { name: name, message: message };
59 }
60
61 function zipDirectory(zipFile, dirToArchive) {
62 let deferred = promise.defer();
63 let writer = Cc["@mozilla.org/zipwriter;1"].createInstance(Ci.nsIZipWriter);
64 writer.open(zipFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE);
65
66 this.addDirToZip(writer, dirToArchive, "");
67
68 writer.processQueue({
69 onStartRequest: function onStartRequest(request, context) {},
70 onStopRequest: (request, context, status) => {
71 if (status == Cr.NS_OK) {
72 writer.close();
73 deferred.resolve(zipFile);
74 }
75 else {
76 let { name, message } = getResultText(status);
77 deferred.reject(name + ": " + message);
78 }
79 }
80 }, null);
81
82 return deferred.promise;
83 }
84
85 function uploadPackage(client, webappsActor, packageFile) {
86 let deferred = promise.defer();
87
88 let request = {
89 to: webappsActor,
90 type: "uploadPackage"
91 };
92 client.request(request, (res) => {
93 openFile(res.actor);
94 });
95
96 function openFile(actor) {
97 OS.File.open(packageFile.path)
98 .then(function (file) {
99 uploadChunk(actor, file);
100 });
101 }
102 function uploadChunk(actor, file) {
103 file.read(CHUNK_SIZE)
104 .then(function (bytes) {
105 // To work around the fact that JSON.stringify translates the typed
106 // array to object, we are encoding the typed array here into a string
107 let chunk = String.fromCharCode.apply(null, bytes);
108
109 let request = {
110 to: actor,
111 type: "chunk",
112 chunk: chunk
113 };
114 client.request(request, (res) => {
115 if (bytes.length == CHUNK_SIZE) {
116 uploadChunk(actor, file);
117 } else {
118 file.close().then(function () {
119 endsUpload(actor);
120 });
121 }
122 });
123 });
124 }
125 function endsUpload(actor) {
126 let request = {
127 to: actor,
128 type: "done"
129 };
130 client.request(request, (res) => {
131 deferred.resolve(actor);
132 });
133 }
134 return deferred.promise;
135 }
136
137 function removeServerTemporaryFile(client, fileActor) {
138 let request = {
139 to: fileActor,
140 type: "remove"
141 };
142 client.request(request);
143 }
144
145 function installPackaged(client, webappsActor, packagePath, appId) {
146 let deferred = promise.defer();
147 let file = FileUtils.File(packagePath);
148 let packagePromise;
149 if (file.isDirectory()) {
150 let tmpZipFile = FileUtils.getDir("TmpD", [], true);
151 tmpZipFile.append("application.zip");
152 tmpZipFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("666", 8));
153 packagePromise = zipDirectory(tmpZipFile, file)
154 } else {
155 packagePromise = promise.resolve(file);
156 }
157 packagePromise.then((zipFile) => {
158 uploadPackage(client, webappsActor, zipFile)
159 .then((fileActor) => {
160 let request = {
161 to: webappsActor,
162 type: "install",
163 appId: appId,
164 upload: fileActor
165 };
166 client.request(request, (res) => {
167 // If the install method immediatly fails,
168 // reject immediatly the installPackaged promise.
169 // Otherwise, wait for webappsEvent for completion
170 if (res.error) {
171 deferred.reject(res);
172 }
173 if ("error" in res)
174 deferred.reject({error: res.error, message: res.message});
175 else
176 deferred.resolve({appId: res.appId});
177 });
178 // Ensure deleting the temporary package file, but only if that a temporary
179 // package created when we pass a directory as `packagePath`
180 if (zipFile != file)
181 zipFile.remove(false);
182 // In case of success or error, ensure deleting the temporary package file
183 // also created on the device, but only once install request is done
184 deferred.promise.then(
185 () => removeServerTemporaryFile(client, fileActor),
186 () => removeServerTemporaryFile(client, fileActor));
187 });
188 });
189 return deferred.promise;
190 }
191 exports.installPackaged = installPackaged;
192
193 function installHosted(client, webappsActor, appId, metadata, manifest) {
194 let deferred = promise.defer();
195 let request = {
196 to: webappsActor,
197 type: "install",
198 appId: appId,
199 metadata: metadata,
200 manifest: manifest
201 };
202 client.request(request, (res) => {
203 if (res.error) {
204 deferred.reject(res);
205 }
206 if ("error" in res)
207 deferred.reject({error: res.error, message: res.message});
208 else
209 deferred.resolve({appId: res.appId});
210 });
211 return deferred.promise;
212 }
213 exports.installHosted = installHosted;
214
215 function getTargetForApp(client, webappsActor, manifestURL) {
216 // Ensure always returning the exact same JS object for a target
217 // of the same app in order to show only one toolbox per app and
218 // avoid re-creating lot of objects twice.
219 let existingTarget = appTargets.get(manifestURL);
220 if (existingTarget)
221 return promise.resolve(existingTarget);
222
223 let deferred = promise.defer();
224 let request = {
225 to: webappsActor,
226 type: "getAppActor",
227 manifestURL: manifestURL,
228 }
229 client.request(request, (res) => {
230 if (res.error) {
231 deferred.reject(res.error);
232 } else {
233 let options = {
234 form: res.actor,
235 client: client,
236 chrome: false
237 };
238
239 devtools.TargetFactory.forRemoteTab(options).then((target) => {
240 target.isApp = true;
241 appTargets.set(manifestURL, target);
242 target.on("close", () => {
243 appTargets.delete(manifestURL);
244 });
245 deferred.resolve(target)
246 }, (error) => {
247 deferred.reject(error);
248 });
249 }
250 });
251 return deferred.promise;
252 }
253 exports.getTargetForApp = getTargetForApp;
254
255 function reloadApp(client, webappsActor, manifestURL) {
256 let deferred = promise.defer();
257 getTargetForApp(client,
258 webappsActor,
259 manifestURL).
260 then((target) => {
261 // Request the ContentActor to reload the app
262 let request = {
263 to: target.form.actor,
264 type: "reload",
265 manifestURL: manifestURL
266 };
267 client.request(request, (res) => {
268 deferred.resolve();
269 });
270 }, () => {
271 deferred.reject("Not running");
272 });
273 return deferred.promise;
274 }
275 exports.reloadApp = reloadApp;
276
277 function launchApp(client, webappsActor, manifestURL) {
278 let deferred = promise.defer();
279 let request = {
280 to: webappsActor,
281 type: "launch",
282 manifestURL: manifestURL
283 };
284 client.request(request, (res) => {
285 if (res.error) {
286 deferred.reject(res.error);
287 } else {
288 deferred.resolve(res);
289 }
290 });
291 return deferred.promise;
292 }
293 exports.launchApp = launchApp;
294
295 function closeApp(client, webappsActor, manifestURL) {
296 let deferred = promise.defer();
297 let request = {
298 to: webappsActor,
299 type: "close",
300 manifestURL: manifestURL
301 };
302 client.request(request, (res) => {
303 if (res.error) {
304 deferred.reject(res.error);
305 } else {
306 deferred.resolve(res);
307 }
308 });
309 return deferred.promise;
310 }
311 exports.closeApp = closeApp;

mercurial