浏览代码

Some progress on refactoring

Michelle Bu 12 年之前
父节点
当前提交
02d3a66094
共有 3 个文件被更改,包括 149 次插入199 次删除
  1. 7 0
      changelog.md
  2. 47 30
      lib/dataconnection.js
  3. 95 169
      lib/peer.js

+ 7 - 0
changelog.md

@@ -1,5 +1,12 @@
 # PeerJS Changelog
 
+## Version 0.3.0 (TBA)
+* Support for WebRTC video and audio streams.
+* **Deprecate the ability to assign labels to DataConnections.** They will
+  instead have a randomly-generated ID.
+* Add `util.supports.[FEATURE]` flags, which represent the WebRTC features
+  supported by your browser.
+
 ## Version 0.2.8 (1 July 2013)
 * Fix bug, no error on Firefox 24 due to missing error callback.
 * TLS secure PeerServers now supported.

+ 47 - 30
lib/dataconnection.js

@@ -142,33 +142,50 @@ DataConnection.prototype.send = function(data) {
   }
 };
 
-/**
- * Returns true if the DataConnection is open and able to send messages.
- */
-DataConnection.prototype.isOpen = function() {
-  return this.open;
-};
-
-/**
- * Gets the metadata associated with this DataConnection.
- */
-DataConnection.prototype.getMetadata = function() {
-  return this.metadata;
-};
-
-/**
- * Gets the label associated with this DataConnection.
- */
-DataConnection.prototype.getLabel = function() {
-  return this.label;
-};
-
-/**
- * Gets the brokering ID of the peer that you are connected with.
- * Note that this ID may be out of date if the peer has disconnected from the
- *  server, so it's not recommended that you use this ID to identify this
- *  connection.
- */
-DataConnection.prototype.getPeer = function() {
-  return this.peer;
-};
+DataConnection.prototype.handleMessage = function(message) {
+  var payload = message.payload;
+
+  switch (message.type) {
+    case 'OFFER':
+      var options = {
+        sdp: payload.sdp,
+        labels: payload.labels,
+        config: this.options.config
+      };
+      // Either forward to or create new manager
+
+      if (!manager) {
+        manager = this._createManager(managerId, peer, options);
+      }
+      manager.handleUpdate(options.labels);
+      manager.handleSDP(payload.sdp, message.type, payload.call);
+      break;
+    case 'EXPIRE':
+      peer.emit('error', new Error('Could not connect to peer ' + manager.peer));
+      break;
+    case 'ANSWER':
+      // Forward to specific manager
+      if (manager) {
+        manager.handleSDP(payload.sdp, message.type);
+      }
+      break;
+    case 'CANDIDATE':
+      // Forward to specific manager
+      if (manager) {
+        manager.handleCandidate(payload);
+      }
+      break;
+    case 'LEAVE':
+      // Leave on all managers for a user
+      if (this._managers[peer]) {
+        var ids = Object.keys(this._managers[peer].managers);
+        for (var i = 0; i < ids.length; i++) {
+          this._managers[peer].managers[ids[i]].handleLeave();
+        }
+      }
+      break;
+    default:
+      util.warn('Unrecognized message type:', message.type, 'from peer:', this.peer);
+      break;
+  }
+}

+ 95 - 169
lib/peer.js

@@ -63,22 +63,16 @@ function Peer(id, options) {
     return;
   }
   //
-  
+
   // States.
   this.destroyed = false; // Connections have been killed
   this.disconnected = false; // Connection to PeerServer killed but P2P connections still active
   //
-  
+
   // References
   this.connections = {}; // DataConnections for this peer.
   this.calls = {}; // MediaConnections for this peer
   //
