michael@0: /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; michael@0: michael@0: const CONNECTION_STATUS_DISCONNECTED = "disconnected"; michael@0: const CONNECTION_STATUS_CONNECTING = "connecting"; michael@0: const CONNECTION_STATUS_CONNECTED = "connected"; michael@0: const CONNECTION_STATUS_DISCONNECTING = "disconnecting"; michael@0: michael@0: const DEBUG = false; michael@0: michael@0: this.EXPORTED_SYMBOLS = ["WifiP2pWorkerObserver"]; michael@0: michael@0: // WifiP2pWorkerObserver resides in WifiWorker to handle DOM message michael@0: // by either 1) returning internally maintained information or michael@0: // 2) delegating to aDomMsgResponder. It is also responsible michael@0: // for observing events from WifiP2pManager and dispatch to DOM. michael@0: // michael@0: // @param aDomMsgResponder handles DOM messages, including michael@0: // - setScanEnabled michael@0: // - connect michael@0: // - disconnect michael@0: // - setPairingConfirmation michael@0: // The instance is actually WifiP2pManager. michael@0: this.WifiP2pWorkerObserver = function(aDomMsgResponder) { michael@0: function debug(aMsg) { michael@0: if (DEBUG) { michael@0: dump('-------------- WifiP2pWorkerObserver: ' + aMsg); michael@0: } michael@0: } michael@0: michael@0: // Private member variables. michael@0: let _localDevice; michael@0: let _peerList = {}; // List of P2pDevice. michael@0: let _domManagers = []; michael@0: michael@0: // Constructor of P2pDevice. It will be exposed to DOM. michael@0: // michael@0: // @param aPeer object representing a P2P device: michael@0: // .name: string for the device name. michael@0: // .address: Mac address. michael@0: // .isGroupOwner: boolean to indicate if this device is the group owner. michael@0: // .wpsCapabilities: array of string of {"pbc", "display", "keypad"}. michael@0: function P2pDevice(aPeer) { michael@0: this.address = aPeer.address; michael@0: this.name = (aPeer.name ? aPeer.name : aPeer.address); michael@0: this.isGroupOwner = aPeer.isGroupOwner; michael@0: this.wpsCapabilities = aPeer.wpsCapabilities; michael@0: this.connectionStatus = CONNECTION_STATUS_DISCONNECTED; michael@0: michael@0: // Since this object will be exposed to web, defined the exposed michael@0: // properties here. michael@0: this.__exposedProps__ = { michael@0: address: "r", michael@0: name: "r", michael@0: isGroupOwner: "r", michael@0: wpsCapabilities: "r", michael@0: connectionStatus: "r" michael@0: }; michael@0: } michael@0: michael@0: // Constructor of P2pGroupOwner. michael@0: // michael@0: // @param aGroupOwner: michael@0: // .macAddress michael@0: // .ipAddress michael@0: // .passphrase michael@0: // .ssid michael@0: // .freq michael@0: // .isLocal michael@0: function P2pGroupOwner(aGroupOwner) { michael@0: this.macAddress = aGroupOwner.macAddress; // The identifier to get further information. michael@0: this.ipAddress = aGroupOwner.ipAddress; michael@0: this.passphrase = aGroupOwner.passphrase; michael@0: this.ssid = aGroupOwner.ssid; // e.g. DIRECT-xy. michael@0: this.freq = aGroupOwner.freq; michael@0: this.isLocal = aGroupOwner.isLocal; michael@0: michael@0: let detail = _peerList[aGroupOwner.macAddress]; michael@0: if (detail) { michael@0: this.name = detail.name; michael@0: this.wpsCapabilities = detail.wpsCapabilities; michael@0: } else if (_localDevice.address === this.macAddress) { michael@0: this.name = _localDevice.name; michael@0: this.wpsCapabilities = _localDevice.wpsCapabilities; michael@0: } else { michael@0: debug("We don't know this group owner: " + aGroupOwner.macAddress); michael@0: this.name = aGroupOwner.macAddress; michael@0: this.wpsCapabilities = []; michael@0: } michael@0: } michael@0: michael@0: function fireEvent(aMessage, aData) { michael@0: debug('domManager: ' + JSON.stringify(_domManagers)); michael@0: _domManagers.forEach(function(manager) { michael@0: // Note: We should never have a dead message manager here because we michael@0: // observe our child message managers shutting down below. michael@0: manager.sendAsyncMessage("WifiP2pManager:" + aMessage, aData); michael@0: }); michael@0: } michael@0: michael@0: function addDomManager(aMsg) { michael@0: if (-1 === _domManagers.indexOf(aMsg.manager)) { michael@0: _domManagers.push(aMsg.manager); michael@0: } michael@0: } michael@0: michael@0: function returnMessage(aMessage, aSuccess, aData, aMsg) { michael@0: let rMsg = aMessage + ":Return:" + (aSuccess ? "OK" : "NO"); michael@0: aMsg.manager.sendAsyncMessage(rMsg, michael@0: { data: aData, rid: aMsg.rid, mid: aMsg.mid }); michael@0: } michael@0: michael@0: function handlePeerListUpdated() { michael@0: fireEvent("onpeerinfoupdate", {}); michael@0: } michael@0: michael@0: // Return a literal object as the constructed object. michael@0: return { michael@0: onLocalDeviceChanged: function(aDevice) { michael@0: _localDevice = aDevice; michael@0: debug('Local device updated to: ' + JSON.stringify(_localDevice)); michael@0: }, michael@0: michael@0: onEnabled: function() { michael@0: _peerList = []; michael@0: fireEvent("p2pUp", {}); michael@0: }, michael@0: michael@0: onDisbaled: function() { michael@0: fireEvent("p2pDown", {}); michael@0: }, michael@0: michael@0: onPeerFound: function(aPeer) { michael@0: let newFoundPeer = new P2pDevice(aPeer); michael@0: let origianlPeer = _peerList[aPeer.address]; michael@0: _peerList[aPeer.address] = newFoundPeer; michael@0: if (origianlPeer) { michael@0: newFoundPeer.connectionStatus = origianlPeer.connectionStatus; michael@0: } michael@0: handlePeerListUpdated(); michael@0: }, michael@0: michael@0: onPeerLost: function(aPeer) { michael@0: let lostPeer = _peerList[aPeer.address]; michael@0: if (!lostPeer) { michael@0: debug('Unknown peer lost: ' + aPeer.address); michael@0: return; michael@0: } michael@0: delete _peerList[aPeer.address]; michael@0: handlePeerListUpdated(); michael@0: }, michael@0: michael@0: onConnecting: function(aPeer) { michael@0: let peer = _peerList[aPeer.address]; michael@0: if (!peer) { michael@0: debug('Unknown peer connecting: ' + aPeer.address); michael@0: peer = new P2pDevice(aPeer); michael@0: _peerList[aPeer.address] = peer; michael@0: handlePeerListUpdated(); michael@0: } michael@0: peer.connectionStatus = CONNECTION_STATUS_CONNECTING; michael@0: michael@0: fireEvent('onconnecting', { peer: peer }); michael@0: }, michael@0: michael@0: onConnected: function(aGroupOwner, aPeer) { michael@0: let go = new P2pGroupOwner(aGroupOwner); michael@0: let peer = _peerList[aPeer.address]; michael@0: if (!peer) { michael@0: debug('Unknown peer connected: ' + aPeer.address); michael@0: peer = new P2pDevice(aPeer); michael@0: _peerList[aPeer.address] = peer; michael@0: handlePeerListUpdated(); michael@0: } michael@0: peer.connectionStatus = CONNECTION_STATUS_CONNECTED; michael@0: peer.isGroupOwner = (aPeer.address === aGroupOwner.address); michael@0: michael@0: fireEvent('onconnected', { groupOwner: go, peer: peer }); michael@0: }, michael@0: michael@0: onDisconnected: function(aPeer) { michael@0: let peer = _peerList[aPeer.address]; michael@0: if (!peer) { michael@0: debug('Unknown peer disconnected: ' + aPeer.address); michael@0: return; michael@0: } michael@0: michael@0: peer.connectionStatus = CONNECTION_STATUS_DISCONNECTED; michael@0: fireEvent('ondisconnected', { peer: peer }); michael@0: }, michael@0: michael@0: getObservedDOMMessages: function() { michael@0: return [ michael@0: "WifiP2pManager:getState", michael@0: "WifiP2pManager:getPeerList", michael@0: "WifiP2pManager:setScanEnabled", michael@0: "WifiP2pManager:connect", michael@0: "WifiP2pManager:disconnect", michael@0: "WifiP2pManager:setPairingConfirmation", michael@0: "WifiP2pManager:setDeviceName" michael@0: ]; michael@0: }, michael@0: michael@0: onDOMMessage: function(aMessage) { michael@0: let msg = aMessage.data || {}; michael@0: msg.manager = aMessage.target; michael@0: michael@0: if ("child-process-shutdown" === aMessage.name) { michael@0: let i; michael@0: if (-1 !== (i = _domManagers.indexOf(msg.manager))) { michael@0: _domManagers.splice(i, 1); michael@0: } michael@0: return; michael@0: } michael@0: michael@0: if (!aMessage.target.assertPermission("wifi-manage")) { michael@0: return; michael@0: } michael@0: michael@0: switch (aMessage.name) { michael@0: case "WifiP2pManager:getState": // A new DOM manager is created. michael@0: addDomManager(msg); michael@0: return { peerList: _peerList, }; // Synchronous call. Simply return it. michael@0: michael@0: case "WifiP2pManager:setScanEnabled": michael@0: { michael@0: let enabled = msg.data; michael@0: michael@0: aDomMsgResponder.setScanEnabled(enabled, function(success) { michael@0: returnMessage(aMessage.name, success, (success ? true : "ERROR"), msg); michael@0: }); michael@0: } michael@0: break; michael@0: michael@0: case "WifiP2pManager:getPeerList": michael@0: { michael@0: // Convert the object to an array. michael@0: let peerArray = []; michael@0: for (let key in _peerList) { michael@0: if (_peerList.hasOwnProperty(key)) { michael@0: peerArray.push(_peerList[key]); michael@0: } michael@0: } michael@0: michael@0: returnMessage(aMessage.name, true, peerArray, msg); michael@0: } michael@0: break; michael@0: michael@0: case "WifiP2pManager:connect": michael@0: { michael@0: let peer = msg.data; michael@0: michael@0: let onDoConnect = function(success) { michael@0: returnMessage(aMessage.name, success, (success ? true : "ERROR"), msg); michael@0: }; michael@0: michael@0: aDomMsgResponder.connect(peer.address, peer.wpsMethod, michael@0: peer.goIntent, onDoConnect); michael@0: } michael@0: break; michael@0: michael@0: case "WifiP2pManager:disconnect": michael@0: { michael@0: let address = msg.data; michael@0: michael@0: aDomMsgResponder.disconnect(address, function(success) { michael@0: returnMessage(aMessage.name, success, (success ? true : "ERROR"), msg); michael@0: }); michael@0: } michael@0: break; michael@0: michael@0: case "WifiP2pManager:setPairingConfirmation": michael@0: { michael@0: let result = msg.data; michael@0: aDomMsgResponder.setPairingConfirmation(result); michael@0: returnMessage(aMessage.name, true, true, msg); michael@0: } michael@0: break; michael@0: michael@0: case "WifiP2pManager:setDeviceName": michael@0: { michael@0: let newDeviceName = msg.data; michael@0: aDomMsgResponder.setDeviceName(newDeviceName, function(success) { michael@0: returnMessage(aMessage.name, success, (success ? true : "ERROR"), msg); michael@0: }); michael@0: } michael@0: break; michael@0: michael@0: default: michael@0: if (0 === aMessage.name.indexOf("WifiP2pManager:")) { michael@0: debug("DOM WifiP2pManager message not handled: " + aMessage.name); michael@0: } michael@0: } // End of switch. michael@0: } michael@0: }; michael@0: };