Jelajahi Sumber

Merge pull request #580 from afrokick/refactoring/peerAndSocket

Fix _lastServerId + refactoring
afrokick 5 tahun lalu
induk
melakukan
0465fe9f18
11 mengubah file dengan 371 tambahan dan 225 penghapusan
  1. 93 81
      dist/peerjs.js
  2. 0 0
      dist/peerjs.js.map
  3. 0 0
      dist/peerjs.min.js
  4. 0 0
      dist/peerjs.min.js.map
  5. 0 8
      lib/dataconnection.ts
  6. 83 91
      lib/peer.ts
  7. 32 19
      lib/socket.ts
  8. 5 5
      package-lock.json
  9. 1 1
      package.json
  10. 10 0
      test/logger.ts
  11. 147 20
      test/peer.ts

+ 93 - 81
dist/peerjs.js

@@ -7333,32 +7333,25 @@ function (_super) {
     var _this = _super.call(this) || this;
 
     _this.pingInterval = pingInterval;
-    _this._disconnected = false;
+    _this._disconnected = true;
     _this._messagesQueue = [];
     var wsProtocol = secure ? "wss://" : "ws://";
-    _this._wsUrl = wsProtocol + host + ":" + port + path + "peerjs?key=" + key;
+    _this._baseUrl = wsProtocol + host + ":" + port + path + "peerjs?key=" + key;
     return _this;
   }
