remote/Connection.jsm
author Tooru Fujisawa <arai_a@mac.com>
Wed, 13 Mar 2019 02:46:12 +0000
changeset 521645 c1e2b7779d6a13626b13bbb1916f8819756a19ff
parent 521340 fde0fa0c16da411aa5b39f423e7be6715ee3d54a
child 524258 ad30588da467bdd3288596be8db8e1a809a7cc47
permissions -rw-r--r--
Bug 1505343 - Part 1: Rename binsource => binast. r=Yoric Differential Revision: https://phabricator.services.mozilla.com/D23097

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

var EXPORTED_SYMBOLS = ["Connection"];

const {Log} = ChromeUtils.import("chrome://remote/content/Log.jsm");
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");

XPCOMUtils.defineLazyGetter(this, "log", Log.get);
XPCOMUtils.defineLazyServiceGetter(this, "UUIDGen", "@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");

class Connection {
  constructor(transport) {
    this.id = UUIDGen.generateUUID().toString();
    this.transport = transport;

    this.transport.hooks = this;
    this.transport.ready();

    this.defaultSession = null;
    this.sessions = new Map();
  }

  /**
   * Register a new Session to forward the messages to.
   * Session without any `id` attribute will be considered to be the
   * default one, to which messages without `sessionId` attribute are
   * forwarded to. Only one such session can be registered.
   *
   * @param Session session
   */
  registerSession(session) {
    if (!session.id) {
      if (this.defaultSession) {
        throw new Error("Default session is already set on Connection," +
                        "can't register another one.");
      }
      this.defaultSession = session;
    }
    this.sessions.set(session.id, session);
  }

  send(message) {
    log.trace(`<-(connection ${this.id}) ${JSON.stringify(message)}`);
    this.transport.send(message);
  }

  error(id, e) {
    const error = {
      message: e.message,
      data: e.stack,
    };
    this.send({id, error});
  }

  deserialize(data) {
    const id = data.id;
    const method = data.method;
    const params = data.params || {};
    return {id, method, params};
  }

  // transport hooks

  onPacket(packet) {
    log.trace(`(connection ${this.id})-> ${JSON.stringify(packet)}`);

    let message = {id: null};
    try {
      message = this.deserialize(packet);
      const { sessionId } = packet;
      if (!sessionId) {
        if (!this.defaultSession) {
          throw new Error(`Connection is missing a default Session.`);
        }
        this.defaultSession.onMessage(message);
      } else {
        const session = this.sessions.get(sessionId);
        if (!session) {
          throw new Error(`Session '${sessionId}' doesn't exists.`);
        }
        session.onMessage(message);
      }
    } catch (e) {
      log.warn(e);
      this.error(message.id, e);
    }
  }

  close() {
    this.transport.close();
    this.sessions.clear();
  }

  onClosed(status) {}

  toString() {
    return `[object Connection ${this.id}]`;
  }
}