coast-team/netflux

View on GitHub
src/BotFacade.ts

Summary

Maintainability
C
1 day
Test Coverage
import { Server as HttpServer } from 'http'
import { Server as HttpsServer } from 'https'
import { Bot as BotServer, IBotOptions as BotOptions } from './Bot'
import { WebGroup } from './WebChannelFacade'

let botServer: BotServer
export { BotOptions }

/**
 * Bot server may be a member of severals groups. Each group is isolated.
 * He can be invited by a group member via {@link WebGroup#invite} method.
 * @example
 * // In NodeJS:
 * // Create a bot server with full mesh topology, without autorejoin feature
 * // and with specified Signaling and ICE servers for WebRTC.
 * // Bot server is listening on 'ws://BOT_HOST:BOT_PORT'.
 *
 * const http = require('http')
 * const server = http.createServer()
 * const bot = new Bot({
 *   server,
 *   webGroupOptions: {
 *     signalingServer: 'wss://mysignaling.com',
 *     rtcConfiguration: {
 *       iceServers: [
 *         {
 *           urls: 'stun.l.google.com:19302'
 *         },
 *         {
 *           urls: ['turn:myturn.com?transport=udp', 'turn:myturn?transport=tcp'],
 *           username: 'user',
 *           password: 'password'
 *         }
 *       ]
 *     }
 *   }
 * })
 *
 * bot.onWebGroup = (wg) => {
 *   // YOUR CODE
 * }
 *
 * bot.onError = (err) => {
 *   // YOUR CODE
 * }
 *
 * server.listen(BOT_PORT, BOT_HOST)
 */
export class Bot {
  public server: HttpServer | HttpsServer
  public perMessageDeflate: boolean
  public webGroups: Map<number, WebGroup>
  public url: string
  public leaveOnceAlone: boolean
  public onWebGroup: (((wg: WebGroup) => void)) | undefined | null
  public onError: (((err: Error) => void)) | undefined | null

  /**
   * @param {BotOptions} options
   * @param {HttpServer|HttpsServer} options.server NodeJS http(s) server.
   * @param {string} [options.url] Bot server URL.
   * @param {boolean} [options.perMessageDeflate=false] Enable/disable permessage-deflate.
   * @param {boolean} [options.leaveOnceAlone=false] If true, bot will live (disconnect from the signaling server) if no other peers left in the group.
   * @param {WebGroupOptions} options.webGroupOptions Options for each {@link WebGroup} the bot is member of.
   * @param {Topology} [options.webGroupOptions.topology=Topology.FULL_MESH]
   * @param {string} [options.webGroupOptions.signalingServer='wss://signaling.netflux.coedit.re']
   * @param {RTCConfiguration} [options.webGroupOptions.rtcConfiguration={iceServers: [{urls: 'stun:stun3.l.google.com:19302'}]}]
   * @param {boolean} [options.webGroupOptions.autoRejoin=true]
   */
  constructor(options: BotOptions) {
    botServer = new BotServer(options)

    /**
     * Read-only NodeJS http server instance.
     * @type {HttpServer|HttpsServer}
     */
    this.server = undefined as any
    Reflect.defineProperty(this, 'server', {
      configurable: false,
      enumerable: true,
      get: () => botServer.server,
    })

    /**
     * Read-only property of WebSocket server: permessage-deflate.
     * @type {HttpServer|HttpsServer}
     */
    this.perMessageDeflate = undefined as any
    Reflect.defineProperty(this, 'perMessageDeflate', {
      configurable: false,
      enumerable: true,
      get: () => botServer.perMessageDeflate,
    })

    /**
     * Read-only property leaveOnceAlone.
     * @type {HttpServer|HttpsServer}
     */
    this.leaveOnceAlone = undefined as any
    Reflect.defineProperty(this, 'leaveOnceAlone', {
      configurable: false,
      enumerable: true,
      get: () => botServer.leaveOnceAlone,
    })

    /**
     * Read-only set of web groups the bot is member of.
     * @type {Set<WebGroup>}
     */
    this.webGroups = undefined as any
    Reflect.defineProperty(this, 'webGroups', {
      configurable: false,
      enumerable: true,
      get: () => botServer.webGroups,
    })

    /**
     * Bot server url. Used to invite the bot in a web group via {@link WebGroup#invite} method.
     * @type {string}
     */
    this.url = undefined as any
    Reflect.defineProperty(this, 'url', {
      configurable: false,
      enumerable: true,
      get: () => botServer.url,
    })

    /**
     * This handler is called when the bot has been invited into a group by one of its members.
     * @type  {function(wg: WebGroup)} handler
     */
    this.onWebGroup = undefined as any
    Reflect.defineProperty(this, 'onWebGroup', {
      configurable: true,
      enumerable: true,
      get: () => (botServer.onWebGroup.name === 'none' ? undefined : botServer.onWebGroup),
      set: (handler: (wg: WebGroup) => void) => {
        if (typeof handler !== 'function') {
          botServer.onWebGroup = function none() {}
        } else {
          botServer.onWebGroup = handler
        }
      },
    })

    /**
     * This handler is called when an error occurs on WebSocket server.
     * @type  {function(err: Error)}
     */
    this.onError = undefined as any
    Reflect.defineProperty(this, 'onError', {
      configurable: true,
      enumerable: true,
      get: () => (botServer.onError.name === 'none' ? undefined : botServer.onError),
      set: (handler: (err: Error) => void) => {
        if (typeof handler !== 'function') {
          botServer.onError = function none() {}
        } else {
          botServer.onError = handler
        }
      },
    })
  }
}