1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/wifi/WifiP2pWorkerObserver.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,303 @@ 1.4 +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ 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 file, 1.8 + * 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, results: Cr} = Components; 1.13 + 1.14 +const CONNECTION_STATUS_DISCONNECTED = "disconnected"; 1.15 +const CONNECTION_STATUS_CONNECTING = "connecting"; 1.16 +const CONNECTION_STATUS_CONNECTED = "connected"; 1.17 +const CONNECTION_STATUS_DISCONNECTING = "disconnecting"; 1.18 + 1.19 +const DEBUG = false; 1.20 + 1.21 +this.EXPORTED_SYMBOLS = ["WifiP2pWorkerObserver"]; 1.22 + 1.23 +// WifiP2pWorkerObserver resides in WifiWorker to handle DOM message 1.24 +// by either 1) returning internally maintained information or 1.25 +// 2) delegating to aDomMsgResponder. It is also responsible 1.26 +// for observing events from WifiP2pManager and dispatch to DOM. 1.27 +// 1.28 +// @param aDomMsgResponder handles DOM messages, including 1.29 +// - setScanEnabled 1.30 +// - connect 1.31 +// - disconnect 1.32 +// - setPairingConfirmation 1.33 +// The instance is actually WifiP2pManager. 1.34 +this.WifiP2pWorkerObserver = function(aDomMsgResponder) { 1.35 + function debug(aMsg) { 1.36 + if (DEBUG) { 1.37 + dump('-------------- WifiP2pWorkerObserver: ' + aMsg); 1.38 + } 1.39 + } 1.40 + 1.41 + // Private member variables. 1.42 + let _localDevice; 1.43 + let _peerList = {}; // List of P2pDevice. 1.44 + let _domManagers = []; 1.45 + 1.46 + // Constructor of P2pDevice. It will be exposed to DOM. 1.47 + // 1.48 + // @param aPeer object representing a P2P device: 1.49 + // .name: string for the device name. 1.50 + // .address: Mac address. 1.51 + // .isGroupOwner: boolean to indicate if this device is the group owner. 1.52 + // .wpsCapabilities: array of string of {"pbc", "display", "keypad"}. 1.53 + function P2pDevice(aPeer) { 1.54 + this.address = aPeer.address; 1.55 + this.name = (aPeer.name ? aPeer.name : aPeer.address); 1.56 + this.isGroupOwner = aPeer.isGroupOwner; 1.57 + this.wpsCapabilities = aPeer.wpsCapabilities; 1.58 + this.connectionStatus = CONNECTION_STATUS_DISCONNECTED; 1.59 + 1.60 + // Since this object will be exposed to web, defined the exposed 1.61 + // properties here. 1.62 + this.__exposedProps__ = { 1.63 + address: "r", 1.64 + name: "r", 1.65 + isGroupOwner: "r", 1.66 + wpsCapabilities: "r", 1.67 + connectionStatus: "r" 1.68 + }; 1.69 + } 1.70 + 1.71 + // Constructor of P2pGroupOwner. 1.72 + // 1.73 + // @param aGroupOwner: 1.74 + // .macAddress 1.75 + // .ipAddress 1.76 + // .passphrase 1.77 + // .ssid 1.78 + // .freq 1.79 + // .isLocal 1.80 + function P2pGroupOwner(aGroupOwner) { 1.81 + this.macAddress = aGroupOwner.macAddress; // The identifier to get further information. 1.82 + this.ipAddress = aGroupOwner.ipAddress; 1.83 + this.passphrase = aGroupOwner.passphrase; 1.84 + this.ssid = aGroupOwner.ssid; // e.g. DIRECT-xy. 1.85 + this.freq = aGroupOwner.freq; 1.86 + this.isLocal = aGroupOwner.isLocal; 1.87 + 1.88 + let detail = _peerList[aGroupOwner.macAddress]; 1.89 + if (detail) { 1.90 + this.name = detail.name; 1.91 + this.wpsCapabilities = detail.wpsCapabilities; 1.92 + } else if (_localDevice.address === this.macAddress) { 1.93 + this.name = _localDevice.name; 1.94 + this.wpsCapabilities = _localDevice.wpsCapabilities; 1.95 + } else { 1.96 + debug("We don't know this group owner: " + aGroupOwner.macAddress); 1.97 + this.name = aGroupOwner.macAddress; 1.98 + this.wpsCapabilities = []; 1.99 + } 1.100 + } 1.101 + 1.102 + function fireEvent(aMessage, aData) { 1.103 + debug('domManager: ' + JSON.stringify(_domManagers)); 1.104 + _domManagers.forEach(function(manager) { 1.105 + // Note: We should never have a dead message manager here because we 1.106 + // observe our child message managers shutting down below. 1.107 + manager.sendAsyncMessage("WifiP2pManager:" + aMessage, aData); 1.108 + }); 1.109 + } 1.110 + 1.111 + function addDomManager(aMsg) { 1.112 + if (-1 === _domManagers.indexOf(aMsg.manager)) { 1.113 + _domManagers.push(aMsg.manager); 1.114 + } 1.115 + } 1.116 + 1.117 + function returnMessage(aMessage, aSuccess, aData, aMsg) { 1.118 + let rMsg = aMessage + ":Return:" + (aSuccess ? "OK" : "NO"); 1.119 + aMsg.manager.sendAsyncMessage(rMsg, 1.120 + { data: aData, rid: aMsg.rid, mid: aMsg.mid }); 1.121 + } 1.122 + 1.123 + function handlePeerListUpdated() { 1.124 + fireEvent("onpeerinfoupdate", {}); 1.125 + } 1.126 + 1.127 + // Return a literal object as the constructed object. 1.128 + return { 1.129 + onLocalDeviceChanged: function(aDevice) { 1.130 + _localDevice = aDevice; 1.131 + debug('Local device updated to: ' + JSON.stringify(_localDevice)); 1.132 + }, 1.133 + 1.134 + onEnabled: function() { 1.135 + _peerList = []; 1.136 + fireEvent("p2pUp", {}); 1.137 + }, 1.138 + 1.139 + onDisbaled: function() { 1.140 + fireEvent("p2pDown", {}); 1.141 + }, 1.142 + 1.143 + onPeerFound: function(aPeer) { 1.144 + let newFoundPeer = new P2pDevice(aPeer); 1.145 + let origianlPeer = _peerList[aPeer.address]; 1.146 + _peerList[aPeer.address] = newFoundPeer; 1.147 + if (origianlPeer) { 1.148 + newFoundPeer.connectionStatus = origianlPeer.connectionStatus; 1.149 + } 1.150 + handlePeerListUpdated(); 1.151 + }, 1.152 + 1.153 + onPeerLost: function(aPeer) { 1.154 + let lostPeer = _peerList[aPeer.address]; 1.155 + if (!lostPeer) { 1.156 + debug('Unknown peer lost: ' + aPeer.address); 1.157 + return; 1.158 + } 1.159 + delete _peerList[aPeer.address]; 1.160 + handlePeerListUpdated(); 1.161 + }, 1.162 + 1.163 + onConnecting: function(aPeer) { 1.164 + let peer = _peerList[aPeer.address]; 1.165 + if (!peer) { 1.166 + debug('Unknown peer connecting: ' + aPeer.address); 1.167 + peer = new P2pDevice(aPeer); 1.168 + _peerList[aPeer.address] = peer; 1.169 + handlePeerListUpdated(); 1.170 + } 1.171 + peer.connectionStatus = CONNECTION_STATUS_CONNECTING; 1.172 + 1.173 + fireEvent('onconnecting', { peer: peer }); 1.174 + }, 1.175 + 1.176 + onConnected: function(aGroupOwner, aPeer) { 1.177 + let go = new P2pGroupOwner(aGroupOwner); 1.178 + let peer = _peerList[aPeer.address]; 1.179 + if (!peer) { 1.180 + debug('Unknown peer connected: ' + aPeer.address); 1.181 + peer = new P2pDevice(aPeer); 1.182 + _peerList[aPeer.address] = peer; 1.183 + handlePeerListUpdated(); 1.184 + } 1.185 + peer.connectionStatus = CONNECTION_STATUS_CONNECTED; 1.186 + peer.isGroupOwner = (aPeer.address === aGroupOwner.address); 1.187 + 1.188 + fireEvent('onconnected', { groupOwner: go, peer: peer }); 1.189 + }, 1.190 + 1.191 + onDisconnected: function(aPeer) { 1.192 + let peer = _peerList[aPeer.address]; 1.193 + if (!peer) { 1.194 + debug('Unknown peer disconnected: ' + aPeer.address); 1.195 + return; 1.196 + } 1.197 + 1.198 + peer.connectionStatus = CONNECTION_STATUS_DISCONNECTED; 1.199 + fireEvent('ondisconnected', { peer: peer }); 1.200 + }, 1.201 + 1.202 + getObservedDOMMessages: function() { 1.203 + return [ 1.204 + "WifiP2pManager:getState", 1.205 + "WifiP2pManager:getPeerList", 1.206 + "WifiP2pManager:setScanEnabled", 1.207 + "WifiP2pManager:connect", 1.208 + "WifiP2pManager:disconnect", 1.209 + "WifiP2pManager:setPairingConfirmation", 1.210 + "WifiP2pManager:setDeviceName" 1.211 + ]; 1.212 + }, 1.213 + 1.214 + onDOMMessage: function(aMessage) { 1.215 + let msg = aMessage.data || {}; 1.216 + msg.manager = aMessage.target; 1.217 + 1.218 + if ("child-process-shutdown" === aMessage.name) { 1.219 + let i; 1.220 + if (-1 !== (i = _domManagers.indexOf(msg.manager))) { 1.221 + _domManagers.splice(i, 1); 1.222 + } 1.223 + return; 1.224 + } 1.225 + 1.226 + if (!aMessage.target.assertPermission("wifi-manage")) { 1.227 + return; 1.228 + } 1.229 + 1.230 + switch (aMessage.name) { 1.231 + case "WifiP2pManager:getState": // A new DOM manager is created. 1.232 + addDomManager(msg); 1.233 + return { peerList: _peerList, }; // Synchronous call. Simply return it. 1.234 + 1.235 + case "WifiP2pManager:setScanEnabled": 1.236 + { 1.237 + let enabled = msg.data; 1.238 + 1.239 + aDomMsgResponder.setScanEnabled(enabled, function(success) { 1.240 + returnMessage(aMessage.name, success, (success ? true : "ERROR"), msg); 1.241 + }); 1.242 + } 1.243 + break; 1.244 + 1.245 + case "WifiP2pManager:getPeerList": 1.246 + { 1.247 + // Convert the object to an array. 1.248 + let peerArray = []; 1.249 + for (let key in _peerList) { 1.250 + if (_peerList.hasOwnProperty(key)) { 1.251 + peerArray.push(_peerList[key]); 1.252 + } 1.253 + } 1.254 + 1.255 + returnMessage(aMessage.name, true, peerArray, msg); 1.256 + } 1.257 + break; 1.258 + 1.259 + case "WifiP2pManager:connect": 1.260 + { 1.261 + let peer = msg.data; 1.262 + 1.263 + let onDoConnect = function(success) { 1.264 + returnMessage(aMessage.name, success, (success ? true : "ERROR"), msg); 1.265 + }; 1.266 + 1.267 + aDomMsgResponder.connect(peer.address, peer.wpsMethod, 1.268 + peer.goIntent, onDoConnect); 1.269 + } 1.270 + break; 1.271 + 1.272 + case "WifiP2pManager:disconnect": 1.273 + { 1.274 + let address = msg.data; 1.275 + 1.276 + aDomMsgResponder.disconnect(address, function(success) { 1.277 + returnMessage(aMessage.name, success, (success ? true : "ERROR"), msg); 1.278 + }); 1.279 + } 1.280 + break; 1.281 + 1.282 + case "WifiP2pManager:setPairingConfirmation": 1.283 + { 1.284 + let result = msg.data; 1.285 + aDomMsgResponder.setPairingConfirmation(result); 1.286 + returnMessage(aMessage.name, true, true, msg); 1.287 + } 1.288 + break; 1.289 + 1.290 + case "WifiP2pManager:setDeviceName": 1.291 + { 1.292 + let newDeviceName = msg.data; 1.293 + aDomMsgResponder.setDeviceName(newDeviceName, function(success) { 1.294 + returnMessage(aMessage.name, success, (success ? true : "ERROR"), msg); 1.295 + }); 1.296 + } 1.297 + break; 1.298 + 1.299 + default: 1.300 + if (0 === aMessage.name.indexOf("WifiP2pManager:")) { 1.301 + debug("DOM WifiP2pManager message not handled: " + aMessage.name); 1.302 + } 1.303 + } // End of switch. 1.304 + } 1.305 + }; 1.306 +};