Selaa lähdekoodia

surface working

Michelle Bu 12 vuotta sitten
vanhempi
commit
57f819b7ca
5 muutettua tiedostoa jossa 267 lisäystä ja 602 poistoa
  1. 1 1
      bin/build.js
  2. 262 279
      dist/peer.js
  3. 0 0
      dist/peer.min.js
  4. 0 320
      lib/connection.js
  5. 4 2
      lib/connectionmanager.js

+ 1 - 1
bin/build.js

@@ -45,7 +45,7 @@ var base = [
   , '../deps/reliable/lib/reliable.js'
   , 'adapter.js' 
   , 'peer.js'
-  , 'connection.js'
+  , 'dataconnection.js'
   , 'connectionmanager.js'
   , 'socket.js'
 

+ 262 - 279
dist/peer.js

@@ -1178,6 +1178,8 @@ function Peer(id, options) {
 
   // Connections for this peer.
   this.connections = {};
+  // Connection managers.
+  this.managers = {};
 
   // Queued connections to make.
   this._queued = [];
@@ -1236,7 +1238,7 @@ Peer.prototype._init = function() {
 
 Peer.prototype._handleServerJSONMessage = function(message) {
   var peer = message.src;
-  var connection = this.connections[peer];
+  var manager = this.managers[peer];
   var payload = message.payload;
   switch (message.type) {
     case 'OPEN':
@@ -1258,31 +1260,36 @@ Peer.prototype._handleServerJSONMessage = function(message) {
         reliable: payload.reliable,
         config: this._options.config
       };
-      var connection = new DataConnection(this.id, peer, this._socket, options);
-      this._attachConnectionListeners(connection);
-      this.connections[peer] = connection;
-      this.emit('connection', connection, payload.metadata);
+
+      var manager = this.managers[peer];
+      if (!!manager) {
+        manager = new ConnectionManager(this.id, peer, this._socket, options);
+        this._attachManagerListeners(manager);
+        this.managers[peer] = manager;
+        this.connections[peer] = {};
+      }
+      // MOVE THIS TO ONDATACHANNEL
+      //this.emit('connection', connection, payload.metadata);
       break;
     case 'EXPIRE':
-      connection = this.connections[peer];
-      if (connection) {
-        connection.close();
-        connection.emit('error', new Error('Could not connect to peer ' + connection.peer));
+      if (manager) {
+        manager.close();
+        manager.emit('error', new Error('Could not connect to peer ' + manager.peer));
       }
       break;
     case 'ANSWER':
-      if (connection) {
-        connection.handleSDP(payload.sdp, message.type);
+      if (manager) {
+        manager.handleSDP(payload.sdp, message.type);
       }
       break;
     case 'CANDIDATE':
-      if (connection) {
-        connection.handleCandidate(payload);
+      if (manager) {
+        manager.handleCandidate(payload);
       }
       break;
     case 'LEAVE':
-      if (connection) {
-        connection.handleLeave();
+      if (manager) {
+        manager.handleLeave();
       }
       break;
     case 'INVALID-KEY':
@@ -1317,10 +1324,10 @@ Peer.prototype._abort = function(type, message) {
 
 Peer.prototype._cleanup = function() {
   var self = this;
-  if (!!this.connections) {
-    var peers = Object.keys(this.connections);
+  if (!!this.managers) {
+    var peers = Object.keys(this.managers);
     for (var i = 0, ii = peers.length; i < ii; i++) {
-      this.connections[peers[i]].close();
+      this.managers[peers[i]].close();
     }
     util.setZeroTimeout(function(){
       self._socket.close();
@@ -1329,16 +1336,6 @@ Peer.prototype._cleanup = function() {
   this.emit('close');
 };
 
-/** Listeners for DataConnection events. */
-Peer.prototype._attachConnectionListeners = function(connection) {
-  var self = this;
-  connection.on('close', function(peer) {
-    if (self.connections[peer]) { 
-      delete self.connections[peer]; 
-    }
-  });
-};
-
 
 
 /** Exposed connect function for users. Will try to connect later if user
@@ -1352,15 +1349,23 @@ Peer.prototype.connect = function(peer, options) {
   }
 
   options = util.extend({
-    config: this._options.config
+    config: this._options.config,
+    label: 'peerjs'
   }, options);
 
-  var connection = new DataConnection(this.id, peer, this._socket, options);
-  this._attachConnectionListeners(connection);
+  var manager = this.managers[peer];
+  if (!!manager) {
+    manager = new ConnectionManager(this.id, peer, this._socket, options);
+    this._attachManagerListeners(manager);
+    this.managers[peer] = manager;
+    this.connections[peer] = {};
+  }
+
+  var connection = manager.connect(options.label);
+  this.connections[peer][options.label] = connection;
 
-  this.connections[peer] = connection;
   if (!this.id) {
-    this._queued.push(connection);
+    this._queued.push(manager);
   }
   return connection;
 };
@@ -1375,162 +1380,31 @@ Peer.prototype.destroy = function() {
 
 exports.Peer = Peer;
 /**
- * A DataChannel|PeerConnection between two Peers.
+ * Wraps a DataChannel between two Peers.
  */
-function DataConnection(id, peer, socket, options) {
-  if (!(this instanceof DataConnection)) return new DataConnection(id, peer, socket, options);
+function DataConnection(dc, options) {
+  if (!(this instanceof DataConnection)) return new DataConnection(dc, options);
   EventEmitter.call(this);
 
   options = util.extend({
-    config: { 'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }] },
     reliable: false,
     serialization: 'binary'
   }, options);
-  this._options = options;
 
   // Connection is not open yet.
   this.open = false;
 
-  this.id = id;
-  this.peer = peer;
   this.metadata = options.metadata;
   this.serialization = options.serialization;
 
-  this._originator = (options.sdp === undefined);
-  this._socket = socket;
-  this._sdp = options.sdp;
-
-  if (!!this.id) {
-    this.initialize();
-  }
+  this._dc = dc;
+  this._configureDataChannel();
 };
 
 util.inherits(DataConnection, EventEmitter);
 
-DataConnection.prototype.initialize = function(id, socket) {
-  if (!!id) {
-    this.id = id;
-  }
-  if (!!socket) {
-    this._socket = socket;
-  }
-  // Firefoxism: connectDataConnection ports.
-  /*if (util.browserisms === 'Firefox') {
-    this._firefoxPortSetup();
-  }*/
-
-  // Set up PeerConnection.
-  this._startPeerConnection();
-
-  // Listen for ICE candidates
-  this._setupIce();
-
-  // Listen for negotiation needed
-  // ** Chrome only.
-  if (util.browserisms !== 'Firefox' && !!this.id) {
-    this._setupOffer();
-  }
-
-  // Listen for or create a data channel
-  this._setupDataChannel();
-
-  var self = this;
-  if (!!this._sdp) {
-    this.handleSDP(this._sdp, 'OFFER');
-  }
-
-  // Makes offer if Firefox
-  /*if (util.browserisms === 'Firefox') {
-    this._firefoxAdditional();
-  }*/
-
-  // No-op this.
-  this.initialize = function() {};
-};
-
-
-DataConnection.prototype._setupOffer = function() {
-  var self = this;
-  util.log('Listening for `negotiationneeded`');
-  this._pc.onnegotiationneeded = function() {
-    util.log('`negotiationneeded` triggered');
-    self._makeOffer();
-  };
-};
-
-
-DataConnection.prototype._setupDataChannel = function() {
-  var self = this;
-  if (this._originator) {
-    util.log('Creating data channel');
-    // FOR NOW: reliable DC is not supported.
-    this._dc = this._pc.createDataChannel(this.peer, { reliable: false });
-    // Experimental reliable wrapper.
-    if (this._options.reliable) {
-      this._reliable = new Reliable(this._dc, util.debug);
-    }
-    this._configureDataChannel();
-  } else {
-    util.log('Listening for data channel');
-    this._pc.ondatachannel = function(evt) {
-      util.log('Received data channel');
-      self._dc = evt.channel;
-      // Experimental reliable wrapper.
-      if (self._options.reliable) {
-        self._reliable = new Reliable(self._dc, util.debug);
-      }
-      self._configureDataChannel();
-    };
-  }
-};
-
-
-/** Starts a PeerConnection and sets up handlers. */
-DataConnection.prototype._startPeerConnection = function() {
-  util.log('Creating RTCPeerConnection');
-  this._pc = new RTCPeerConnection(this._options.config, { optional:[ { RtpDataChannels: true } ]});
-};
-
-
-/** Takes care of ice handlers. */
-DataConnection.prototype._setupIce = function() {
-  util.log('Listening for ICE candidates');
-  var self = this;
-  this._pc.onicecandidate = function(evt) {
-    if (evt.candidate) {
-      util.log('Received ICE candidates');
-      self._socket.send({
-        type: 'CANDIDATE',
-        payload: {
-          candidate: evt.candidate
-        },
-        dst: self.peer
-      });
-    }
-  };
-};
-
-
-/*DataConnection.prototype._firefoxPortSetup = function() {
-  if (!DataConnection.usedPorts) {
-    DataConnection.usedPorts = [];
-  }
-  this.localPort = util.randomPort();
-  while (DataConnection.usedPorts.indexOf(this.localPort) != -1) {
-    this.localPort = util.randomPort();
-  }
-  this.remotePort = util.randomPort();
-  while (this.remotePort === this.localPort ||
-      DataConnection.usedPorts.indexOf(this.localPort) != -1) {
-    this.remotePort = util.randomPort();
-  }
-  DataConnection.usedPorts.push(this.remotePort);
-  DataConnection.usedPorts.push(this.localPort);
-}*/
-
 DataConnection.prototype._configureDataChannel = function() {
   var self = this;
-  
   if (util.browserisms !== 'Webkit') {
     this._dc.binaryType = 'arraybuffer';
   }
@@ -1538,7 +1412,6 @@ DataConnection.prototype._configureDataChannel = function() {
     util.log('Data channel connection success');
     self.open = true;
     self.emit('open');
-    self._pc.onicecandidate = null;
   };
   if (this._reliable) {
     this._reliable.onmessage = function(msg) {
@@ -1552,88 +1425,21 @@ DataConnection.prototype._configureDataChannel = function() {
   this._dc.onclose = function(e) {
     self.emit('close');
   };
-};
 
+  // Reliable.
+  if (this._options.reliable) {
+    this._reliable = new Reliable(this._dc, util.debug);
+  }
 
-/** Decide whether to handle Firefoxisms. */
-/*DataConnection.prototype._firefoxAdditional = function() {
-  var self = this;
-  getUserMedia({ audio: true, fake: true }, function(s) {
-    self._pc.addStream(s);
-    if (self._originator) {
-      self._makeOffer();
-    }
-  }, function(err) { util.log('Could not getUserMedia'); });
-};*/
-
-DataConnection.prototype._makeOffer = function() {
-  var self = this;
-  this._pc.createOffer(function(offer) {
-    util.log('Created offer');
-    // Reliable hack.
-    if (self._options.reliable) {
-      offer.sdp = Reliable.higherBandwidthSDP(offer.sdp);
-    }
-    self._pc.setLocalDescription(offer, function() {
-      util.log('Set localDescription to offer');
-      self._socket.send({
-        type: 'OFFER',
-        payload: {
-          sdp: offer,
-          serialization: self.serialization,
-          metadata: self.metadata,
-          reliable: self._options.reliable
-        },
-        dst: self.peer
-      });
-    }, function(err) {
-      self.emit('error', err);
-      util.log('Failed to setLocalDescription, ', err);
-    });
-  });
-};
-
-/** Create an answer for PC. */
-DataConnection.prototype._makeAnswer = function() {
-  var self = this;
-  this._pc.createAnswer(function(answer) {
-    util.log('Created answer');
-    // Reliable hack.
-    if (self._options.reliable) {
-      answer.sdp = Reliable.higherBandwidthSDP(answer.sdp);
-    }
-    self._pc.setLocalDescription(answer, function() {
-      util.log('Set localDescription to answer');
-      self._socket.send({
-        type: 'ANSWER',
-        payload: {
-          sdp: answer
-        },
-        dst: self.peer
-      });
-    }, function(err) {
-      self.emit('error', err);
-      util.log('Failed to setLocalDescription, ', err)
-    });
-  }, function(err) {
-    self.emit('error', err);
-    util.log('Failed to create answer, ', err)
-  });
 };
 
-
 DataConnection.prototype._cleanup = function() {
   if (!!this._dc && this._dc.readyState != 'closed') {
     this._dc.close();
     this._dc = null;
   }
-  if (!!this._pc && this._pc.readyState != 'closed') {
-    this._pc.close();
-    this._pc = null;
-  }
 };
 
-
 // Handles a DataChannel message.
 DataConnection.prototype._handleDataMessage = function(e) {
   var self = this;
@@ -1666,18 +1472,10 @@ DataConnection.prototype._handleDataMessage = function(e) {
 /** Allows user to close connection. */
 DataConnection.prototype.close = function() {
   this._cleanup();
-  var self = this;
-  if (this.open) {
-    this._socket.send({
-      type: 'LEAVE',
-      dst: self.peer
-    });
-  }
   this.open = false;
-  this.emit('close', this.peer);
+  this.emit('close');
 };
 
-
 /** Allows user to send data. */
 DataConnection.prototype.send = function(data) {
   if (this._reliable) {
@@ -1704,26 +1502,179 @@ DataConnection.prototype.send = function(data) {
     }
   }
 };
+/**
+ * Manages DataConnections between its peer and one other peer.
+ * Internally, manages PeerConnection.
+ */
+function ConnectionManager(id, peer, socket, options) {
+  if (!(this instanceof ConnectionManager)) return new ConnectionManager(id, peer, socket, options);
+  EventEmitter.call(this);
+
+  options = util.extend({
+    config: { 'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }] },
+    reliable: false,
+    serialization: 'binary'
+  }, options);
+  this._options = options;
+
+  // PeerConnection is not yet dead.
+  this.open = true;
+
+  this.id = id;
+  this.peer = peer;
+  this.pc = null;
+
+  // Mapping labels to metadata and serialization.
+  // label => { metadata: ..., serialization: ..., reliable: ...}
+  this.labels = {}
 
-DataConnection.prototype.handleSDP = function(sdp, type) {
-  if (util.browserisms != 'Firefox') {
-    sdp = new RTCSessionDescription(sdp);
+  // DataConnections on this PC.
+  this.connections = {};
+
+  this._socket = socket;
+
+  if (!!this.id) {
+    this.initialize();
+  }
+};
+
+util.inherits(ConnectionManager, EventEmitter);
+
+ConnectionManager.prototype.initialize = function(id, socket) {
+  if (!!id) {
+    this.id = id;
   }
+  if (!!socket) {
+    this._socket = socket;
+  }
+
+  // Set up PeerConnection.
+  this._startPeerConnection();
+
+  // Listen for ICE candidates.
+  this._setupIce();
+
+  // Listen for negotiation needed.
+  // Chrome only **
+  this._setupNegotiationHandler();
+
+  // Listen for data channel.
+  this._setupDataChannel();
+
+  this.initialize = function() { };
+};
+
+/** Start a PC. */
+ConnectionManager.prototype._startPeerConnection = function() {
+  util.log('Creating RTCPeerConnection');
+  this.pc = new RTCPeerConnection(this._options.config, { optional: [ { rtpDataChannels: true } ]});
+};
+
+/** Set up ICE candidate handlers. */
+ConnectionManager.prototype._setupIce = function() {
+  util.log('Listening for ICE candidates.');
   var self = this;
-  this._pc.setRemoteDescription(sdp, function() {
-    util.log('Set remoteDescription: ' + type);
-    // Firefoxism
-    /**if (type === 'ANSWER' && util.browserisms === 'Firefox') {
-      self._pc.connectDataConnection(self.localPort, self.remotePort);
+  this.pc.onicecandidate = function(evt) {
+    if (evt.candidate) {
+      util.log('Received ICE candidates.');
       self._socket.send({
-        type: 'PORT',
-        dst: self.peer,
+        type: 'CANDIDATE',
         payload: {
-          remote: self.localPort,
-          local: self.remotePort
-        }
+          candidate: evt.candidate
+        },
+        dst: self.peer
       });
-    } else*/ if (type === 'OFFER') {
+    }
+  };
+};
+
+/** Set up onnegotiationneeded. */
+ConnectionManager.prototype._setupNegotiationHandler = function() {
+  var self = this;
+  util.log('Listening for `negotiationneeded`');
+  this.pc.onnegotiationneeded = function() {
+    util.log('`negotiationneeded` triggered');
+    self._makeOffer();
+  };
+};
+
+/** Set up Data Channel listener. */
+ConnectionManager.prototype._setupDataChannel = function() {
+  var self = this;
+  this.pc.ondatachannel = function(evt) {
+    util.log('Received data channel');
+    var dc = evt.channel;
+    var label = dc.label;
+    // This should not be empty.
+    var options = self.labels[label] || {};
+    var connection  = new DataConnection(dc, options);
+    self.connections[label] = connection;
+    self.emit('connection', connection);
+  };
+};
+
+/** Send an offer. */
+ConnectionManager.prototype._makeOffer = function() {
+  var self = this;
+  this.pc.createOffer(function(offer) {
+    util.log('Created offer.');
+    self.pc.setLocalDescription(offer, function() {
+      util.log('Set localDescription to offer');
+      self._socket.send({
+        type: 'OFFER',
+        payload: {
+          sdp: offer,
+          labels: self.labels
+        },
+        dst: self.peer
+      });
+      // We can now reset labels because all info has been communicated.
+      self.labels = {};
+    }, function(err) {
+      self.emit('error', err);
+      util.log('Failed to setLocalDescription, ', err);
+    });
+  });
+};
+
+/** Create an answer for PC. */
+ConnectionManager.prototype._makeAnswer = function() {
+  var self = this;
+  this.pc.createAnswer(function(answer) {
+    util.log('Created answer.');
+    self.pc.setLocalDescription(answer, function() {
+      util.log('Set localDescription to answer.');
+      self._socket.send({
+        type: 'ANSWER',
+        payload: {
+          sdp: answer
+        },
+        dst: self.peer
+      });
+    }, function(err) {
+      self.emit('error', err);
+      util.log('Failed to setLocalDescription, ', err);
+    });
+  }, function(err) {
+    self.emit('error', err);
+    util.log('Failed to create answer, ', err);
+  });
+};
+
+/** Clean up PC, close related DCs. */
+ConnectionManager.prototype._cleanup = function() {
+  util.log('Cleanup ConnectionManager for ' + this.peer);
+
+};
+
+/** Handle an SDP. */
+ConnectionManager.prototype.handleSDP = function(sdp, type) {
+  sdp = new RTCSessionDescription(sdp);
+
+  var self = this;
+  this.pc.setRemoteDescription(sdp, function() {
+    util.log('Set remoteDescription: ' + type);
+    if (type === 'OFFER') {
       self._makeAnswer();
     }
   }, function(err) {
@@ -1732,30 +1683,62 @@ DataConnection.prototype.handleSDP = function(sdp, type) {
   });
 };
 
-
-DataConnection.prototype.handleCandidate = function(message) {
+/** Handle a candidate. */
+ConnectionManager.prototype.handleCandidate = function(message) {
   var candidate = new RTCIceCandidate(message.candidate);
-  this._pc.addIceCandidate(candidate);
-  util.log('Added ice candidate');
+  this.pc.addIceCandidate(candidate);
+  util.log('Added ICE candidate.');
 };
 
-
-DataConnection.prototype.handleLeave = function() {
-  util.log('Peer ' + this.peer + ' disconnected');
+/** Handle peer leaving. */
+ConnectionManager.prototype.handleLeave = function() {
+  util.log('Peer ' + this.peer + ' disconnected.');
   this.close();
 };
 
-/*
-DataConnection.prototype.handlePort = function(message) {
-  if (!DataConnection.usedPorts) {
-    DataConnection.usedPorts = [];
+/** Closes manager and all related connections. */
+ConnectionManager.prototype.close = function() {
+  this._cleanup();
+  var self = this;
+  if (this.open) {
+    this._socket.send({
+      type: 'LEAVE',
+      dst: self.peer
+    });
   }
-  DataConnection.usedPorts.push(message.local);
-  DataConnection.usedPorts.push(message.remote);
-  this._pc.connectDataConnection(message.local, message.remote);
+  this.open = false;
+  this.emit('close', this.peer);
+};
+
+/** Create and returns a DataConnection with the peer with the given label. */
+// TODO: queue in case no ID/PC.
+ConnectionManager.prototype.connect = function(label, options) {
+  options = util.extend({
+    reliable: false,
+    serialization: 'binary'
+  }, options);
+
+  this.labels[label] = {
+    reliable: options.reliable,
+    serialization: options.serialization,
+    label: label,
+    metadata: options.metadata
+  };
+
+  var connection  = new DataConnection(this.pc.createDataChannel(this.peer, { reliable: false }), options);
+  this.connections[label] = connection;
+  return connection;
 };
-*/
 
+/** Updates label:[serialization, reliable, metadata] pairs from offer. */
+// TODO: queue in case no ID/PC.
+ConnectionManager.prototype.update = function(updates) {
+  var labels = Object.keys(updates);
+  for (var i = 0, ii = labels.length; i < ii; i += 1) {
+    var label = labels[i];
+    this.labels[label] = updates[label];
+  }
+};
 /**
  * An abstraction on top of WebSockets and XHR streaming to provide fastest
  * possible connection for peers.

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
dist/peer.min.js


+ 0 - 320
lib/connection.js

@@ -1,320 +0,0 @@
-/**
- * Wraps a DataChannel between two Peers.
- */
-function DataConnection(id, peer, socket, options) {
-  if (!(this instanceof DataConnection)) return new DataConnection(id, peer, socket, options);
-  EventEmitter.call(this);
-
-  options = util.extend({
-    config: { 'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }] },
-    reliable: false,
-    serialization: 'binary'
-  }, options);
-  this._options = options;
-
-  // Connection is not open yet.
-  this.open = false;
-
-  this.id = id;
-  this.peer = peer;
-  this.metadata = options.metadata;
-  this.serialization = options.serialization;
-
-  this._originator = (options.sdp === undefined);
-  this._socket = socket;
-  this._sdp = options.sdp;
-
-  if (!!this.id) {
-    this.initialize();
-  }
-};
-
-util.inherits(DataConnection, EventEmitter);
-
-DataConnection.prototype.initialize = function(id, socket) {
-  if (!!id) {
-    this.id = id;
-  }
-  if (!!socket) {
-    this._socket = socket;
-  }
-
-  // Set up PeerConnection.
-  this._startPeerConnection();
-
-  // Listen for ICE candidates
-  this._setupIce();
-
-  // Listen for negotiation needed
-  // ** Chrome only.
-  if (util.browserisms !== 'Firefox' && !!this.id) {
-    this._setupOffer();
-  }
-
-  // Listen for or create a data channel
-  this._setupDataChannel();
-
-  var self = this;
-  if (!!this._sdp) {
-    this.handleSDP(this._sdp, 'OFFER');
-  }
-
-  // No-op this.
-  this.initialize = function() {};
-};
-
-
-DataConnection.prototype._setupOffer = function() {
-  var self = this;
-  util.log('Listening for `negotiationneeded`');
-  this._pc.onnegotiationneeded = function() {
-    util.log('`negotiationneeded` triggered');
-    self._makeOffer();
-  };
-};
-
-
-DataConnection.prototype._setupDataChannel = function() {
-  var self = this;
-  if (this._originator) {
-    util.log('Creating data channel');
-    // FOR NOW: reliable DC is not supported.
-    this._dc = this._pc.createDataChannel(this.peer, { reliable: false });
-    // Experimental reliable wrapper.
-    if (this._options.reliable) {
-      this._reliable = new Reliable(this._dc, util.debug);
-    }
-    this._configureDataChannel();
-  } else {
-    util.log('Listening for data channel');
-    this._pc.ondatachannel = function(evt) {
-      util.log('Received data channel');
-      self._dc = evt.channel;
-      // Experimental reliable wrapper.
-      if (self._options.reliable) {
-        self._reliable = new Reliable(self._dc, util.debug);
-      }
-      self._configureDataChannel();
-    };
-  }
-};
-
-
-/** Starts a PeerConnection and sets up handlers. */
-DataConnection.prototype._startPeerConnection = function() {
-  util.log('Creating RTCPeerConnection');
-  this._pc = new RTCPeerConnection(this._options.config, { optional:[ { RtpDataChannels: true } ]});
-};
-
-
-/** Takes care of ice handlers. */
-DataConnection.prototype._setupIce = function() {
-  util.log('Listening for ICE candidates');
-  var self = this;
-  this._pc.onicecandidate = function(evt) {
-    if (evt.candidate) {
-      util.log('Received ICE candidates');
-      self._socket.send({
-        type: 'CANDIDATE',
-        payload: {
-          candidate: evt.candidate
-        },
-        dst: self.peer
-      });
-    }
-  };
-};
-
-DataConnection.prototype._configureDataChannel = function() {
-  var self = this;
-  
-  if (util.browserisms !== 'Webkit') {
-    this._dc.binaryType = 'arraybuffer';
-  }
-  this._dc.onopen = function() {
-    util.log('Data channel connection success');
-    self.open = true;
-    self.emit('open');
-    self._pc.onicecandidate = null;
-  };
-  if (this._reliable) {
-    this._reliable.onmessage = function(msg) {
-      self.emit('data', msg);
-    };
-  } else {
-    this._dc.onmessage = function(e) {
-      self._handleDataMessage(e);
-    };
-  }
-  this._dc.onclose = function(e) {
-    self.emit('close');
-  };
-};
-
-DataConnection.prototype._makeOffer = function() {
-  var self = this;
-  this._pc.createOffer(function(offer) {
-    util.log('Created offer');
-    // Reliable hack.
-    if (self._options.reliable) {
-      offer.sdp = Reliable.higherBandwidthSDP(offer.sdp);
-    }
-    self._pc.setLocalDescription(offer, function() {
-      util.log('Set localDescription to offer');
-      self._socket.send({
-        type: 'OFFER',
-        payload: {
-          sdp: offer,
-          serialization: self.serialization,
-          metadata: self.metadata,
-          reliable: self._options.reliable
-        },
-        dst: self.peer
-      });
-    }, function(err) {
-      self.emit('error', err);
-      util.log('Failed to setLocalDescription, ', err);
-    });
-  });
-};
-
-/** Create an answer for PC. */
-DataConnection.prototype._makeAnswer = function() {
-  var self = this;
-  this._pc.createAnswer(function(answer) {
-    util.log('Created answer');
-    // Reliable hack.
-    if (self._options.reliable) {
-      answer.sdp = Reliable.higherBandwidthSDP(answer.sdp);
-    }
-    self._pc.setLocalDescription(answer, function() {
-      util.log('Set localDescription to answer');
-      self._socket.send({
-        type: 'ANSWER',
-        payload: {
-          sdp: answer
-        },
-        dst: self.peer
-      });
-    }, function(err) {
-      self.emit('error', err);
-      util.log('Failed to setLocalDescription, ', err)
-    });
-  }, function(err) {
-    self.emit('error', err);
-    util.log('Failed to create answer, ', err)
-  });
-};
-
-
-DataConnection.prototype._cleanup = function() {
-  if (!!this._dc && this._dc.readyState != 'closed') {
-    this._dc.close();
-    this._dc = null;
-  }
-  if (!!this._pc && this._pc.readyState != 'closed') {
-    this._pc.close();
-    this._pc = null;
-  }
-};
-
-
-// Handles a DataChannel message.
-DataConnection.prototype._handleDataMessage = function(e) {
-  var self = this;
-  var data = e.data;
-  var datatype = data.constructor;
-  if (this.serialization === 'binary' || this.serialization === 'binary-utf8') {
-    if (datatype === Blob) {
-      util.blobToArrayBuffer(data, function(ab) {
-        data = util.unpack(ab);
-        self.emit('data', data);
-      });
-      return;
-    } else if (datatype === ArrayBuffer) {
-      data = util.unpack(data);
-    } else if (datatype === String) {
-      var ab = util.binaryStringToArrayBuffer(data);
-      data = util.unpack(ab);
-    }
-  } else if (this.serialization === 'json') {
-    data = JSON.parse(data);
-  }
-  this.emit('data', data);
-};
-
-
-/**
- * Exposed functionality for users.
- */
-
-/** Allows user to close connection. */
-DataConnection.prototype.close = function() {
-  this._cleanup();
-  var self = this;
-  if (this.open) {
-    this._socket.send({
-      type: 'LEAVE',
-      dst: self.peer
-    });
-  }
-  this.open = false;
-  this.emit('close', this.peer);
-};
-
-
-/** Allows user to send data. */
-DataConnection.prototype.send = function(data) {
-  if (this._reliable) {
-    // Note: reliable sending will make it so that you cannot customize
-    // serialization.
-    this._reliable.send(data);
-    return;
-  }
-  var self = this;
-  if (this.serialization === 'none') {
-    this._dc.send(data);
-  } else if (this.serialization === 'json') {
-    this._dc.send(JSON.stringify(data));
-  } else {
-    var utf8 = (this.serialization === 'binary-utf8');
-    var blob = util.pack(data, utf8);
-    // DataChannel currently only supports strings.
-    if (util.browserisms === 'Webkit') {
-      util.blobToBinaryString(blob, function(str){
-        self._dc.send(str);
-      });
-    } else {
-      this._dc.send(blob);
-    }
-  }
-};
-
-DataConnection.prototype.handleSDP = function(sdp, type) {
-  if (util.browserisms != 'Firefox') {
-    sdp = new RTCSessionDescription(sdp);
-  }
-  var self = this;
-  this._pc.setRemoteDescription(sdp, function() {
-    util.log('Set remoteDescription: ' + type);
-    if (type === 'OFFER') {
-      self._makeAnswer();
-    }
-  }, function(err) {
-    self.emit('error', err);
-    util.log('Failed to setRemoteDescription, ', err);
-  });
-};
-
-
-DataConnection.prototype.handleCandidate = function(message) {
-  var candidate = new RTCIceCandidate(message.candidate);
-  this._pc.addIceCandidate(candidate);
-  util.log('Added ice candidate');
-};
-
-
-DataConnection.prototype.handleLeave = function() {
-  util.log('Peer ' + this.peer + ' disconnected');
-  this.close();
-};

+ 4 - 2
lib/connectionmanager.js

@@ -13,8 +13,8 @@ function ConnectionManager(id, peer, socket, options) {
   }, options);
   this._options = options;
 
-  // PeerConnection is not yet open.
-  this.open = false;
+  // PeerConnection is not yet dead.
+  this.open = true;
 
   this.id = id;
   this.peer = peer;
@@ -101,6 +101,7 @@ ConnectionManager.prototype._setupDataChannel = function() {
     util.log('Received data channel');
     var dc = evt.channel;
     var label = dc.label;
+    // This should not be empty.
     var options = self.labels[label] || {};
     var connection  = new DataConnection(dc, options);
     self.connections[label] = connection;
@@ -216,6 +217,7 @@ ConnectionManager.prototype.connect = function(label, options) {
   this.labels[label] = {
     reliable: options.reliable,
     serialization: options.serialization,
+    label: label,
     metadata: options.metadata
   };
 

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä