std4453/bilibili-danmaku-client

View on GitHub
src/index.js

Summary

Maintainability
A
0 mins
Test Coverage
/**
 * This file contains the class definition of DanmakuClient, the only API
 * open to applications.
 * The Wiki page 'DanmakuClient' contains more choreographed documentation,
 * see that instead.
 */

const EventEmitter = require('events');

const ApplicationConnection = require('./application');

/**
 * DanmakuClient is the only open API to applications.
 * Internally it is a thin wrap over ApplicationConnection, which provides a
 * more explicit control of the lifecycle and partial backwards compatibility
 * to the old version.
 * The lifecycle of DanmakuClient is as follows:
 * - Start from state 'idle'.
 * - 'idle' -> 'opening': On start().
 * - 'opening' -> 'opened': When connection is successfully opened. Emit event 'open'.
 *             -> 'closing': On terminate().
 *             -> 'closed': If the connection is closed by the server. Emit event 'close'.
 *             -> 'closed': If an error has occurred. Emit event 'close'. Emit event
 *                          'error' with the error.
 * - 'opened' -> 'closing': On terminate().
 *            -> 'closed': If the connection is closed by the server. Emit event 'close'.
 *            -> 'closed': If an error has occurred. Emit event 'close'. Emit event
 *                         'error' with the error.
 * - 'closing' -> 'closed': When connection is succefully closed. Emit event 'close'.
 * - End in state 'closed'.
 */
class DanmakuClient extends EventEmitter {
    /**
     * Construct a new DanmakuClient with the given Room id and options.
     * Note that the Room id must be the original Room id, that is, the short Room id
     * is not accepted.
     * For example, one of the official Live Rooms, https://live.bilibili.com/1,
     * uses the original Room id 5440. In this case, trying to connect to Room 1 would
     * not work properly, the correct way is to connect to Room 5440.
     * @param {Number} room The id of the Room to connect to.
     * @param {Object} [options] The options to pass to ApplicationConnection.
     *   Use this only when you know what you're doing.
     */
    constructor(room, options) {
        super();

        this.room = room;
        this.options = options;
        this.state = 'idle';
    }

    /**
     * Start the DanmakuClient.
     * This method is only available in state 'idle'. Otherwise nothing will happen.
     * Internally the underlying ApplicationConnection is not created before start(),
     * so this.connection will not be available then,
     */
    start() {
        if (this.state !== 'idle') return;
        this.connection = new ApplicationConnection(this.room, this.options);
        this.state = 'opening';
        this.connection.on('open', () => {
            this.state = 'opened';
            this.emit('open');
        });
        this.connection.on('error', err => this.emit('error', err));
        this.connection.on('close', () => {
            this.state = 'closed';
            this.emit('close');
        });
        this.connection.on('message', event => this.emit('event', event));
    }

    /**
     * Request closing of the DanmakuClient.
     * Note that this method will return immediately after requesting. The client will
     * be actually closed at time when the 'close' event is emitted.
     */
    terminate() {
        if (this.state === 'opening' || this.state === 'opened') this.connection.close();
    }
}

module.exports = DanmakuClient;