{"size": 2491, "ext": "js", "max_stars_repo_path": "lib/Tracing.js", "max_stars_repo_name": "N0taN3rd/chrome-remote-interface-extra", "max_stars_repo_stars_event_min_datetime": "2019-02-10T14:57:08.000Z", "max_stars_repo_stars_event_max_datetime": "2022-03-12T06:31:02.000Z", "max_issues_repo_path": "lib/Tracing.js", "max_issues_repo_name": "N0taN3rd/chrome-remote-interface-extra", "max_issues_repo_issues_event_min_datetime": "2020-07-16T18:11:23.000Z", "max_issues_repo_issues_event_max_datetime": "2021-09-01T01:04:22.000Z", "max_forks_repo_path": "lib/Tracing.js", "max_forks_repo_name": "N0taN3rd/chrome-remote-interface-extra", "max_forks_repo_forks_event_min_datetime": "2021-07-16T03:02:13.000Z", "max_forks_repo_forks_event_max_datetime": "2021-07-16T03:02:13.000Z"}
{"max_stars_count": 10, "max_issues_count": 4, "max_forks_count": 1, "avg_line_length": 25.1616161616, "max_line_length": 91, "alphanum_fraction": 0.6154154958}
const fs = require('fs-extra')
const { assert } = require('./helper')

class Tracing {
  /**
   * @param {Chrome|CRIConnection|CDPSession|Object} client
   */
  constructor (client) {
    /**
     * @type {Chrome|CRIConnection|CDPSession|Object}
     * @private
     */
    this._client = client
    this._recording = false
    this._path = ''
  }

  /**
   * @param {!{path?: string, screenshots?: boolean, categories?: Array<string>}} [options]
   */
  async start (options = {}) {
    assert(
      !this._recording,
      'Cannot start recording trace while already recording trace.'
    )

    const defaultCategories = [
      '-*',
      'devtools.timeline',
      'v8.execute',
      'disabled-by-default-devtools.timeline',
      'disabled-by-default-devtools.timeline.frame',
      'toplevel',
      'blink.console',
      'blink.user_timing',
      'latencyInfo',
      'disabled-by-default-devtools.timeline.stack',
      'disabled-by-default-v8.cpu_profiler',
      'disabled-by-default-v8.cpu_profiler.hires'
    ]
    const {
      path = null,
      screenshots = false,
      categories = defaultCategories
    } = options

    if (screenshots) categories.push('disabled-by-default-devtools.screenshot')

    this._path = path
    this._recording = true
    await this._client.send('Tracing.start', {
      transferMode: 'ReturnAsStream',
      categories: categories.join(',')
    })
  }

  /**
   * @return {Promise<Buffer>}
   */
  async stop () {
    let fulfill
    const contentPromise = new Promise(resolve => (fulfill = resolve))
    this._client.once('Tracing.tracingComplete', event => {
      this._readStream(event.stream, this._path).then(fulfill)
    })
    await this._client.send('Tracing.end')
    this._recording = false
    return contentPromise
  }

  /**
   * @param {string} handle
   * @param {?string} path
   * @return {Buffer}
   */
  async _readStream (handle, path) {
    let eof = false
    let file
    if (path) file = await fs.open(path, 'w')
    const bufs = []
    const ioArgs = { handle }
    while (!eof) {
      const response = await this._client.send('IO.read', ioArgs)
      eof = response.eof
      bufs.push(Buffer.from(response.data))
      if (path) await fs.write(file, response.data)
    }
    if (path) await fs.close(file)
    await this._client.send('IO.close', ioArgs)
    let resultBuffer = null
    try {
      resultBuffer = Buffer.concat(bufs)
    } catch (_) {}
    return resultBuffer
  }
}

module.exports = Tracing
