Home Manual Reference Source Test Repository

src/Channel.js

/**
 * A P2P communication channel
 * @protected
 */
export default class Channel {
  /**
   * Instantiates a new Channel object
   * @protected
   * @param {DataChannel} dataChannel - The DataChannel to operate on
   * @param {SignalFactory} signalFactory - Instance factory for event signals
   */
  constructor(dataChannel, signalFactory) {
    /**
     * The DataChannel to operate on
     * @private
     * @type {DataChannel}
     */
    this.dataChannel = dataChannel;
    /**
     * Event container
     * @type {Object<string, Signal>}
     * @property {Signal} userJoin - Signal for userJoin event
     * @property {Signal} userLeave - Signal for userLeave event
     * @property {Signal} message - Signal for message event
     */
    this.on = {
      userJoin: signalFactory.instance(),
      userLeave: signalFactory.instance(),
      message: signalFactory.instance(),
    };
    this.registerDataChannelEvents();
  }

  /**
   * Gets the channel ID
   * @protected
   * @return {string} The channel ID
   */
  getID() {
    return this.dataChannel.channel;
  }

  /**
   * Gets the user’s unique ID
   * @protected
   * @return {string} The user’s ID
   */
  getUserID() {
    return this.dataChannel.userid;
  }

  /**
   * Gets the number of currently connected users
   * @protected
   * @return {Promise<number>} Currently connected users including the active user
   */
  getNumberOfUsers() {
    // needs to be done asynchronous because DataChannel updates number only after the listeners
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve(1 + Object.keys(this.dataChannel.channels).length);
      }, 1);
    });
  }

  /**
   * Gets the other users’ unique IDs
   * @protected
   * @return {Promise<Array<string>>} The other users’ IDs
   */
  getOtherUserIDs() {
    // needs to be done asynchronous because DataChannel updates number only after the listeners
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve(Object.keys(this.dataChannel.channels));
      }, 1);
    });
  }

  /**
   * Registers events on the DataChannel
   * @private
   * @emits {userJoin} when a new user joined the channel
   * @emits {userLeave} when a user left the channel
   * @emits {message} when a message was received over  the channel
   */
  registerDataChannelEvents() {
    this.dataChannel.onopen = (userID) => this.on.userJoin.dispatch(userID);
    this.dataChannel.onleave = (userID) => this.on.userLeave.dispatch(userID);
    this.dataChannel.onclose = () => {};
    this.dataChannel.onmessage = (message, userID) => this.on.message.dispatch(message, userID);
  }

  /**
   * Sends data over the DataChannel
   * @protected
   * @param {Object|string} data - The data
   */
  send(data) {
    this.dataChannel.send(data);
  }

  /**
   * Sends data over the DataChannel to a specific user only
   * @protected
   * @param {string} userID - The receiver’s user ID
   * @param {Object|string} data - The data
   */
  sendPrivately(userID, data) {
    this.dataChannel.channels[userID].send(data);
  }
}