dom/wifi/WifiP2pWorkerObserver.jsm

changeset 0
6474c204b198
     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 +};

mercurial