gecko/dom/wifi/WifiP2pWorkerObserver.jsm

320 lines
9.6 KiB
JavaScript

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