-  
-  // Internal references
-  this._managers = {}; // Managers for peer connections
-  this._queued = []; // Queued connections to make.
-  //
-
 
   // Start the connections
   if (id) {
@@ -122,8 +116,8 @@ Peer.prototype._initialize = function(id) {
   var self = this;
   this.id = id;
   this.socket = new Socket(this.options.secure, this.options.host, this.options.port, this.options.key, this.id);
-  this.socket.on('message', function(data) {
-    self._dispatchMessage(data);
+  this.socket.on('server-message', function(data) {
+    self._handleMessage(data);
   });
   this.socket.on('error', function(error) {
     self._abort('socket-error', error);
@@ -135,172 +129,106 @@ Peer.prototype._initialize = function(id) {
   this.socket.start();
 }
 
-
-Peer.prototype._dispatchMessage = function(message) {
+/** Handles messages from the server. */
+Peer.prototype._handleMessage = function(message) {
   var type = message.type;
-  // Message types that don't involve a peer
+  var payload = message.payload
   switch (type) {
     case 'OPEN':
       this._processQueue();
       this.emit('open', this.id);
-      return;
+      break;
     case 'ERROR':
       this._abort('server-error', payload.msg);
-      return;
+      break;
     case 'ID-TAKEN':
-      this._abort('unavailable-id', 'ID `'+this.id+'` is taken');
-      return;
+      this._abort('unavailable-id', 'ID `' + this.id + '` is taken');
+      break;
     case 'INVALID-KEY':
       this._abort('invalid-key', 'API KEY "' + this._key + '" is invalid');
-      return;
-  }
-  
-  var peer = message.src;
-  var managerId = message.manager;
-  var manager = this._getManager(peer, managerId);
-  var payload = message.payload;
-  switch (message.type) {
-   
-    case 'OFFER':
-      var options = {
-        sdp: payload.sdp,
-        labels: payload.labels,
-        config: this.options.config
-      };
-      // Either forward to or create new manager
-      
-      if (!manager) {
-        manager = this._createManager(managerId, peer, options);
-      }
-      manager.handleUpdate(options.labels);
-      manager.handleSDP(payload.sdp, message.type, payload.call);
-      break;
-    case 'EXPIRE':
-      peer.emit('error', new Error('Could not connect to peer ' + manager.peer));
-      break;
-    case 'ANSWER':
-      // Forward to specific manager
-      if (manager) {
-        manager.handleSDP(payload.sdp, message.type);
-      }
       break;
-    case 'CANDIDATE':
-      // Forward to specific manager
-      if (manager) {
-        manager.handleCandidate(payload);
-      }
-      break;
-    case 'LEAVE':
-      // Leave on all managers for a user
-      if (this._managers[peer]) {
-        var ids = Object.keys(this._managers[peer].managers);
-        for (var i = 0; i < ids.length; i++) {
-          this._managers[peer].managers[ids[i]].handleLeave();
+    case 'OFFER': // we should consider switching this to CALL/CONNECT, but this is the least breaking option.
+      var peer = message.src;
+      var id = message.id;
+      var connection = this._getConnection(peer, id);
+
+      if (connection) {
+        // Pass it on
+        connection.handleMessage(message);
+      } else {
+        // Create a new connection.
+        if (payload.type === 'call') {
+          var call = new MediaConnection(peer, {
+            id: id,
+            offer: offer,
+            sdp: payload.sdp
+          });
+          this._addConnection(peer, call);
+          this.emit('call', call);
+        } else if (payload.type === 'connect') {
+          var connection = new DataConnection(peer, {
+            id: id,
+            offer: offer,
+            sdp: payload.sdp
+          });
+          this._addConnection(peer, connection);
+          this.emit('connection', connection);
+        } else {
+          util.warn('Received malformed connection type.');
         }
       }
       break;
     default:
-      util.warn('Unrecognized message type:', message.type);
-      break;
-  }
-};
-
-/** Process queued calls to connect. */
-Peer.prototype._processQueue = function() {
-  while (this._queued.length > 0) {
-    var manager = this._queued.pop();
-    manager.initialize(this.id, this.socket);
-  }
-};
-
-/** Listeners for manager. */
-Peer.prototype._attachManagerListeners = function(manager) {
-  var self = this;
-  // Handle receiving a connection.
-  manager.on('connection', function(connection) {
-    self._managers[manager.peer].dataManager = manager;
-    self.connections[connection.label] = connection;
-    self.emit('connection', connection);
-  });
-  // Handle receiving a call
-  manager.on('call', function(call) {
-    self.calls[call.label] = call;
-    self.emit('call', call);
-  });
-  // Handle a connection closing.
-  manager.on('close', function() {
-    if (!!self._managers[manager.peer]) {
-      delete self._managers[manager.peer];
-      // TODO: delete relevant calls and connections
-    }
-  });
-  manager.on('error', function(err) {
-    self.emit('error', err);
-  });
-};
-
+      var peer = message.src;
+      var id = message.id;
+      var connection = this._getConnection(peer, id);
 
-Peer.prototype._getManager = function(peer, managerId) {
-  if (this._managers[peer]) {
-    return this._managers[peer].managers[managerId];
+      if (connection) {
+        connection.handleMessage(message);
+      } else {
+        util.warn('You aborted your connection to ' + peer + ' before it opened.');
+      }
+      break;
   }
 }
 
-Peer.prototype._getDataManager = function(peer) {
-  if (this._managers[peer]) {
-    return this._managers[peer].dataManager;
-  }
+Peer.prototype.connect = function(peer, options) {
+  var connection = new DataConnection(peer, options);
+  this._addConnection(peer, connection);
+  return connection;
 }
 
-/** Exposed connect function for users. Will try to connect later if user
- * is waiting for an ID. */
-Peer.prototype._createManager = function(managerId, peer, options) {
-  if (this.disconnected) {
-    var err = new Error('This Peer has been disconnected from the server and can no longer make connections.');
-    err.type = 'server-disconnected';
-    this.emit('error', err);
+Peer.prototype.call = function(peer, stream, options) {
+  if (!stream) {
+    util.error('To call a peer, you must provide a stream from your browser\'s `getUserMedia`.');
     return;
   }
+  options.stream = stream;
+  var call = new MediaConnection(peer, options);
+  this._addConnection(peer, call);
+  return call;
+}
 
-  options = util.extend({
-    config: this.options.config
-  }, options);
-
-  if (!this._managers[peer]) {
-    this._managers[peer] = {nextId: 0, managers: {}};
-  }
-  
-  managerId = managerId || peer + this._managers[peer].nextId++;
-  
-  var manager = new ConnectionManager(managerId, peer, options);
-  if (!!this.id && !!this.socket) {
-    manager.initialize(this.id, this.socket);
-  } else {
-    this._queued.push(manager);
-  }
-  this._attachManagerListeners(manager);
-  this._managers[peer].managers[manager._managerId] = manager;
-
-  return manager;
-};
-
-Peer.prototype.connect = function(peer, options) {
-  var manager = this._getDataManager(peer);
-  if (!manager) {
-    manager = this._createManager(false, peer, options);
+Peer.prototype._addConnection = function(peer, connection) {
+  if (!this.connections[peer]) {
+    this.connections[peer] = [];
   }
-  var connection = manager.connect(options);
-  return connection;
+  this.connections[peer].push(connection);
 }
 
-Peer.prototype.call = function(peer, stream, options) {
-  var manager = this._createManager(false, peer, options);
-  var connection = manager.call(stream, options);
-  return connection;
+Peer.prototype._getConnection = function(peer, id) {
+  var connections = this.connections[peer];
+  if (!connections) {
+    return null;
+  }
+  for (var i = 0, ii = connections.length; i < ii; i++) {
+    if (connections[i].id === id) {
+      return connections[i];
+    }
+  }
+  return null;
 }
 
-
-
 Peer.prototype._delayedAbort = function(type, message) {
   var self = this;
   util.setZeroTimeout(function(){
@@ -326,28 +254,23 @@ Peer.prototype._abort = function(type, message) {
 Peer.prototype.destroy = function() {
   if (!this.destroyed) {
     this._cleanup();
+    this.disconnect();
     this.destroyed = true;
   }
-};
+}
 
 
-// TODO: UPDATE
+/* Disconnects every connection on this peer. */
 Peer.prototype._cleanup = function() {
-  var self = this;
-  if (!!this._managers) {
-    var peers = Object.keys(this._managers);
-    for (var i = 0, ii = peers.length; i < ii; i++) {
-      var ids = Object.keys(this._managers[peers[i]]);
-      for (var j = 0, jj = peers.length; j < jj; j++) {
-        this._managers[peers[i]][ids[j]].close();
-      }
+  var peers = Object.keys(this.connections);
+  for (var i = 0, ii = peers.length; i < ii; i++) {
+    var connections = this.connections[peers[i]];
+    for (var j = 0, jj = connections; j < jj; j++) {
+      connections[j].close();
     }
   }
-  util.setZeroTimeout(function(){
-    self.disconnect();
-  });
   this.emit('close');
-};
+}
 
 /**
  * Disconnects the Peer's connection to the PeerServer. Does not close any
@@ -356,17 +279,20 @@ Peer.prototype._cleanup = function() {
  *  disconnected. It also cannot reconnect to the server.
  */
 Peer.prototype.disconnect = function() {
-  if (!this.disconnected) {
-    if (!!this.socket) {
-      this.socket.close();
+  var self = this;
+  util.setZeroTimeout(function(){
+    if (!self.disconnected) {
+      if (self.socket) {
+        self.socket.close();
+      }
+      self.id = null;
+      self.disconnected = true;
     }
-    this.id = null;
-    this.disconnected = true;
-  }
-};
+  });
+}
 
 /** The current browser. */
+// TODO: maybe expose util.supports
 Peer.browser = util.browserisms;
 
-
 exports.Peer = Peer;