tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CdpSession.ts (4376B)


      1 /**
      2 * @license
      3 * Copyright 2017 Google Inc.
      4 * SPDX-License-Identifier: Apache-2.0
      5 */
      6 
      7 import type {ProtocolMapping} from 'devtools-protocol/types/protocol-mapping.js';
      8 
      9 import {
     10  type CDPEvents,
     11  CDPSession,
     12  CDPSessionEvent,
     13  type CommandOptions,
     14 } from '../api/CDPSession.js';
     15 import {CallbackRegistry} from '../common/CallbackRegistry.js';
     16 import {TargetCloseError} from '../common/Errors.js';
     17 import {assert} from '../util/assert.js';
     18 import {createProtocolErrorMessage} from '../util/ErrorLike.js';
     19 
     20 import type {Connection} from './Connection.js';
     21 import type {CdpTarget} from './Target.js';
     22 
     23 /**
     24 * @internal
     25 */
     26 
     27 export class CdpCDPSession extends CDPSession {
     28  #sessionId: string;
     29  #targetType: string;
     30  #callbacks = new CallbackRegistry();
     31  #connection: Connection;
     32  #parentSessionId?: string;
     33  #target?: CdpTarget;
     34  #rawErrors = false;
     35  #detached = false;
     36  /**
     37   * @internal
     38   */
     39  constructor(
     40    connection: Connection,
     41    targetType: string,
     42    sessionId: string,
     43    parentSessionId: string | undefined,
     44    rawErrors: boolean,
     45  ) {
     46    super();
     47    this.#connection = connection;
     48    this.#targetType = targetType;
     49    this.#sessionId = sessionId;
     50    this.#parentSessionId = parentSessionId;
     51    this.#rawErrors = rawErrors;
     52  }
     53 
     54  /**
     55   * Sets the {@link CdpTarget} associated with the session instance.
     56   *
     57   * @internal
     58   */
     59  setTarget(target: CdpTarget): void {
     60    this.#target = target;
     61  }
     62 
     63  /**
     64   * Gets the {@link CdpTarget} associated with the session instance.
     65   *
     66   * @internal
     67   */
     68  target(): CdpTarget {
     69    assert(this.#target, 'Target must exist');
     70    return this.#target;
     71  }
     72 
     73  override connection(): Connection | undefined {
     74    return this.#connection;
     75  }
     76 
     77  override get detached(): boolean {
     78    return this.#connection._closed || this.#detached;
     79  }
     80 
     81  override parentSession(): CDPSession | undefined {
     82    if (!this.#parentSessionId) {
     83      // In some cases, e.g., DevTools pages there is no parent session. In this
     84      // case, we treat the current session as the parent session.
     85      return this;
     86    }
     87    const parent = this.#connection?.session(this.#parentSessionId);
     88    return parent ?? undefined;
     89  }
     90 
     91  override send<T extends keyof ProtocolMapping.Commands>(
     92    method: T,
     93    params?: ProtocolMapping.Commands[T]['paramsType'][0],
     94    options?: CommandOptions,
     95  ): Promise<ProtocolMapping.Commands[T]['returnType']> {
     96    if (this.detached) {
     97      return Promise.reject(
     98        new TargetCloseError(
     99          `Protocol error (${method}): Session closed. Most likely the ${this.#targetType} has been closed.`,
    100        ),
    101      );
    102    }
    103    return this.#connection._rawSend(
    104      this.#callbacks,
    105      method,
    106      params,
    107      this.#sessionId,
    108      options,
    109    );
    110  }
    111 
    112  /**
    113   * @internal
    114   */
    115  onMessage(object: {
    116    id?: number;
    117    method: keyof CDPEvents;
    118    params: CDPEvents[keyof CDPEvents];
    119    error: {message: string; data: any; code: number};
    120    result?: any;
    121  }): void {
    122    if (object.id) {
    123      if (object.error) {
    124        if (this.#rawErrors) {
    125          this.#callbacks.rejectRaw(object.id, object.error);
    126        } else {
    127          this.#callbacks.reject(
    128            object.id,
    129            createProtocolErrorMessage(object),
    130            object.error.message,
    131          );
    132        }
    133      } else {
    134        this.#callbacks.resolve(object.id, object.result);
    135      }
    136    } else {
    137      assert(!object.id);
    138      this.emit(object.method, object.params);
    139    }
    140  }
    141 
    142  /**
    143   * Detaches the cdpSession from the target. Once detached, the cdpSession object
    144   * won't emit any events and can't be used to send messages.
    145   */
    146  override async detach(): Promise<void> {
    147    if (this.detached) {
    148      throw new Error(
    149        `Session already detached. Most likely the ${this.#targetType} has been closed.`,
    150      );
    151    }
    152    await this.#connection.send('Target.detachFromTarget', {
    153      sessionId: this.#sessionId,
    154    });
    155    this.#detached = true;
    156  }
    157 
    158  /**
    159   * @internal
    160   */
    161  onClosed(): void {
    162    this.#callbacks.clear();
    163    this.#detached = true;
    164    this.emit(CDPSessionEvent.Disconnected, undefined);
    165  }
    166 
    167  /**
    168   * Returns the session's id.
    169   */
    170  override id(): string {
    171    return this.#sessionId;
    172  }
    173 
    174  /**
    175   * @internal
    176   */
    177  getPendingProtocolErrors(): Error[] {
    178    return this.#callbacks.getPendingProtocolErrors();
    179  }
    180 }