|
@@ -1052,9 +1052,9 @@ Reliable.higherBandwidthSDP = function(sdp) {
|
|
|
Reliable.prototype.onmessage = function(msg) {};
|
|
|
|
|
|
exports.Reliable = Reliable;
|
|
|
-exports.RTCSessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription;
|
|
|
-exports.RTCPeerConnection = window.mozRTCPeerConnection || window.webkitRTCPeerConnection || window.RTCPeerConnection;
|
|
|
-exports.RTCIceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate;
|
|
|
+exports.RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription;
|
|
|
+exports.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
|
|
|
+exports.RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate;
|
|
|
var defaultConfig = {'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }]};
|
|
|
var dataCount = 1;
|
|
|
|
|
@@ -1390,6 +1390,7 @@ function Peer(id, options) {
|
|
|
port: util.CLOUD_PORT,
|
|
|
key: 'peerjs',
|
|
|
path: '/',
|
|
|
+ token: util.randomToken(),
|
|
|
config: util.defaultConfig
|
|
|
}, options);
|
|
|
this.options = options;
|
|
@@ -1442,7 +1443,7 @@ function Peer(id, options) {
|
|
|
|
|
|
// States.
|
|
|
this.destroyed = false; // Connections have been killed
|
|
|
- this.disconnected = false; // Connection to PeerServer killed manually but P2P connections still active
|
|
|
+ this.disconnected = false; // Connection to PeerServer killed but P2P connections still active
|
|
|
this.open = false; // Sockets and such are not yet open.
|
|
|
//
|
|
|
|
|
@@ -1451,8 +1452,21 @@ function Peer(id, options) {
|
|
|
this._lostMessages = {}; // src => [list of messages]
|
|
|
//
|
|
|
|
|
|
- // Initialize the 'socket' (which is actually a mix of XHR streaming and
|
|
|
- // websockets.)
|
|
|
+ // Start the server connection
|
|
|
+ this._initializeServerConnection();
|
|
|
+ if (id) {
|
|
|
+ this._initialize(id);
|
|
|
+ } else {
|
|
|
+ this._retrieveId();
|
|
|
+ }
|
|
|
+ //
|
|
|
+};
|
|
|
+
|
|
|
+util.inherits(Peer, EventEmitter);
|
|
|
+
|
|
|
+// Initialize the 'socket' (which is actually a mix of XHR streaming and
|
|
|
+// websockets.)
|
|
|
+Peer.prototype._initializeServerConnection = function() {
|
|
|
var self = this;
|
|
|
this.socket = new Socket(this.options.secure, this.options.host, this.options.port, this.options.path, this.options.key);
|
|
|
this.socket.on('message', function(data) {
|
|
@@ -1461,24 +1475,35 @@ function Peer(id, options) {
|
|
|
this.socket.on('error', function(error) {
|
|
|
self._abort('socket-error', error);
|
|
|
});
|
|
|
+ this.socket.on('disconnected', function() {
|
|
|
+ // If we haven't explicitly disconnected, emit error and disconnect.
|
|
|
+ if (!self.disconnected) {
|
|
|
+ self._error('network', 'Lost connection to server.')
|
|
|
+ self.disconnect();
|
|
|
+ }
|
|
|
+ });
|
|
|
this.socket.on('close', function() {
|
|
|
- if (!self.disconnected) { // If we haven't explicitly disconnected, emit error.
|
|
|
+ // If we haven't explicitly disconnected, emit error.
|
|
|
+ if (!self.disconnected) {
|
|
|
self._abort('socket-closed', 'Underlying socket is already closed.');
|
|
|
}
|
|
|
});
|
|
|
- //
|
|
|
+};
|
|
|
|
|
|
- // Start the connections
|
|
|
- if (id) {
|
|
|
- this._initialize(id);
|
|
|
+Peer.prototype.reconnect = function() {
|
|
|
+ if (this.disconnected && !this.destroyed) {
|
|
|
+ this._initializeServerConnection();
|
|
|
+ this._initialize(this._lastServerId);
|
|
|
+ } else if (this.destroyed) {
|
|
|
+ throw new Error('This peer cannot reconnect to the server. It has already been destroyed.');
|
|
|
+ } else if (!this.disconnected && !this.open) {
|
|
|
+ // Do nothing. We're still connecting the first time.
|
|
|
+ util.error('In a hurry? We\'re still trying to make the initial connection!');
|
|
|
} else {
|
|
|
- this._retrieveId();
|
|
|
+ throw new Error('Peer ' + this.id + ' cannot reconnect because it is not disconnected from the server!');
|
|
|
}
|
|
|
- //
|
|
|
};
|
|
|
|
|
|
-util.inherits(Peer, EventEmitter);
|
|
|
-
|
|
|
/** Get a unique ID from the server via XHR. */
|
|
|
Peer.prototype._retrieveId = function(cb) {
|
|
|
var self = this;
|
|
@@ -1516,9 +1541,8 @@ Peer.prototype._retrieveId = function(cb) {
|
|
|
|
|
|
/** Initialize a connection with the server. */
|
|
|
Peer.prototype._initialize = function(id) {
|
|
|
- var self = this;
|
|
|
this.id = id;
|
|
|
- this.socket.start(this.id);
|
|
|
+ this.socket.start(this.id, this.options.token);
|
|
|
}
|
|
|
|
|
|
/** Handles messages from the server. */
|
|
@@ -1549,7 +1573,7 @@ Peer.prototype._handleMessage = function(message) {
|
|
|
break;
|
|
|
|
|
|
case 'EXPIRE': // The offer sent to a peer has expired without response.
|
|
|
- this.emit('error', new Error('Could not connect to peer ' + peer));
|
|
|
+ this.emitError('peer-unavailable', 'Could not connect to peer ' + peer);
|
|
|
break;
|
|
|
case 'OFFER': // we should consider switching this to CALL/CONNECT, but this is the least breaking option.
|
|
|
var connectionId = payload.connectionId;
|
|
@@ -1640,7 +1664,7 @@ Peer.prototype.connect = function(peer, options) {
|
|
|
util.warn('You cannot connect to a new Peer because you called '
|
|
|
+ '.disconnect() on this Peer and ended your connection with the'
|
|
|
+ ' server. You can create a new Peer to reconnect.');
|
|
|
- this.emit('error', new Error('Cannot connect to new Peer after disconnecting from server.'));
|
|
|
+ this.emitError('disconnected', 'Cannot connect to new Peer after disconnecting from server.');
|
|
|
return;
|
|
|
}
|
|
|
var connection = new DataConnection(peer, this, options);
|
|
@@ -1657,7 +1681,7 @@ Peer.prototype.call = function(peer, stream, options) {
|
|
|
util.warn('You cannot connect to a new Peer because you called '
|
|
|
+ '.disconnect() on this Peer and ended your connection with the'
|
|
|
+ ' server. You can create a new Peer to reconnect.');
|
|
|
- this.emit('error', new Error('Cannot connect to new Peer after disconnecting from server.'));
|
|
|
+ this.emitError('disconnected', 'Cannot connect to new Peer after disconnecting from server.');
|
|
|
return;
|
|
|
}
|
|
|
if (!stream) {
|
|
@@ -1702,10 +1726,17 @@ Peer.prototype._delayedAbort = function(type, message) {
|
|
|
|
|
|
/** Destroys the Peer and emits an error message. */
|
|
|
Peer.prototype._abort = function(type, message) {
|
|
|
- util.error('Aborting. Error:', message);
|
|
|
- var err = new Error(message);
|
|
|
+ util.error('Aborting!');
|
|
|
+ this.emitError(type, message);
|
|
|
+};
|
|
|
+
|
|
|
+/** Emits a typed error message. */
|
|
|
+Peer.prototype.emitError = function(type, err) {
|
|
|
+ util.error('Error:', err);
|
|
|
+ if (typeof err === 'string') {
|
|
|
+ err = new Error(err);
|
|
|
+ }
|
|
|
err.type = type;
|
|
|
- this.destroy();
|
|
|
this.emit('error', err);
|
|
|
};
|
|
|
|
|
@@ -1758,6 +1789,8 @@ Peer.prototype.disconnect = function() {
|
|
|
if (self.socket) {
|
|
|
self.socket.close();
|
|
|
}
|
|
|
+ self.emit('disconnected', self.id);
|
|
|
+ self._lastServerId = self.id;
|
|
|
self.id = null;
|
|
|
}
|
|
|
});
|
|
@@ -1930,12 +1963,12 @@ DataConnection.prototype._handleDataMessage = function(e) {
|
|
|
chunkInfo.count += 1;
|
|
|
|
|
|
if (chunkInfo.total === chunkInfo.count) {
|
|
|
+ // Clean up before making the recursive call to `_handleDataMessage`.
|
|
|
+ delete this._chunkedData[id];
|
|
|
+
|
|
|
// We've received all the chunks--time to construct the complete data.
|
|
|
data = new Blob(chunkInfo.data);
|
|
|
this._handleDataMessage({data: data});
|
|
|
-
|
|
|
- // We can also just delete the chunks now.
|
|
|
- delete this._chunkedData[id];
|
|
|
}
|
|
|
|
|
|
this._chunkedData[id] = chunkInfo;
|
|
@@ -2384,11 +2417,11 @@ Negotiator._makeOffer = function(connection) {
|
|
|
dst: connection.peer
|
|
|
});
|
|
|
}, function(err) {
|
|
|
- connection.provider.emit('error', err);
|
|
|
+ connection.provider.emitError('webrtc', err);
|
|
|
util.log('Failed to setLocalDescription, ', err);
|
|
|
});
|
|
|
}, function(err) {
|
|
|
- connection.provider.emit('error', err);
|
|
|
+ connection.provider.emitError('webrtc', err);
|
|
|
util.log('Failed to createOffer, ', err);
|
|
|
}, connection.options.constraints);
|
|
|
}
|
|
@@ -2416,11 +2449,11 @@ Negotiator._makeAnswer = function(connection) {
|
|
|
dst: connection.peer
|
|
|
});
|
|
|
}, function(err) {
|
|
|
- connection.provider.emit('error', err);
|
|
|
+ connection.provider.emitError('webrtc', err);
|
|
|
util.log('Failed to setLocalDescription, ', err);
|
|
|
});
|
|
|
}, function(err) {
|
|
|
- connection.provider.emit('error', err);
|
|
|
+ connection.provider.emitError('webrtc', err);
|
|
|
util.log('Failed to create answer, ', err);
|
|
|
});
|
|
|
}
|
|
@@ -2438,7 +2471,7 @@ Negotiator.handleSDP = function(type, connection, sdp) {
|
|
|
Negotiator._makeAnswer(connection);
|
|
|
}
|
|
|
}, function(err) {
|
|
|
- connection.provider.emit('error', err);
|
|
|
+ connection.provider.emitError('webrtc', err);
|
|
|
util.log('Failed to setRemoteDescription, ', err);
|
|
|
});
|
|
|
}
|
|
@@ -2476,12 +2509,11 @@ util.inherits(Socket, EventEmitter);
|
|
|
|
|
|
|
|
|
/** Check in with ID or get one from server. */
|
|
|
-Socket.prototype.start = function(id) {
|
|
|
+Socket.prototype.start = function(id, token) {
|
|
|
this.id = id;
|
|
|
|
|
|
- var token = util.randomToken();
|
|
|
this._httpUrl += '/' + id + '/' + token;
|
|
|
- this._wsUrl += '&id='+id+'&token='+token;
|
|
|
+ this._wsUrl += '&id=' + id + '&token=' + token;
|
|
|
|
|
|
this._startXhrStream();
|
|
|
this._startWebSocket();
|
|
@@ -2499,14 +2531,19 @@ Socket.prototype._startWebSocket = function(id) {
|
|
|
this._socket = new WebSocket(this._wsUrl);
|
|
|
|
|
|
this._socket.onmessage = function(event) {
|
|
|
- var data;
|
|
|
try {
|
|
|
- data = JSON.parse(event.data);
|
|
|
+ var data = JSON.parse(event.data);
|
|
|
+ self.emit('message', data);
|
|
|
} catch(e) {
|
|
|
util.log('Invalid server message', event.data);
|
|
|
return;
|
|
|
}
|
|
|
- self.emit('message', data);
|
|
|
+ };
|
|
|
+
|
|
|
+ this._socket.onclose = function(event) {
|
|
|
+ util.log('Socket closed.');
|
|
|
+ self.disconnected = true;
|
|
|
+ self.emit('disconnected');
|
|
|
};
|
|
|
|
|
|
// Take care of the queue of connections if necessary and make sure Peer knows
|
|
@@ -2536,9 +2573,13 @@ Socket.prototype._startXhrStream = function(n) {
|
|
|
if (this.readyState == 2 && this.old) {
|
|
|
this.old.abort();
|
|
|
delete this.old;
|
|
|
- }
|
|
|
- if (this.readyState > 2 && this.status == 200 && this.responseText) {
|
|
|
+ } else if (this.readyState > 2 && this.status === 200 && this.responseText) {
|
|
|
self._handleStream(this);
|
|
|
+ } else if (this.status !== 200) {
|
|
|
+ // If we get a different status code, likely something went wrong.
|
|
|
+ // Stop streaming.
|
|
|
+ clearTimeout(self._timeout);
|
|
|
+ self.emit('disconnected');
|
|
|
}
|
|
|
};
|
|
|
this._http.send(null);
|