-  /** Check in with ID or get one from server. */
-
 
   Socket.prototype.start = function (id, token) {
-    this._id = id;
-    this._wsUrl += "&id=" + id + "&token=" + token;
-
-    this._startWebSocket();
-  };
-  /** Start up websocket communications. */
-
-
-  Socket.prototype._startWebSocket = function () {
     var _this = this;
 
-    if (this._socket) {
+    this._id = id;
+    var wsUrl = this._baseUrl + "&id=" + id + "&token=" + token;
+
+    if (!!this._socket || !this._disconnected) {
       return;
     }
 
-    this._socket = new WebSocket(this._wsUrl);
+    this._socket = new WebSocket(wsUrl);
+    this._disconnected = false;
 
     this._socket.onmessage = function (event) {
       var data;
@@ -7375,9 +7368,15 @@ function (_super) {
     };
 
     this._socket.onclose = function (event) {
+      if (_this._disconnected) {
+        return;
+      }
+
       logger_1.default.log("Socket closed.", event);
+
+      _this._cleanup();
+
       _this._disconnected = true;
-      clearTimeout(_this._wsPingTimer);
 
       _this.emit(enums_1.SocketEventType.Disconnected);
     }; // Take care of the queue of connections if necessary and make sure Peer knows
@@ -7385,7 +7384,9 @@ function (_super) {
 
 
     this._socket.onopen = function () {
-      if (_this._disconnected) return;
+      if (_this._disconnected) {
+        return;
+      }
 
       _this._sendQueuedMessages();
 
@@ -7483,12 +7484,25 @@ function (_super) {
   };
 
   Socket.prototype.close = function () {
-    if (!this._disconnected && !!this._socket) {
+    if (this._disconnected) {
+      return;
+    }
+
+    this._cleanup();
+
+    this._disconnected = true;
+  };
+
+  Socket.prototype._cleanup = function () {
+    if (!!this._socket) {
+      this._socket.onopen = this._socket.onmessage = this._socket.onclose = null;
+
       this._socket.close();
 
-      this._disconnected = true;
-      clearTimeout(this._wsPingTimer);
+      this._socket = undefined;
     }
+
+    clearTimeout(this._wsPingTimer);
   };
 
   return Socket;
@@ -8675,10 +8689,6 @@ function (_super) {
     _this.serialization = _this.options.serialization || enums_1.SerializationType.Binary;
     _this.reliable = !!_this.options.reliable;
 
-    if (_this.options._payload) {
-      _this._peerBrowser = _this.options._payload.browser;
-    }
-
     _this._encodingQueue.on('done', function (ab) {
       _this._bufferedSend(ab);
     });
@@ -8984,8 +8994,6 @@ function (_super) {
 
     switch (message.type) {
       case enums_1.ServerMessageType.Answer:
-        this._peerBrowser = payload.browser; // Forward to negotiator
-
         this._negotiator.handleSDP(message.type, payload.sdp);
 
         break;
@@ -9423,8 +9431,10 @@ function (_super) {
   __extends(Peer, _super);
 
   function Peer(id, options) {
-    var _this = _super.call(this) || this; // States.
+    var _this = _super.call(this) || this;
 
+    _this._id = null;
+    _this._lastServerId = null; // States.
 
     _this._destroyed = false; // Connections have been killed
 
@@ -9483,7 +9493,9 @@ function (_super) {
       logger_1.default.setLogFunction(_this._options.logFunction);
     }
 
-    logger_1.default.logLevel = _this._options.debug || 0; // Sanity checks
+    logger_1.default.logLevel = _this._options.debug || 0;
+    _this._api = new api_1.API(options);
+    _this._socket = _this._createServerConnection(); // Sanity checks
     // Ensure WebRTC supported
 
     if (!util_1.util.supports.audioVideo && !util_1.util.supports.data) {
@@ -9499,10 +9511,6 @@ function (_super) {
       return _this;
     }
 
-    _this._api = new api_1.API(options); // Start the server connection
-
-    _this._initializeServerConnection();
-
     if (userId) {
       _this._initialize(userId);
     } else {
@@ -9592,40 +9600,42 @@ function (_super) {
     },
     enumerable: true,
     configurable: true
-  }); // Initialize the 'socket' (which is actually a mix of XHR streaming and
-  // websockets.)
+  });
 
-  Peer.prototype._initializeServerConnection = function () {
+  Peer.prototype._createServerConnection = function () {
     var _this = this;
 
-    this._socket = new socket_1.Socket(this._options.secure, this._options.host, this._options.port, this._options.path, this._options.key, this._options.pingInterval);
-    this.socket.on(enums_1.SocketEventType.Message, function (data) {
+    var socket = new socket_1.Socket(this._options.secure, this._options.host, this._options.port, this._options.path, this._options.key, this._options.pingInterval);
+    socket.on(enums_1.SocketEventType.Message, function (data) {
       _this._handleMessage(data);
     });
-    this.socket.on(enums_1.SocketEventType.Error, function (error) {
+    socket.on(enums_1.SocketEventType.Error, function (error) {
       _this._abort(enums_1.PeerErrorType.SocketError, error);
     });
-    this.socket.on(enums_1.SocketEventType.Disconnected, function () {
-      // If we haven't explicitly disconnected, emit error and disconnect.
-      if (!_this.disconnected) {
-        _this.emitError(enums_1.PeerErrorType.Network, "Lost connection to server.");
-
-        _this.disconnect();
+    socket.on(enums_1.SocketEventType.Disconnected, function () {
+      if (_this.disconnected) {
+        return;
       }
+
+      _this.emitError(enums_1.PeerErrorType.Network, "Lost connection to server.");
+
+      _this.disconnect();
     });
-    this.socket.on(enums_1.SocketEventType.Close, function () {
-      // If we haven't explicitly disconnected, emit error.
-      if (!_this.disconnected) {
-        _this._abort(enums_1.PeerErrorType.SocketClosed, "Underlying socket is already closed.");
+    socket.on(enums_1.SocketEventType.Close, function () {
+      if (_this.disconnected) {
+        return;
       }
+
+      _this._abort(enums_1.PeerErrorType.SocketClosed, "Underlying socket is already closed.");
     });
+    return socket;
   };
   /** Initialize a connection with the server. */
 
 
   Peer.prototype._initialize = function (id) {
     this._id = id;
-    this.socket.start(this.id, this._options.token);
+    this.socket.start(id, this._options.token);
   };
   /** Handles messages from the server. */
 
@@ -9640,8 +9650,9 @@ function (_super) {
     switch (type) {
       case enums_1.ServerMessageType.Open:
         // The connection to the server is open.
-        this.emit(enums_1.PeerEventType.Open, this.id);
+        this._lastServerId = this.id;
         this._open = true;
+        this.emit(enums_1.PeerEventType.Open, this.id);
         break;
 
       case enums_1.ServerMessageType.Error:
@@ -9664,7 +9675,7 @@ function (_super) {
 
       case enums_1.ServerMessageType.Leave:
         // Another peer has closed its connection to this peer.
-        logger_1.default.log("Received leave message from", peerId);
+        logger_1.default.log("Received leave message from " + peerId);
 
         this._cleanupPeer(peerId);
 
@@ -9685,7 +9696,7 @@ function (_super) {
 
           if (connection) {
             connection.close();
-            logger_1.default.warn("Offer received for existing Connection ID:", connectionId);
+            logger_1.default.warn("Offer received for existing Connection ID:" + connectionId);
           } // Create a new connection.
 
 
@@ -9713,7 +9724,7 @@ function (_super) {
 
             this.emit(enums_1.PeerEventType.Connection, connection);
           } else {
-            logger_1.default.warn("Received malformed connection type:", payload.type);
+            logger_1.default.warn("Received malformed connection type:" + payload.type);
             return;
           } // Find messages.
 
@@ -9845,7 +9856,7 @@ function (_super) {
 
 
   Peer.prototype._addConnection = function (peerId, connection) {
-    logger_1.default.log("add connection " + connection.type + ":" + connection.connectionId + "\n       to peerId:" + peerId);
+    logger_1.default.log("add connection " + connection.type + ":" + connection.connectionId + " to peerId:" + peerId);
 
     if (!this._connections.has(peerId)) {
       this._connections.set(peerId, []);
@@ -9933,13 +9944,16 @@ function (_super) {
 
   Peer.prototype.emitError = function (type, err) {
     logger_1.default.error("Error:", err);
+    var error;
 
     if (typeof err === "string") {
-      err = new Error(err);
+      error = new Error(err);
+    } else {
+      error = err;
     }
 
-    err.type = type;
-    this.emit(enums_1.PeerEventType.Error, err);
+    error.type = type;
+    this.emit(enums_1.PeerEventType.Error, error);
   };
   /**
    * Destroys the Peer: closes all active connections as well as the connection
@@ -9950,12 +9964,17 @@ function (_super) {
 
 
   Peer.prototype.destroy = function () {
-    if (!this.destroyed) {
-      this._cleanup();
-
-      this.disconnect();
-      this._destroyed = true;
+    if (this.destroyed) {
+      return;
     }
+
+    logger_1.default.log("Destroy peer with ID:" + this.id);
+    this.disconnect();
+
+    this._cleanup();
+
+    this._destroyed = true;
+    this.emit(enums_1.PeerEventType.Close);
   };
   /** Disconnects every connection on this peer. */
 
@@ -9983,7 +10002,7 @@ function (_super) {
       }
     }
 
-    this.emit(enums_1.PeerEventType.Close);
+    this.socket.removeAllListeners();
   };
   /** Closes all connections to this peer. */
 
@@ -10021,23 +10040,18 @@ function (_super) {
 
 
   Peer.prototype.disconnect = function () {
-    var _this = this;
-
-    setTimeout(function () {
-      if (!_this.disconnected) {
-        _this._disconnected = true;
-        _this._open = false;
-
-        if (_this.socket) {
-          _this.socket.close();
-        }
-
-        _this.emit(enums_1.PeerEventType.Disconnected, _this.id);
+    if (this.disconnected) {
+      return;
+    }
 
-        _this._lastServerId = _this.id;
-        _this._id = null;
-      }
-    }, 0);
+    var currentId = this.id;
+    logger_1.default.log("Disconnect peer with ID:" + currentId);
+    this._disconnected = true;
+    this._open = false;
+    this.socket.close();
+    this._lastServerId = currentId;
+    this._id = null;
+    this.emit(enums_1.PeerEventType.Disconnected, currentId);
   };
   /** Attempts to reconnect with the same ID. */
 
@@ -10047,8 +10061,6 @@ function (_super) {
       logger_1.default.log("Attempting reconnection to server with ID " + this._lastServerId);
       this._disconnected = false;
 
-      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.");

File diff ditekan karena terlalu besar
+ 0 - 0
dist/peerjs.js.map


File diff ditekan karena terlalu besar
+ 0 - 0
dist/peerjs.min.js


File diff ditekan karena terlalu besar
+ 0 - 0
dist/peerjs.min.js.map


+ 0 - 8
lib/dataconnection.ts

@@ -39,7 +39,6 @@ export class DataConnection extends BaseConnection {
     }
   } = {};
 
-  private _peerBrowser: any;
   private _dc: RTCDataChannel;
   private _encodingQueue = new EncodingQueue();
 
@@ -59,10 +58,6 @@ export class DataConnection extends BaseConnection {
     this.serialization = this.options.serialization || SerializationType.Binary;
     this.reliable = !!this.options.reliable;
 
-    if (this.options._payload) {
-      this._peerBrowser = this.options._payload.browser;
-    }
-
     this._encodingQueue.on('done', (ab: ArrayBuffer) => {
       this._bufferedSend(ab);
     });
@@ -319,9 +314,6 @@ export class DataConnection extends BaseConnection {
 
     switch (message.type) {
       case ServerMessageType.Answer:
-        this._peerBrowser = payload.browser;
-
-        // Forward to negotiator
         this._negotiator.handleSDP(message.type, payload.sdp);
         break;
       case ServerMessageType.Candidate:

+ 83 - 91
lib/peer.ts

@@ -36,9 +36,11 @@ export class Peer extends EventEmitter {
   private static readonly DEFAULT_KEY = "peerjs";
 
   private readonly _options: PeerOptions;
-  private _id: string;
-  private _lastServerId: string;
-  private _api: API;
+  private readonly _api: API;
+  private readonly _socket: Socket;
+
+  private _id: string | null = null;
+  private _lastServerId: string | null = null;
 
   // States.
   private _destroyed = false; // Connections have been killed
@@ -47,8 +49,6 @@ export class Peer extends EventEmitter {
   private readonly _connections: Map<string, BaseConnection[]> = new Map(); // All connections for this peer.
   private readonly _lostMessages: Map<string, ServerMessage[]> = new Map(); // src => [list of messages]
 
-  private _socket: Socket;
-
   get id() {
     return this._id;
   }
@@ -139,6 +139,9 @@ export class Peer extends EventEmitter {
 
     logger.logLevel = this._options.debug || 0;
 
+    this._api = new API(options);
+    this._socket = this._createServerConnection();
+
     // Sanity checks
     // Ensure WebRTC supported
     if (!util.supports.audioVideo && !util.supports.data) {
@@ -148,17 +151,13 @@ export class Peer extends EventEmitter {
       );
       return;
     }
+
     // Ensure alphanumeric id
     if (!!userId && !util.validateId(userId)) {
       this._delayedAbort(PeerErrorType.InvalidID, `ID "${userId}" is invalid`);
       return;
     }
 
-    this._api = new API(options);
-
-    // Start the server connection
-    this._initializeServerConnection();
-
     if (userId) {
       this._initialize(userId);
     } else {
@@ -168,49 +167,48 @@ export class Peer extends EventEmitter {
     }
   }
 
-  // Initialize the 'socket' (which is actually a mix of XHR streaming and
-  // websockets.)
-  private _initializeServerConnection(): void {
-    this._socket = new Socket(
+  private _createServerConnection(): Socket {
+    const socket = new Socket(
       this._options.secure,
-      this._options.host,
-      this._options.port,
-      this._options.path,
-      this._options.key,
+      this._options.host!,
+      this._options.port!,
+      this._options.path!,
+      this._options.key!,
       this._options.pingInterval
     );
 
-    this.socket.on(SocketEventType.Message, data => {
+    socket.on(SocketEventType.Message, (data: ServerMessage) => {
       this._handleMessage(data);
     });
 
-    this.socket.on(SocketEventType.Error, error => {
+    socket.on(SocketEventType.Error, (error: string) => {
       this._abort(PeerErrorType.SocketError, error);
     });
 
-    this.socket.on(SocketEventType.Disconnected, () => {
-      // If we haven't explicitly disconnected, emit error and disconnect.
-      if (!this.disconnected) {
-        this.emitError(PeerErrorType.Network, "Lost connection to server.");
-        this.disconnect();
+    socket.on(SocketEventType.Disconnected, () => {
+      if (this.disconnected) {
+        return;
       }
+
+      this.emitError(PeerErrorType.Network, "Lost connection to server.");
+      this.disconnect();
     });
 
-    this.socket.on(SocketEventType.Close, () => {
-      // If we haven't explicitly disconnected, emit error.
-      if (!this.disconnected) {
-        this._abort(
-          PeerErrorType.SocketClosed,
-          "Underlying socket is already closed."
-        );
+    socket.on(SocketEventType.Close, () => {
+      if (this.disconnected) {
+        return;
       }
+
+      this._abort(PeerErrorType.SocketClosed, "Underlying socket is already closed.");
     });
+
+    return socket;
   }
 
   /** Initialize a connection with the server. */
   private _initialize(id: string): void {
     this._id = id;
-    this.socket.start(this.id, this._options.token);
+    this.socket.start(id, this._options.token!);
   }
 
   /** Handles messages from the server. */
@@ -221,8 +219,9 @@ export class Peer extends EventEmitter {
 
     switch (type) {
       case ServerMessageType.Open: // The connection to the server is open.
-        this.emit(PeerEventType.Open, this.id);
+        this._lastServerId = this.id;
         this._open = true;
+        this.emit(PeerEventType.Open, this.id);
         break;
       case ServerMessageType.Error: // Server error.
         this._abort(PeerErrorType.ServerError, payload.msg);
@@ -231,21 +230,15 @@ export class Peer extends EventEmitter {
         this._abort(PeerErrorType.UnavailableID, `ID "${this.id}" is taken`);
         break;
       case ServerMessageType.InvalidKey: // The given API key cannot be found.
-        this._abort(
-          PeerErrorType.InvalidKey,
-          `API KEY "${this._options.key}" is invalid`
-        );
+        this._abort(PeerErrorType.InvalidKey, `API KEY "${this._options.key}" is invalid`);
         break;
       case ServerMessageType.Leave: // Another peer has closed its connection to this peer.
-        logger.log("Received leave message from", peerId);
+        logger.log(`Received leave message from ${peerId}`);
         this._cleanupPeer(peerId);
         this._connections.delete(peerId);
         break;
       case ServerMessageType.Expire: // The offer sent to a peer has expired without response.
-        this.emitError(
-          PeerErrorType.PeerUnavailable,
-          "Could not connect to peer " + peerId
-        );
+        this.emitError(PeerErrorType.PeerUnavailable, `Could not connect to peer ${peerId}`);
         break;
       case ServerMessageType.Offer: {
         // we should consider switching this to CALL/CONNECT, but this is the least breaking option.
@@ -254,7 +247,7 @@ export class Peer extends EventEmitter {
 
         if (connection) {
           connection.close();
-          logger.warn("Offer received for existing Connection ID:", connectionId);
+          logger.warn(`Offer received for existing Connection ID:${connectionId}`);
         }
 
         // Create a new connection.
@@ -278,7 +271,7 @@ export class Peer extends EventEmitter {
           this._addConnection(peerId, connection);
           this.emit(PeerEventType.Connection, connection);
         } else {
-          logger.warn("Received malformed connection type:", payload.type);
+          logger.warn(`Received malformed connection type:${payload.type}`);
           return;
         }
 
@@ -292,9 +285,7 @@ export class Peer extends EventEmitter {
       }
       default: {
         if (!payload) {
-          logger.warn(
-            `You received a malformed message from ${peerId} of type ${type}`
-          );
+          logger.warn(`You received a malformed message from ${peerId} of type ${type}`);
           return;
         }
 
@@ -395,10 +386,7 @@ export class Peer extends EventEmitter {
 
   /** Add a data/media connection to this peer. */
   private _addConnection(peerId: string, connection: BaseConnection): void {
-    logger.log(
-      `add connection ${connection.type}:${connection.connectionId}
-       to peerId:${peerId}`
-    );
+    logger.log(`add connection ${connection.type}:${connection.connectionId} to peerId:${peerId}`);
 
     if (!this._connections.has(peerId)) {
       this._connections.set(peerId, []);
@@ -438,7 +426,7 @@ export class Peer extends EventEmitter {
     return null;
   }
 
-  private _delayedAbort(type: PeerErrorType, message): void {
+  private _delayedAbort(type: PeerErrorType, message: string | Error): void {
     setTimeout(() => {
       this._abort(type, message);
     }, 0);
@@ -449,7 +437,7 @@ export class Peer extends EventEmitter {
    * The Peer is not destroyed if it's in a disconnected state, in which case
    * it retains its disconnected state and its existing connections.
    */
-  private _abort(type: PeerErrorType, message): void {
+  private _abort(type: PeerErrorType, message: string | Error): void {
     logger.error("Aborting!");
 
     this.emitError(type, message);
@@ -462,16 +450,20 @@ export class Peer extends EventEmitter {
   }
 
   /** Emits a typed error message. */
-  emitError(type: PeerErrorType, err): void {
+  emitError(type: PeerErrorType, err: string | Error): void {
     logger.error("Error:", err);
 
+    let error: Error & { type?: PeerErrorType };
+
     if (typeof err === "string") {
-      err = new Error(err);
+      error = new Error(err);
+    } else {
+      error = err as Error;
     }
 
-    err.type = type;
+    error.type = type;
 
-    this.emit(PeerEventType.Error, err);
+    this.emit(PeerEventType.Error, error);
   }
 
   /**
@@ -481,11 +473,18 @@ export class Peer extends EventEmitter {
    *  destroyed.
    */
   destroy(): void {
-    if (!this.destroyed) {
-      this._cleanup();
-      this.disconnect();
-      this._destroyed = true;
+    if (this.destroyed) {
+      return;
     }
+
+    logger.log(`Destroy peer with ID:${this.id}`);
+
+    this.disconnect();
+    this._cleanup();
+
+    this._destroyed = true;
+
+    this.emit(PeerEventType.Close);
   }
 
   /** Disconnects every connection on this peer. */
@@ -495,7 +494,7 @@ export class Peer extends EventEmitter {
       this._connections.delete(peerId);
     }
 
-    this.emit(PeerEventType.Close);
+    this.socket.removeAllListeners();
   }
 
   /** Closes all connections to this peer. */
@@ -516,45 +515,38 @@ export class Peer extends EventEmitter {
    *  disconnected. It also cannot reconnect to the server.
    */
   disconnect(): void {
-    setTimeout(() => {
-      if (!this.disconnected) {
-        this._disconnected = true;
-        this._open = false;
-        if (this.socket) {
-          this.socket.close();
-        }
+    if (this.disconnected) {
+      return;
+    }
 
-        this.emit(PeerEventType.Disconnected, this.id);
-        this._lastServerId = this.id;
-        this._id = null;
-      }
-    }, 0);
+    const currentId = this.id;
+
+    logger.log(`Disconnect peer with ID:${currentId}`);
+
+    this._disconnected = true;
+    this._open = false;
+
+    this.socket.close();
+
+    this._lastServerId = currentId;
+    this._id = null;
+
+    this.emit(PeerEventType.Disconnected, currentId);
   }
 
   /** Attempts to reconnect with the same ID. */
   reconnect(): void {
     if (this.disconnected && !this.destroyed) {
-      logger.log(
-        "Attempting reconnection to server with ID " + this._lastServerId
-      );
+      logger.log(`Attempting reconnection to server with ID ${this._lastServerId}`);
       this._disconnected = false;
-      this._initializeServerConnection();
-      this._initialize(this._lastServerId);
+      this._initialize(this._lastServerId!);
     } else if (this.destroyed) {
-      throw new Error(
-        "This peer cannot reconnect to the server. It has already been 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.
-      logger.error(
-        "In a hurry? We're still trying to make the initial connection!"
-      );
+      logger.error("In a hurry? We're still trying to make the initial connection!");
     } else {
-      throw new Error(
-        "Peer " +
-        this.id +
-        " cannot reconnect because it is not disconnected from the server!"
-      );
+      throw new Error(`Peer ${this.id} cannot reconnect because it is not disconnected from the server!`);
     }
   }
 

+ 32 - 19
lib/socket.ts

@@ -7,12 +7,12 @@ import { SocketEventType, ServerMessageType } from "./enums";
  * possible connection for peers.
  */
 export class Socket extends EventEmitter {
-  private _disconnected = false;
+  private _disconnected: boolean = true;
   private _id?: string;
-  private _messagesQueue: Array<any> = [];
-  private _wsUrl: string;
+  private _messagesQueue: Array<object> = [];
   private _socket?: WebSocket;
-  private _wsPingTimer: any;
+  private _wsPingTimer?: any;
+  private readonly _baseUrl: string;
 
   constructor(
     secure: any,
@@ -26,25 +26,20 @@ export class Socket extends EventEmitter {
 
     const wsProtocol = secure ? "wss://" : "ws://";
 
-    this._wsUrl = wsProtocol + host + ":" + port + path + "peerjs?key=" + key;
+    this._baseUrl = wsProtocol + host + ":" + port + path + "peerjs?key=" + key;
   }
 
-  /** Check in with ID or get one from server. */
   start(id: string, token: string): void {
     this._id = id;
 
-    this._wsUrl += "&id=" + id + "&token=" + token;
+    const wsUrl = `${this._baseUrl}&id=${id}&token=${token}`;
 
-    this._startWebSocket();
-  }
-
-  /** Start up websocket communications. */
-  private _startWebSocket(): void {
-    if (this._socket) {
+    if (!!this._socket || !this._disconnected) {
       return;
     }
 
-    this._socket = new WebSocket(this._wsUrl);
+    this._socket = new WebSocket(wsUrl);
+    this._disconnected = false;
 
     this._socket.onmessage = (event) => {
       let data;
@@ -61,10 +56,14 @@ export class Socket extends EventEmitter {
     };
 
     this._socket.onclose = (event) => {
+      if (this._disconnected) {
+        return;
+      }
+
       logger.log("Socket closed.", event);
 
+      this._cleanup();
       this._disconnected = true;
-      clearTimeout(this._wsPingTimer);
 
       this.emit(SocketEventType.Disconnected);
     };
@@ -72,7 +71,9 @@ export class Socket extends EventEmitter {
     // Take care of the queue of connections if necessary and make sure Peer knows
     // socket is open.
     this._socket.onopen = () => {
-      if (this._disconnected) return;
+      if (this._disconnected) {
+        return;
+      }
 
       this._sendQueuedMessages();
 
@@ -146,10 +147,22 @@ export class Socket extends EventEmitter {
   }
 
   close(): void {
-    if (!this._disconnected && !!this._socket) {
+    if (this._disconnected) {
+      return;
+    }
+
+    this._cleanup();
+
+    this._disconnected = true;
+  }
+
+  private _cleanup(): void {
+    if (!!this._socket) {
+      this._socket.onopen = this._socket.onmessage = this._socket.onclose = null;
       this._socket.close();
-      this._disconnected = true;
-      clearTimeout(this._wsPingTimer);
+      this._socket = undefined;
     }
+
+    clearTimeout(this._wsPingTimer!);
   }
 }

+ 5 - 5
package-lock.json

@@ -1,6 +1,6 @@
 {
   "name": "peerjs",
-  "version": "1.0.4",
+  "version": "1.1.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -5789,12 +5789,12 @@
       }
     },
     "mock-socket": {
-      "version": "9.0.0",
-      "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.0.0.tgz",
-      "integrity": "sha512-8Q3y/chmcYRJ6oxhAO9QJwSr6ZWU2zuzD0A7tHa0HOyL83nInIqimFWuke7936IYjEuhBaOrruV+aemlB1f+aA==",
+      "version": "8.0.5",
+      "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-8.0.5.tgz",
+      "integrity": "sha512-dE2EbcxJKQCeYLZSsI7BAiMZCe/bHbJ2LHb5aGwUuDmfoOINEJ8QI6qYJ85NHsSNkNa90F3s6onZcmt/+MppFA==",
       "dev": true,
       "requires": {
-        "url-parse": "^1.4.4"
+        "url-parse": "^1.2.0"
       }
     },
     "ms": {

+ 1 - 1
package.json

@@ -27,7 +27,7 @@
     "jsdom": "^15.1.1",
     "jsdom-global": "^3.0.2",
     "mocha": "^6.2.0",
-    "mock-socket": "^9.0.0",
+    "mock-socket": "8.0.5",
     "parcel-bundler": "^1.12.3",
     "standard": "^14.1.0",
     "ts-node": "^8.3.0",

+ 10 - 0
test/logger.ts

@@ -2,6 +2,12 @@ import { expect } from "chai";
 import Logger, { LogLevel } from "../lib/logger";
 
 describe("Logger", function () {
+    let oldLoggerPrint;
+    before(() => {
+        //@ts-ignore
+        oldLoggerPrint = Logger._print;
+    });
+
     it("should be disabled by default", function () {
         expect(Logger.logLevel).to.eq(LogLevel.Disabled);
     });
@@ -42,4 +48,8 @@ describe("Logger", function () {
 
         expect(checkedLevels).to.deep.eq([LogLevel.All, LogLevel.Warnings, LogLevel.Errors]);
     });
+
+    after(() => {
+        Logger.setLogFunction(oldLoggerPrint);
+    })
 });

+ 147 - 20
test/peer.ts

@@ -2,15 +2,31 @@ import "./setup";
 import { expect } from "chai";
 import { Peer } from "../lib/peer";
 import { Server } from 'mock-socket';
-import { ConnectionType, ServerMessageType } from "../lib/enums";
+import { ConnectionType, ServerMessageType, PeerErrorType, PeerEventType } from "../lib/enums";
 
+const createMockServer = (): Server => {
+    const fakeURL = 'ws://localhost:8080/peerjs?key=peerjs&id=1&token=testToken';
+    const mockServer = new Server(fakeURL);
+
+    mockServer.on('connection', socket => {
+        //@ts-ignore
+        socket.on('message', data => {
+            socket.send('test message from mock server');
+        });
+
+        socket.send(JSON.stringify({ type: ServerMessageType.Open }));
+    });
+
+    return mockServer;
+}
 describe("Peer", function () {
     describe("after construct without parameters", function () {
         it("shouldn't contains any connection", function () {
             const peer = new Peer();
 
-            expect(peer.connections).to.deep.eq({});
-            expect(peer.id).to.be.undefined;
+            expect(peer.open).to.be.false;
+            expect(peer.connections).to.be.empty;
+            expect(peer.id).to.be.null;
             expect(peer.disconnected).to.be.false;
             expect(peer.destroyed).to.be.false;
 
@@ -19,15 +35,13 @@ describe("Peer", function () {
     });
 
     describe("after construct with parameters", function () {
-        it("should contains id and key", function (done) {
+        it("should contains id and key", function () {
             const peer = new Peer('1', { key: 'anotherKey' });
 
             expect(peer.id).to.eq('1');
             expect(peer.options.key).to.eq('anotherKey');
 
             peer.destroy();
-
-            setTimeout(() => done(), 0);
         });
     });
 
@@ -35,21 +49,12 @@ describe("Peer", function () {
         let mockServer;
 
         before(function () {
-            const fakeURL = 'ws://localhost:8080/peerjs?key=peerjs&id=1&token=testToken';
-            mockServer = new Server(fakeURL);
-
-            mockServer.on('connection', socket => {
-                //@ts-ignore
-                socket.on('message', data => {
-                    socket.send('test message from mock server');
-                });
-
-                socket.send(ServerMessageType.Open);
-            });
+            mockServer = createMockServer();
         });
 
         it("Peer#1 should has id #1", function (done) {
             const peer1 = new Peer('1', { port: 8080, host: 'localhost' });
+            expect(peer1.open).to.be.false;
 
             const mediaOptions = {
                 metadata: { var: '123' },
@@ -73,14 +78,136 @@ describe("Peer", function () {
             expect(mediaConnection.metadata).to.deep.eq(mediaOptions.metadata);
             expect(mediaConnection.peerConnection.getSenders()[0].track.id).to.eq(track.id);
 
-            peer1.destroy();
+            peer1.once('open', (id) => {
+                expect(id).to.be.eq('1');
+                //@ts-ignore
+                expect(peer1._lastServerId).to.be.eq('1');
+                expect(peer1.disconnected).to.be.false;
+                expect(peer1.destroyed).to.be.false;
+                expect(peer1.open).to.be.true;
+
+                peer1.destroy();
 
-            setTimeout(() => {
                 expect(peer1.disconnected).to.be.true;
+                expect(peer1.destroyed).to.be.true;
                 expect(peer1.open).to.be.false;
+                expect(peer1.connections).to.be.empty;
 
                 done();
-            }, 0);
+            });
+        });
+
+        after(function () {
+            mockServer.stop();
+        });
+    });
+
+    describe("reconnect", function () {
+        let mockServer;
+
+        before(function () {
+            mockServer = createMockServer();
+        });
+
+        it("connect to server => disconnect => reconnect => destroy", function (done) {
+            const peer1 = new Peer('1', { port: 8080, host: 'localhost' });
+
+            peer1.once('open', () => {
+                expect(peer1.open).to.be.true;
+
+                peer1.once('disconnected', () => {
+                    expect(peer1.disconnected).to.be.true;
+                    expect(peer1.destroyed).to.be.false;
+                    expect(peer1.open).to.be.false;
+
+                    peer1.once('open', (id) => {
+                        expect(id).to.be.eq('1');
+                        expect(peer1.disconnected).to.be.false;
+                        expect(peer1.destroyed).to.be.false;
+                        expect(peer1.open).to.be.true;
+
+                        peer1.once('disconnected', () => {
+                            expect(peer1.disconnected).to.be.true;
+                            expect(peer1.destroyed).to.be.false;
+                            expect(peer1.open).to.be.false;
+
+                            peer1.once('close', () => {
+                                expect(peer1.disconnected).to.be.true;
+                                expect(peer1.destroyed).to.be.true;
+                                expect(peer1.open).to.be.false;
+
+                                done();
+                            });
+                        });
+
+                        peer1.destroy();
+                    });
+
+                    peer1.reconnect();
+                });
+
+                peer1.disconnect();
+            });
+        });
+
+        it("disconnect => reconnect => destroy", function (done) {
+            mockServer.stop();
+
+            const peer1 = new Peer('1', { port: 8080, host: 'localhost' });
+
+            peer1.once('disconnected', (id) => {
+                expect(id).to.be.eq('1');
+                expect(peer1.disconnected).to.be.true;
+                expect(peer1.destroyed).to.be.false;
+                expect(peer1.open).to.be.false;
+
+                peer1.once('open', (id) => {
+                    expect(id).to.be.eq('1');
+                    expect(peer1.disconnected).to.be.false;
+                    expect(peer1.destroyed).to.be.false;
+                    expect(peer1.open).to.be.true;
+
+                    peer1.once('disconnected', () => {
+                        expect(peer1.disconnected).to.be.true;
+                        expect(peer1.destroyed).to.be.false;
+                        expect(peer1.open).to.be.false;
+
+                        peer1.once('close', () => {
+                            expect(peer1.disconnected).to.be.true;
+                            expect(peer1.destroyed).to.be.true;
+                            expect(peer1.open).to.be.false;
+
+                            done();
+                        });
+                    });
+
+                    peer1.destroy();
+                });
+
+                mockServer = createMockServer();
+
+                peer1.reconnect();
+            });
+        });
+
+        it("destroy peer if no id and no connection", function (done) {
+            mockServer.stop();
+
+            const peer1 = new Peer({ port: 8080, host: 'localhost' });
+
+            peer1.once(PeerEventType.Error, (error) => {
+                expect(error.type).to.be.eq(PeerErrorType.ServerError);
+
+                peer1.once(PeerEventType.Close, () => {
+                    expect(peer1.disconnected).to.be.true;
+                    expect(peer1.destroyed).to.be.true;
+                    expect(peer1.open).to.be.false;
+
+                    done();
+                });
+
+                mockServer = createMockServer();
+            });
         });
 
         after(function () {

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini