1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/components/social/WorkerAPI.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,151 @@ 1.4 +/* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +"use strict"; 1.11 + 1.12 +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; 1.13 +Cu.import("resource://gre/modules/Services.jsm"); 1.14 +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 1.15 + 1.16 +XPCOMUtils.defineLazyModuleGetter(this, "getFrameWorkerHandle", "resource://gre/modules/FrameWorker.jsm"); 1.17 +XPCOMUtils.defineLazyModuleGetter(this, "openChatWindow", "resource://gre/modules/MozSocialAPI.jsm"); 1.18 + 1.19 +this.EXPORTED_SYMBOLS = ["WorkerAPI"]; 1.20 + 1.21 +this.WorkerAPI = function WorkerAPI(provider, port) { 1.22 + if (!port) 1.23 + throw new Error("Can't initialize WorkerAPI with a null port"); 1.24 + 1.25 + this._provider = provider; 1.26 + this._port = port; 1.27 + this._port.onmessage = this._handleMessage.bind(this); 1.28 + 1.29 + // Send an "intro" message so the worker knows this is the port 1.30 + // used for the api. 1.31 + // later we might even include an API version - version 0 for now! 1.32 + this._port.postMessage({topic: "social.initialize"}); 1.33 +} 1.34 + 1.35 +WorkerAPI.prototype = { 1.36 + terminate: function terminate() { 1.37 + this._port.close(); 1.38 + }, 1.39 + 1.40 + _handleMessage: function _handleMessage(event) { 1.41 + let {topic, data} = event.data; 1.42 + let handler = this.handlers[topic]; 1.43 + if (!handler) { 1.44 + Cu.reportError("WorkerAPI: topic doesn't have a handler: '" + topic + "'"); 1.45 + return; 1.46 + } 1.47 + try { 1.48 + handler.call(this, data); 1.49 + } catch (ex) { 1.50 + Cu.reportError("WorkerAPI: failed to handle message '" + topic + "': " + ex + "\n" + ex.stack); 1.51 + } 1.52 + }, 1.53 + 1.54 + handlers: { 1.55 + "social.manifest-get": function(data) { 1.56 + // retreive the currently installed manifest from firefox 1.57 + this._port.postMessage({topic: "social.manifest", data: this._provider.manifest}); 1.58 + }, 1.59 + "social.manifest-set": function(data) { 1.60 + // the provider will get reloaded as a result of this call 1.61 + let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService; 1.62 + let origin = this._provider.origin; 1.63 + SocialService.updateProvider(origin, data); 1.64 + }, 1.65 + "social.reload-worker": function(data) { 1.66 + this._provider.reload(); 1.67 + }, 1.68 + "social.user-profile": function (data) { 1.69 + this._provider.updateUserProfile(data); 1.70 + }, 1.71 + "social.ambient-notification": function (data) { 1.72 + this._provider.setAmbientNotification(data); 1.73 + }, 1.74 + "social.cookies-get": function(data) { 1.75 + // We don't want to trust provider.origin etc, just incase the provider 1.76 + // redirected away or something else bad is going on. So we want to 1.77 + // reach into the Worker's document and fetch the actual cookies it has. 1.78 + // We need to do this via our own message dance. 1.79 + let port = this._port; 1.80 + let whandle = getFrameWorkerHandle(this._provider.workerURL, null); 1.81 + whandle.port.close(); 1.82 + whandle._worker.browserPromise.then(browser => { 1.83 + let mm = browser.messageManager; 1.84 + mm.addMessageListener("frameworker:cookie-get-response", function _onCookieResponse(msg) { 1.85 + mm.removeMessageListener("frameworker:cookie-get-response", _onCookieResponse); 1.86 + let cookies = msg.json.split(";"); 1.87 + let results = []; 1.88 + cookies.forEach(function(aCookie) { 1.89 + let [name, value] = aCookie.split("="); 1.90 + if (name || value) { 1.91 + results.push({name: unescape(name.trim()), 1.92 + value: value ? unescape(value.trim()) : ""}); 1.93 + } 1.94 + }); 1.95 + port.postMessage({topic: "social.cookies-get-response", 1.96 + data: results}); 1.97 + }); 1.98 + mm.sendAsyncMessage("frameworker:cookie-get"); 1.99 + }); 1.100 + }, 1.101 + 'social.request-chat': function(data) { 1.102 + openChatWindow(null, this._provider, data); 1.103 + }, 1.104 + 'social.notification-create': function(data) { 1.105 + if (!Services.prefs.getBoolPref("social.toast-notifications.enabled")) 1.106 + return; 1.107 + 1.108 + let port = this._port; 1.109 + let provider = this._provider; 1.110 + let {id, type, icon, body, action, actionArgs} = data; 1.111 + let alertsService = Cc["@mozilla.org/alerts-service;1"] 1.112 + .getService(Ci.nsIAlertsService); 1.113 + function listener(subject, topic, data) { 1.114 + if (topic === "alertclickcallback") { 1.115 + // we always post back the click 1.116 + port.postMessage({topic: "social.notification-action", 1.117 + data: {id: id, 1.118 + action: action, 1.119 + actionArgs: actionArgs}}); 1.120 + switch (action) { 1.121 + case "link": 1.122 + // if there is a url, make it open a tab 1.123 + if (actionArgs.toURL) { 1.124 + let uriToOpen = provider.resolveUri(actionArgs.toURL); 1.125 + // Bug 815970 - facebook gives us http:// links even though 1.126 + // the origin is https:// - so we perform a fixup here. 1.127 + let pUri = Services.io.newURI(provider.origin, null, null); 1.128 + if (uriToOpen.scheme != pUri.scheme) 1.129 + uriToOpen.scheme = pUri.scheme; 1.130 + if (provider.isSameOrigin(uriToOpen)) { 1.131 + let xulWindow = Services.wm.getMostRecentWindow("navigator:browser"); 1.132 + xulWindow.openUILinkIn(uriToOpen.spec, "tab"); 1.133 + } else { 1.134 + Cu.reportError("Not opening notification link " + actionArgs.toURL 1.135 + + " as not in provider origin"); 1.136 + } 1.137 + } 1.138 + break; 1.139 + default: 1.140 + break; 1.141 + } 1.142 + } 1.143 + } 1.144 + alertsService.showAlertNotification(icon, 1.145 + this._provider.name, // title 1.146 + body, 1.147 + !!action, // text clickable if an 1.148 + // action was provided. 1.149 + null, 1.150 + listener, 1.151 + type); 1.152 + }, 1.153 + } 1.154 +}