<commit_before>'use strict';

var http = require('http');
var querystring = require('querystring');
var BufferList = require('bl');

function Rpc(agent, options) {
  this.agent = agent;
  this.host = options.host;
  this.port = options.port;
}

// Rpc.prototype.echo = function(options, callback) {};

Rpc.prototype.report = function(callback) {
  this._call('report', undefined, {}, callback);
};

// Rpc.prototype.playScript = function(options, callback) {};
// Rpc.prototype.tuneReplication = function(options, callback) {};
// Rpc.prototype.status = function(options, callback) {};
// Rpc.prototype.clear = function(options, callback) {};
// Rpc.prototype.synchronize = function(options, callback) {};
// Rpc.prototype.append = function(options, callback) {};
// Rpc.prototype.increment = function(options, callback) {};
// Rpc.prototype.incrementDouble = function(options, callback) {};
// Rpc.prototype.cas = function(options, callback) {};
// Rpc.prototype.check = function(options, callback) {};
// Rpc.prototype.seize = function(options, callback) {};
// Rpc.prototype.setBulk = function(options, callback) {};
// Rpc.prototype.removeBulk = function(options, callback) {};
// Rpc.prototype.getBulk = function(options, callback) {};
// Rpc.prototype.vacuum = function(options, callback) {};

Rpc.prototype.matchPrefix = function(prefix, options, callback) {
  var cb, opt = {}, params = {};

  if (typeof options === 'function') {
    opt = {};
    cb = options;
  } else {
    opt = options;
    cb = callback;
  }

  params.prefix = prefix;

  if (typeof opt.db !== 'undefined') {
    params.DB = opt.db;
  }

  if (typeof opt.max !== 'undefined') {
    params.max = opt.max;
  }

  cb = function(error, res) {
    callback(error, res);
  };

  this._call('match_prefix', {}, function(error, ret) {
    var data = {}, num;

    if (typeof error !== 'undefined') {
      cb(error);
    }

    for (var key in ret) {
      if (ret.hasOwnProperty(key)) {
        if (key === 'num') {
          num = ret[key];
        } else {
          data[key.substr(1)] = ret[key];
        }
      }
    }
    cb(undefined, data, num);
  });
};

// Rpc.prototype.matchRegex = function(options, callback) {};
// Rpc.prototype.matchSimilar = function(options, callback) {};
// Rpc.prototype.curJump = function(options, callback) {};
// Rpc.prototype.curJumpBack = function(options, callback) {};
// Rpc.prototype.curStep = function(options, callback) {};
// Rpc.prototype.curStepBack = function(options, callback) {};
// Rpc.prototype.curSetValue = function(options, callback) {};
// Rpc.prototype.curRemove = function(options, callback) {};
// Rpc.prototype.curGetGey = function(options, callback) {};
// Rpc.prototype.curGetValue = function(options, callback) {};
// Rpc.prototype.curGet = function(options, callback) {};
// Rpc.prototype.curSeize = function(options, callback) {};
// Rpc.prototype.curDelete = function(options, callback) {};

Rpc.prototype._call = function(method, params, options, callback) {
  var paramStr = '';
  if (typeof params !== 'undefined') {
    paramStr = '?' + querystring.stringify(params);
  }
  var requestOptions = {
    hostname: this.host,
    port: this.port,
    path: '/rpc/' + method + paramStr,
    method: 'GET',
    agent: this.agent
  };

  http.request(requestOptions, function(res) {
    var buf = new BufferList(), str = '';

    res.on('data', function(chunk) {
      if (Buffer.isBuffer(chunk)) {
        buf.append(chunk);
      } else {
        str += chunk;
      }
    });

    res.on('end', function() {
      var ret;

      if (res.statusCode === 204) {
        if (buf.length) {
          // TSV-RPC response is string only
          ret = buf.toString();
        } else {
          ret = str;
        }

        if (res.headers['Content-Type'].indexOf('colenc=B')) {
          callback(undefined, this._parseBase64Encode(ret, options.encode));
        } else if (res.headers['Content-Type'].indexOf('colenc=U')) {
          callback(undefined, this._parseURLEncode(ret));
        } else {
          callback(undefined, this._parse(ret));
        }
      } else if (res.statusCode === 404) {
        callback('No record was found');
      } else {
        callback('Connection error');
      }
    });
  }).on('error', function() {
    callback('Connection error');
  }).end();
};

Rpc.prototype._parse = function(tsv) {
  var lines = [], kv = [], ret = {};

  lines = tsv.split('\n');

  for (var i = 0; i < lines.length; ++i) {
    kv = lines.split('\t');
    ret[kv[0]] = kv[1];
  }

  return ret;
};

Rpc.prototype._parseBase64Encode = function(tsv, encode) {
  var lines = [], kv = [], ret = {}, i = 0;

  lines = tsv.split('\n');

  if (typeof encode === 'undefined' || encode === null) {
    for (; i < lines.length; ++i) {
      kv = lines.split('\t');
      ret[new Buffer(kv[0], 'base64').toString()] =
        new Buffer(kv[1], 'base64').toString();
    }
  } else if (encode === 'binary') {
    for (; i < lines.length; ++i) {
      kv = lines.split('\t');
      ret[new Buffer(kv[0], 'base64').toString()] = new Buffer(kv[1], 'base64');
    }
  } else {
    for (; i < lines.length; ++i) {
      kv = lines.split('\t');
      ret[new Buffer(kv[0], 'base64').toString(encode)] =
        new Buffer(kv[1], 'base64').toString(encode);
    }
  }

  return ret;
};

Rpc.prototype._parseURLEncode = function(tsv) {
  var lines = [], kv = [], ret = {};

  lines = tsv.split('\n');

  for (var i = 0; i < lines.length; ++i) {
    kv = lines.split('\t');
    ret[decodeURIComponent(kv[0])] = decodeURIComponent(kv[1]);
  }

  return ret;
};

module.exports = Rpc;
<commit_msg>Fixed rpc status code<commit_after>'use strict';

var http = require('http');
var querystring = require('querystring');
var BufferList = require('bl');

function Rpc(agent, options) {
  this.agent = agent;
  this.host = options.host;
  this.port = options.port;
}

// Rpc.prototype.echo = function(options, callback) {};

Rpc.prototype.report = function(callback) {
  this._call('report', undefined, {}, callback);
};

// Rpc.prototype.playScript = function(options, callback) {};
// Rpc.prototype.tuneReplication = function(options, callback) {};
// Rpc.prototype.status = function(options, callback) {};
// Rpc.prototype.clear = function(options, callback) {};
// Rpc.prototype.synchronize = function(options, callback) {};
// Rpc.prototype.append = function(options, callback) {};
// Rpc.prototype.increment = function(options, callback) {};
// Rpc.prototype.incrementDouble = function(options, callback) {};
// Rpc.prototype.cas = function(options, callback) {};
// Rpc.prototype.check = function(options, callback) {};
// Rpc.prototype.seize = function(options, callback) {};
// Rpc.prototype.setBulk = function(options, callback) {};
// Rpc.prototype.removeBulk = function(options, callback) {};
// Rpc.prototype.getBulk = function(options, callback) {};
// Rpc.prototype.vacuum = function(options, callback) {};

Rpc.prototype.matchPrefix = function(prefix, options, callback) {
  var cb, opt = {}, params = {};

  if (typeof options === 'function') {
    opt = {};
    cb = options;
  } else {
    opt = options;
    cb = callback;
  }

  params.prefix = prefix;

  if (typeof opt.db !== 'undefined') {
    params.DB = opt.db;
  }

  if (typeof opt.max !== 'undefined') {
    params.max = opt.max;
  }

  cb = function(error, res) {
    callback(error, res);
  };

  this._call('match_prefix', {}, function(error, ret) {
    var data = {}, num;

    if (typeof error !== 'undefined') {
      cb(error);
    }

    for (var key in ret) {
      if (ret.hasOwnProperty(key)) {
        if (key === 'num') {
          num = ret[key];
        } else {
          data[key.substr(1)] = ret[key];
        }
      }
    }
    cb(undefined, data, num);
  });
};

// Rpc.prototype.matchRegex = function(options, callback) {};
// Rpc.prototype.matchSimilar = function(options, callback) {};
// Rpc.prototype.curJump = function(options, callback) {};
// Rpc.prototype.curJumpBack = function(options, callback) {};
// Rpc.prototype.curStep = function(options, callback) {};
// Rpc.prototype.curStepBack = function(options, callback) {};
// Rpc.prototype.curSetValue = function(options, callback) {};
// Rpc.prototype.curRemove = function(options, callback) {};
// Rpc.prototype.curGetGey = function(options, callback) {};
// Rpc.prototype.curGetValue = function(options, callback) {};
// Rpc.prototype.curGet = function(options, callback) {};
// Rpc.prototype.curSeize = function(options, callback) {};
// Rpc.prototype.curDelete = function(options, callback) {};

Rpc.prototype._call = function(method, params, options, callback) {
  var paramStr = '';
  if (typeof params !== 'undefined') {
    paramStr = '?' + querystring.stringify(params);
  }
  var requestOptions = {
    hostname: this.host,
    port: this.port,
    path: '/rpc/' + method + paramStr,
    method: 'GET',
    agent: this.agent
  };

  http.request(requestOptions, function(res) {
    var buf = new BufferList(), str = '';

    res.on('data', function(chunk) {
      if (Buffer.isBuffer(chunk)) {
        buf.append(chunk);
      } else {
        str += chunk;
      }
    });

    res.on('end', function() {
      var ret;

      if (res.statusCode === 200) {
        if (buf.length) {
          // TSV-RPC response is string only
          ret = buf.toString();
        } else {
          ret = str;
        }

        if (res.headers['Content-Type'].indexOf('colenc=B')) {
          callback(undefined, this._parseBase64Encode(ret, options.encode));
        } else if (res.headers['Content-Type'].indexOf('colenc=U')) {
          callback(undefined, this._parseURLEncode(ret));
        } else {
          callback(undefined, this._parse(ret));
        }
      } else if (res.statusCode === 404) {
        callback('No record was found');
      } else {
        callback('Connection error');
      }
    });
  }).on('error', function() {
    callback('Connection error');
  }).end();
};

Rpc.prototype._parse = function(tsv) {
  var lines = [], kv = [], ret = {};

  lines = tsv.split('\n');

  for (var i = 0; i < lines.length; ++i) {
    kv = lines.split('\t');
    ret[kv[0]] = kv[1];
  }

  return ret;
};

Rpc.prototype._parseBase64Encode = function(tsv, encode) {
  var lines = [], kv = [], ret = {}, i = 0;

  lines = tsv.split('\n');

  if (typeof encode === 'undefined' || encode === null) {
    for (; i < lines.length; ++i) {
      kv = lines.split('\t');
      ret[new Buffer(kv[0], 'base64').toString()] =
        new Buffer(kv[1], 'base64').toString();
    }
  } else if (encode === 'binary') {
    for (; i < lines.length; ++i) {
      kv = lines.split('\t');
      ret[new Buffer(kv[0], 'base64').toString()] = new Buffer(kv[1], 'base64');
    }
  } else {
    for (; i < lines.length; ++i) {
      kv = lines.split('\t');
      ret[new Buffer(kv[0], 'base64').toString(encode)] =
        new Buffer(kv[1], 'base64').toString(encode);
    }
  }

  return ret;
};

Rpc.prototype._parseURLEncode = function(tsv) {
  var lines = [], kv = [], ret = {};

  lines = tsv.split('\n');

  for (var i = 0; i < lines.length; ++i) {
    kv = lines.split('\t');
    ret[decodeURIComponent(kv[0])] = decodeURIComponent(kv[1]);
  }

  return ret;
};

module.exports = Rpc;
<|endoftext|>


<commit_before>/*
 * Copyright 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview JavaScript Built-Ins for windows properties.
 *
 * @externs
 */

// Window properties
// Only common properties are here.  Others such as open()
// should be used with an explicit Window object.

/**
 * @type {!Window}
 * @see https://developer.mozilla.org/en/DOM/window.top
 * @const
 */
var top;

/**
 * @type {Navigator}
 * @see https://developer.mozilla.org/en/DOM/window.navigator
 * @const
 */
var navigator;

/**
 * @type {!HTMLDocument}
 * @see https://developer.mozilla.org/en/DOM/window.document
 * @const
 */
var document;

/**
 * @type {Location}
 * @see https://developer.mozilla.org/en/DOM/window.location
 * @const
 * @suppress {duplicate}
 */
var location;

/**
 * @see https://developer.mozilla.org/En/DOM/Window.screen
 * @const
 */
var screen;

/**
 * @type {!Window}
 * @see https://developer.mozilla.org/En/DOM/Window.self
 * @const
 */
var self;

// Magic functions for Firefox's LiveConnect.
// We'll probably never use these in practice. But redefining them
// will fire up the JVM, so we want to reserve the symbol names.

/**
 * @see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/JavaArray
 */
var JavaArray;

/**
 * @see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/JavaClass
 */
var JavaClass;

// We just ripped this from the FF source; it doesn't appear to be
// publicly documented.
var JavaMember;

/**
 * @see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/JavaObject
 */
var JavaObject;

/**
 * @see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/JavaPackage
 */
var JavaPackage;

/**
 * @see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Packages
 */
var Packages;

/**
 * @see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/java
 */
var java;

/**
 * @see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/netscape
 */
var netscape;

/**
 * @see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/sun
 */
var sun;

// Magic variable for Norton Identity Protection's Chrome extension.  This
// program will overwrite whatever's stored in the variable 'o' with random
// values, so we want to avoid it.
// NOTE(user): Added 8-30-2012.  We may want to remove this once Norton
// Identity Protection has been fixed and pushed to most people.
var o;

/**
 * @see https://developer.mozilla.org/en/DOM/window.alert
 */
function alert(x) {}

/**
 * @param {number|undefined?} intervalID
 * @see https://developer.mozilla.org/en/DOM/window.clearInterval
 */
function clearInterval(intervalID) {}

/**
 * @param {number|undefined?} timeoutID
 * @see https://developer.mozilla.org/en/DOM/window.clearTimeout
 */
function clearTimeout(timeoutID) {}

/**
 * @see https://developer.mozilla.org/en/DOM/window.confirm
 */
function confirm(x) {}

/**
 * @see https://developer.mozilla.org/en/DOM/window.dump
 */
function dump(x) {}

/**
 * @param {string} message
 * @param {string=} opt_value
 * @return {?string}
 * @see https://developer.mozilla.org/en/DOM/window.prompt
 */
function prompt(message, opt_value) {}

/**
 * @param {Function|string} callback
 * @param {number} delay
 * @return {number}
 * @see https://developer.mozilla.org/en/DOM/window.setInterval
 * @see https://msdn.microsoft.com/en-us/library/ms536749(v=VS.85).aspx
 */
function setInterval(callback, delay) {}

/**
 * @param {Function|string} callback
 * @param {number} delay
 * @return {number}
 * @see https://developer.mozilla.org/en/DOM/window.setTimeout
 * @see https://msdn.microsoft.com/en-us/library/ms536753(VS.85).aspx
 */
function setTimeout(callback, delay) {}
<commit_msg><commit_after>/*
 * Copyright 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview JavaScript Built-Ins for windows properties.
 *
 * @externs
 */

// Window properties
// Only common properties are here.  Others such as open()
// should be used with an explicit Window object.

/**
 * @type {!Window}
 * @see https://developer.mozilla.org/en/DOM/window.top
 * @const
 */
var top;

/**
 * @type {Navigator}
 * @see https://developer.mozilla.org/en/DOM/window.navigator
 * @const
 */
var navigator;

/**
 * @type {!HTMLDocument}
 * @see https://developer.mozilla.org/en/DOM/window.document
 * @const
 */
var document;

/**
 * @type {Location}
 * @see https://developer.mozilla.org/en/DOM/window.location
 * @const
 * @suppress {duplicate}
 */
var location;

/**
 * @see https://developer.mozilla.org/En/DOM/Window.screen
 * @const
 */
var screen;

/**
 * @type {!Window}
 * @see https://developer.mozilla.org/En/DOM/Window.self
 * @const
 */
var self;

// Magic functions for Firefox's LiveConnect.
// We'll probably never use these in practice. But redefining them
// will fire up the JVM, so we want to reserve the symbol names.

/**
 * @see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/JavaArray
 */
var JavaArray;

/**
 * @see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/JavaClass
 */
var JavaClass;

// We just ripped this from the FF source; it doesn't appear to be
// publicly documented.
var JavaMember;

/**
 * @see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/JavaObject
 */
var JavaObject;

/**
 * @see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/JavaPackage
 */
var JavaPackage;

/**
 * @see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Packages
 */
var Packages;

/**
 * @see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/java
 */
var java;

/**
 * @see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/netscape
 */
var netscape;

/**
 * @see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/sun
 */
var sun;

// Magic variable for Norton Identity Protection's Chrome extension.  This
// program will overwrite whatever's stored in the variable 'o' with random
// values, so we want to avoid it.
// NOTE(user): Added 8-30-2012.  We may want to remove this once Norton
// Identity Protection has been fixed and pushed to most people.
var o;

/**
 * @see https://developer.mozilla.org/en/DOM/window.alert
 */
function alert(x) {}

/**
 * @param {number|undefined?} intervalID
 * @see https://developer.mozilla.org/en/DOM/window.clearInterval
 */
function clearInterval(intervalID) {}

/**
 * @param {number|undefined?} timeoutID
 * @see https://developer.mozilla.org/en/DOM/window.clearTimeout
 */
function clearTimeout(timeoutID) {}

/**
 * @see https://developer.mozilla.org/en/DOM/window.confirm
 */
function confirm(x) {}

/**
 * @see https://developer.mozilla.org/en/DOM/window.dump
 */
function dump(x) {}

/**
 * @param {string} message
 * @param {string=} opt_value
 * @return {?string}
 * @see https://developer.mozilla.org/en/DOM/window.prompt
 */
function prompt(message, opt_value) {}

/**
 * @param {Function|string} callback
 * @param {number} delay
 * @return {number}
 * @see https://developer.mozilla.org/en/DOM/window.setInterval
 * @see https://msdn.microsoft.com/en-us/library/ms536749(v=VS.85).aspx
 */
function setInterval(callback, delay) {}

/**
 * @param {Function|string} callback
 * @param {number} delay
 * @return {number}
 * @see https://developer.mozilla.org/en/DOM/window.setTimeout
 * @see https://msdn.microsoft.com/en-us/library/ms536753(VS.85).aspx
 */
function setTimeout(callback, delay) {}

var i;
<|endoftext|>


<commit_before>const fridaLoad = require('frida-load')

const Cache = require('./cache')
const { retry } = require('./utils')

module.exports = class RpcHandler {
  constructor(session, socket) {
    this.session = session
    this.socket = socket
    this.cache = new Cache()
    this.handleMessage()
  }

  async load() {
    let { socket } = this
    let source = await fridaLoad(require.resolve('../frida'))
    let script = await this.session.createScript(source)

    await script.load()
    script.events.listen('destroyed', () => {
      socket.emit('script_destroyed')
      socket.disconnect(true)
    })
    script.events.listen('message', (message, data) => {
      // todo
    })

    this.script = script
    this.agent = await script.getExports()
  }

  handleMessage() {
    const events = [
      'modules',
      'ranges',
      'exports',
      'classes',
      'methods',
      'info',
      'lsof',
      'imports',
      'ls',
      'plist',
      'text',
    ]

    this._router = new Map()
    for (let event of events) {
      this.socket.on(event, this.wrap(event))
    }
  }

  wrap(key) {
    let method = this[key].bind(this)
    return async(data, ack) => {
      try {
        ack({
          status: 'ok',
          data: await method(data)
        })
      } catch (err) {
        console.error('rpc error', err)
        console.info(err.stack)
        ack({
          status: 'error',
          error: err + '',
        })
      }
    }
  }

  async modules() {
    return await this.session.enumerateModules()
  }

  async ranges({ protection }) {
    return await this.session.enumerateRanges(protection)
  }

  async exports({ module }) {
    return await session.enumerateExports(module)
  }

  async classes() {
    let func = this.agent.classes.bind(this.agent)
    return await this.cache.fetch('classes', func)
  }

  async methods({ clz }) {
    let func = this.agent.methods.bind(this.agent, clz)
    return await this.cache.fetch(`methods_${clz}`, func)
  }

  async info() {
    return await retry(async() => {
      let sec = await this.agent.checksec()
      let info = await this.agent.info()
      return { sec, info }
    })
  }

  async lsof() {
    return await this.agent.lsof()
  }

  async imports(data) {
    let name = (data && data.name) ? data.name : null
    return await this.agent.imports()
  }

  async ls(path) {
    return path ? await this.agent.ls(path) : await this.agent.home()
  }

  async plist(path) {
    return await this.agent.plist(path)
  }

  async text(path) {
    return await this.agent.text(path)
  }
}<commit_msg>bugfix: session not defined<commit_after>const fridaLoad = require('frida-load')

const Cache = require('./cache')
const { retry } = require('./utils')

module.exports = class RpcHandler {
  constructor(session, socket) {
    this.session = session
    this.socket = socket
    this.cache = new Cache()
    this.handleMessage()
  }

  async load() {
    let { socket } = this
    let source = await fridaLoad(require.resolve('../frida'))
    let script = await this.session.createScript(source)

    await script.load()
    script.events.listen('destroyed', () => {
      socket.emit('script_destroyed')
      socket.disconnect(true)
    })
    script.events.listen('message', (message, data) => {
      // todo
    })

    this.script = script
    this.agent = await script.getExports()
  }

  handleMessage() {
    const events = [
      'modules',
      'ranges',
      'exports',
      'classes',
      'methods',
      'info',
      'lsof',
      'imports',
      'ls',
      'plist',
      'text',
    ]

    this._router = new Map()
    for (let event of events) {
      this.socket.on(event, this.wrap(event))
    }
  }

  wrap(key) {
    let method = this[key].bind(this)
    return async(data, ack) => {
      try {
        ack({
          status: 'ok',
          data: await method(data)
        })
      } catch (err) {
        console.error('rpc error', err)
        console.info(err.stack)
        ack({
          status: 'error',
          error: err + '',
        })
      }
    }
  }

  async modules() {
    return await this.session.enumerateModules()
  }

  async ranges({ protection }) {
    return await this.session.enumerateRanges(protection)
  }

  async exports({ module }) {
    return await this.session.enumerateExports(module)
  }

  async classes() {
    let func = this.agent.classes.bind(this.agent)
    return await this.cache.fetch('classes', func)
  }

  async methods({ clz }) {
    let func = this.agent.methods.bind(this.agent, clz)
    return await this.cache.fetch(`methods_${clz}`, func)
  }

  async info() {
    return await retry(async() => {
      let sec = await this.agent.checksec()
      let info = await this.agent.info()
      return { sec, info }
    })
  }

  async lsof() {
    return await this.agent.lsof()
  }

  async imports(data) {
    let name = (data && data.name) ? data.name : null
    return await this.agent.imports()
  }

  async ls(path) {
    return path ? await this.agent.ls(path) : await this.agent.home()
  }

  async plist(path) {
    return await this.agent.plist(path)
  }

  async text(path) {
    return await this.agent.text(path)
  }
}<|endoftext|>


<commit_before><commit_msg>Added run<commit_after>/*
 * run: Takes an express server and runs it.
 */

var protocols = {
      http: require('http'),
      https: require('https'),
    },
    fs = require('fs'),
    path = require('path');

module.exports = function(app){
  var config = iora.config,
      files = config.https.options,
      base = config.base.https;

  // Things to be used.
  var port, host, listener, protocol, options;

  // Set defaults
  if (typeof base !== 'string') base = process.cwd();
  if (typeof files !== 'object') options = {};

  if (files) {
    // Path -> file data
    for (var opt in files) {
      files[opt] = fs.readFileSync(path.join(base, files[opt]));
    }
  }
  for (var name in protocols) {
    // Disabled checker
    if (typeof options.disabled === 'undefined' || !options.disabled) {
      // Set defaults
      options = config[name];
      if (typeof options !== 'object') options = {};

      port = options.port;
      if (typeof port !== 'number') port = (name === 'https' ? 443 : 80);

      host = config.host || options.host;
      if (typeof host !== 'string') host = '0.0.0.0';

      if (typeof config.listener !== 'undefined' || typeof options.listener !== 'undefined') {
        try {
          listener = require(config.listener || options.listener);
        } catch (e) {
          console.warn('Couldn\'t load listener ('+name+')');
          listener = function(){};
        }
      } else {
         listener = function(){};
      }

      // Create and listen to servers
      protocol.Server(
        (name === 'https' ? options : app),
        (name === 'https' ? app : undefined)
      ).listen(port, host, listener);
    }
  }
};
<|endoftext|>


<commit_before>var _ = require('lodash'),
    EventEmitter = require('eventemitter3'),
    runtime = require('postman-runtime'),
    Collection = require('postman-collection').Collection,

    runtimeEvents = ['start', 'beforeIteration', 'beforeItem', 'beforePrerequest', 'prerequest',
        'beforeRequest', 'request', 'beforeTest', 'test', 'item', 'iteration', 'beforeScript', 'script', 'console',
        'exception', 'done'],

    /**
     * Accepts an object, and extracts the property inside an object which is supposed to contain a list of variables
     *
     * @param {Object} source
     * @param {String} type - "environment" or "globals", etc
     *
     * @returns {Object}
     */
    extractVariables = function (source, type) {
        if (!_.isObject(source && (source = source[type]))) { return; } // get hold of the object that holds ariable

        // ensure we unbox the JSON if it comes from cloud-api or similar sources
        !source.values && _.isObject(source[type]) && (source = source[type]);

        // ensure we handle environment sent in form of array of values
        (source.name && _.isArray(source.values)) && (source = source.values);

        // we ensure that environment passed as array is converted to plain object. runtime does this too, but we do it
        // here for consistency of options passed to reporters
        return _.isArray(source) ? _(source).keyBy('key').mapValues('value').value() : source;
    };

/**
 * @param {Object} options
 * @param {Collection|Object} options.collection
 * @param {Object} options.environment
 * @param {Array|String} options.reporters
 * @param {Function} callback
 *
 * @returns {EventEmitter}
 */
module.exports = function (options, callback) {
    // validate all options. it is to be notet that `options` parameter is option and is polymorphic
    (!callback && _.isFunction(options)) && (
        (callback = options),
        (options = {})
    );
    options = _.isObject(options) ? _.clone(options) : {}; // we initialise this as object to avoid needless validations
    !_.isFunction(callback) && (callback = _.noop);

    // create a collection in case it is not one. user can send v2 JSON as a source and that will be converted
    // to a collection
    if (_.isPlainObject(options.collection) && !Collection.isCollection(options.collection)) {
        options.collection = new Collection(options.collection);
    }

    // we sanitise the environment and globals and mutate the original otions so that subsequent consumers do not need
    // to do this again
    _.assign(options, {
        environment: extractVariables(options, 'environment'),
        globals: extractVariables(options, 'globals')
    });

    var emitter = new EventEmitter(), // @todo: create a new inherited constructor
        runner = new runtime.Runner();

    // ensure that the collection option is present before starting a run
    if (!_.isObject(options.collection)) {
        callback(new Error('newman: expecting a collection to run'));
        return emitter;
    }

    options.collection && runner.run(options.collection, {
        abortOnError: options.abortOnError, // todo: could be a better name, especially in the CLI.
        iterationCount: options.iterationCount,
        environment: options.environment,
        globals: options.globals
    }, function (err, run) {
        var callbacks = {},
            // ensure that the reporter option type polymorphism is handled
            reporters = _.isString(options.reporters) ? [options.reporters] : options.reporters;

        // emit events for all the callbacks triggered by the runtime
        runtimeEvents.forEach(function (eventName) {
            callbacks[eventName] = emitter.emit.bind(emitter, eventName);
        });

        // override the `done` event to fire the end callback
        callbacks.done = function (err) { // @todo - do some meory cleanup here?
            callback(err);
            emitter.emit('done', err); // we now trigger the actual done event which we had overridden
        };

        // initialise all the reporters
        _.isArray(reporters) && _.each(reporters, function (reporterName) {
            // @todo validate reporter name to exist
            // @todo look up for node module "newman-reporter-" as reporters if one is not found locally
            // @todo sanitise the reporter name for security reasons
            (emitter.reporters || (emitter.reporters = {}))[reporterName] =
                new (require('./reporters/' + reporterName))(emitter, options);
        });

        // we ensure that everything is async to comply with event paradigm and start the run
        setImmediate(function () {
            run.start(callbacks);
        });
    });

    return emitter;
};
<commit_msg>Instantiated the summary object during run<commit_after>var _ = require('lodash'),
    EventEmitter = require('eventemitter3'),
    runtime = require('postman-runtime'),
    RunSummary = require('./summary'),
    Collection = require('postman-collection').Collection,

    runtimeEvents = ['start', 'beforeIteration', 'beforeItem', 'beforePrerequest', 'prerequest',
        'beforeRequest', 'request', 'beforeTest', 'test', 'item', 'iteration', 'beforeScript', 'script', 'console',
        'exception', 'done'],

    /**
     * Accepts an object, and extracts the property inside an object which is supposed to contain a list of variables
     *
     * @param {Object} source
     * @param {String} type - "environment" or "globals", etc
     *
     * @returns {Object}
     */
    extractVariables = function (source, type) {
        if (!_.isObject(source && (source = source[type]))) { return; } // get hold of the object that holds ariable

        // ensure we unbox the JSON if it comes from cloud-api or similar sources
        !source.values && _.isObject(source[type]) && (source = source[type]);

        // ensure we handle environment sent in form of array of values
        (source.name && _.isArray(source.values)) && (source = source.values);

        // we ensure that environment passed as array is converted to plain object. runtime does this too, but we do it
        // here for consistency of options passed to reporters
        return _.isArray(source) ? _(source).keyBy('key').mapValues('value').value() : source;
    };

/**
 * @param {Object} options
 * @param {Collection|Object} options.collection
 * @param {Object} options.environment
 * @param {Array|String} options.reporters
 * @param {Function} callback
 *
 * @returns {EventEmitter}
 */
module.exports = function (options, callback) {
    // validate all options. it is to be notet that `options` parameter is option and is polymorphic
    (!callback && _.isFunction(options)) && (
        (callback = options),
        (options = {})
    );
    options = _.isObject(options) ? _.clone(options) : {}; // we initialise this as object to avoid needless validations
    !_.isFunction(callback) && (callback = _.noop);

    // create a collection in case it is not one. user can send v2 JSON as a source and that will be converted
    // to a collection
    if (_.isPlainObject(options.collection) && !Collection.isCollection(options.collection)) {
        options.collection = new Collection(options.collection);
    }

    // we sanitise the environment and globals and mutate the original otions so that subsequent consumers do not need
    // to do this again
    _.assign(options, {
        environment: extractVariables(options, 'environment'),
        globals: extractVariables(options, 'globals')
    });

    var emitter = new EventEmitter(), // @todo: create a new inherited constructor
        runner = new runtime.Runner();

    // ensure that the collection option is present before starting a run
    if (!_.isObject(options.collection)) {
        callback(new Error('newman: expecting a collection to run'));
        return emitter;
    }

    // store summary object and other relevant information inside the emitter
    emitter.summary = new RunSummary(emitter, options);

    options.collection && runner.run(options.collection, {
        abortOnError: options.abortOnError, // todo: could be a better name, especially in the CLI.
        iterationCount: options.iterationCount,
        environment: options.environment,
        globals: options.globals
    }, function (err, run) {
        var callbacks = {},
            // ensure that the reporter option type polymorphism is handled
            reporters = _.isString(options.reporters) ? [options.reporters] : options.reporters;

        // emit events for all the callbacks triggered by the runtime
        runtimeEvents.forEach(function (eventName) {
            callbacks[eventName] = emitter.emit.bind(emitter, eventName);
        });

        // override the `done` event to fire the end callback
        callbacks.done = function (err) { // @todo - do some meory cleanup here?
            callback(err);
            emitter.emit('done', err); // we now trigger the actual done event which we had overridden
        };

        // initialise all the reporters
        _.isArray(reporters) && _.each(reporters, function (reporterName) {
            // @todo validate reporter name to exist
            // @todo look up for node module "newman-reporter-" as reporters if one is not found locally
            // @todo sanitise the reporter name for security reasons
            (emitter.reporters || (emitter.reporters = {}))[reporterName] =
                new (require('./reporters/' + reporterName))(emitter, options);
        });

        // we ensure that everything is async to comply with event paradigm and start the run
        setImmediate(function () {
            run.start(callbacks);
        });
    });

    return emitter;
};
<|endoftext|>


<commit_before>/***************************************************************************
*
* Copyright (C) 2014 Baidu.com, Inc. All Rights Reserved
*
***************************************************************************/

/**
 * @file sdk.js ~ 2014-03-21 11:49
 * @author sekiyika (px.pengxing@gmail.com)
 * @description
 *  获取配置文件，并且启动edp-webserver的入口文件
 */

exports.start = function(conf) {

    var path = require('path');
    var ws = require('edp-webserver');
    var proxyLinks = require('./proxyLinks');
    var Render = require('./render');
    var util = require('./util');
    var AssembleTemplate = require('./AssembleTemplate');
    var indexer = require('./indexer');

    try {

        /**
         * 得到edpx-zhixin-config.js模块
         *
         * @type {Module}
         */
        var gConf = require(
                path.resolve(
                    util.findFile(conf.config, 'edpx-zhixin-config.js'),
                    './edpx-zhixin-config'
                )
            ).zhixinConfig;
    }
    catch (ex) {
        console.log('>> Not found config file `edpx-zhixin-config.js`.');
        process.exit(1);
    }

    var root = path.normalize(''
        + util.findFile(conf.config, 'edpx-zhixin-config.js')
        + path.sep
        + gConf.server.documentRoot
    ) || process.cwd();

    /*
    var root = util.getAbsPath(
        gConf.server.documentRoot,
        util.findFile(conf.config, 'edpx-zhixin-config.js')
    ) || process.cwd();
    */

    /**
     * edp webserver的配置文件
     *
     * @type {Object}
     */
    var edpWSConfig = {

        /**
         * 配置ws的documentRoot
         */
        documentRoot: root,
        port: gConf.server.port,

        getLocations: function() {
            return [
                {
                    location: /^\/$/,
                    handler: [
                        function(context) {
                            var req = context.request;
                            req.headers.Host = gConf.proxy.hostname;
                        },
                        proxy(gConf.proxy.hostname, gConf.proxy.port)
                    ]
                },
                {
                    location: /^\/s\?.*/,
                    handler: [
                        function(context) {
                            var req = context.request;
                            req.headers.Host = gConf.proxy.hostname;
                        },
                        proxy(gConf.proxy.hostname, gConf.proxy.port),
                        function(context) {
                            var response = context.response;

                            context.stop();
                            var zlib = require('zlib');

                            // 这里进行解码操作，删除header中的content-encoding
                            delete context.header['content-encoding'];

                            // 当前都是gzip，所以目前只考虑gzip的格式
                            zlib.gunzip(context.content, function(err, buffer) {
                                if(!err) {
                                    var content = buffer.toString();

                                    var requestHeaders = context.request.headers;
                                    var proxyedUrl = ['http://',requestHeaders.host,'/proxy_url'].join('');

                                    content = proxyLinks.proxyLinks(content, proxyedUrl);
                                    content = AssembleTemplate.disassemble(content);
                                    context.stop();

                                    // 在这里进行渲染，拿到渲染后的结果
                                    var queryObj = context.request.query;

                                    var promise = Render.render(indexer.getRenderConf(queryObj.wd));
                                    promise.done(function(output) {
                                        var data;
                                        if(!output) {
                                            data = {};
                                        } else {
                                            output = output.output;
                                            data = JSON.parse(output);
                                        }

                                        // 在这里进行拼装，将模板和渲染的数据进行拼装
                                        content = AssembleTemplate.assmeble(content, data);

                                        context.content = content;
                                        context.start();
                                    });
                                    promise.fail(function(output) {
                                        output = '
' + output.output + '
';

                                        context.content = output;
                                        context.status = 500;
                                        context.start();
                                    });
                                } else {
                                    // 发生服务器错误
                                    context.status = 500;
                                    // 这一步发生错误，也得到最后啊
                                    context.start();
                                }

                            });

                        }
                    ]
                },
                {
                    location: /^\/proxy_url.*/,
                    handler: [
                        function(context) {
                            var query = context.request.query;
                            if(query.url) {

                                var urlLib = require('url');
                                var url = urlLib.parse(query.url);
                                // 重写request的url
                                context.request.url = url.path;
                                context.request.headers.host = url.hostname;
                                //增加referer，以通过百度对图片的验证
                                context.request.headers.referer = 'http://' + gConf.proxy.hostname;
                                // 代理一下
                                (proxy(url.hostname, url.port ? url.port : 80))(context);
                            }
                        }
                    ]
                },
                {
                    location: /^.*$/,
                    handler: [
                        function(context) {
                            var req = context.request;
                            req.headers.Host = gConf.proxy.hostname
                        },
                        proxy(gConf.proxy.hostname, gConf.proxy.port)
                    ]
                }
            ];
        },

        injectResource: function ( res ) {
            for ( var key in res ) {
                global[ key ] = res[ key ];
            }
        }
    };

    // 建立query到数据的索引
    indexer.index(root)
        .done(function() {
            ws.start(edpWSConfig);
        })
        .fail(function(er) {
            edp.log.fatal(er);
        });
};
<commit_msg>fix notice<commit_after>/***************************************************************************
*
* Copyright (C) 2014 Baidu.com, Inc. All Rights Reserved
*
***************************************************************************/

/**
 * @file sdk.js ~ 2014-03-21 11:49
 * @author sekiyika (px.pengxing@gmail.com)
 * @description
 *  获取配置文件，并且启动edp-webserver的入口文件
 */

exports.start = function(conf) {

    var path = require('path');
    var ws = require('edp-webserver');
    var proxyLinks = require('./proxyLinks');
    var Render = require('./render');
    var util = require('./util');
    var AssembleTemplate = require('./AssembleTemplate');
    var indexer = require('./indexer');

    try {

        /**
         * 得到edpx-zhixin-config.js模块
         *
         * @type {Module}
         */
        var gConf = require(
                path.resolve(
                    util.findFile(conf.config, 'edpx-zhixin-config.js'),
                    './edpx-zhixin-config'
                )
            ).zhixinConfig;
    }
    catch (ex) {
        console.log('>> Not found config file `edpx-zhixin-config.js`.');
        process.exit(1);
    }

    var root = path.normalize(''
        + util.findFile(conf.config, 'edpx-zhixin-config.js')
        + path.sep
        + gConf.server.documentRoot
    ) || process.cwd();

    /*
    var root = util.getAbsPath(
        gConf.server.documentRoot,
        util.findFile(conf.config, 'edpx-zhixin-config.js')
    ) || process.cwd();
    */

    /**
     * edp webserver的配置文件
     *
     * @type {Object}
     */
    var edpWSConfig = {

        /**
         * 配置ws的documentRoot
         */
        documentRoot: root,
        port: gConf.server.port,

        getLocations: function() {
            return [
                {
                    location: /^\/$/,
                    handler: [
                        function(context) {
                            var req = context.request;
                            req.headers.Host = gConf.proxy.hostname;
                        },
                        proxy(gConf.proxy.hostname, gConf.proxy.port)
                    ]
                },
                {
                    location: /^\/s\?.*/,
                    handler: [
                        function(context) {
                            var req = context.request;
                            req.headers.Host = gConf.proxy.hostname;
                        },
                        proxy(gConf.proxy.hostname, gConf.proxy.port),
                        function(context) {
                            var response = context.response;

                            context.stop();
                            var zlib = require('zlib');

                            // 这里进行解码操作，删除header中的content-encoding
                            delete context.header['content-encoding'];

                            // 当前都是gzip，所以目前只考虑gzip的格式
                            zlib.gunzip(context.content, function(err, buffer) {
                                if(!err) {
                                    var content = buffer.toString();

                                    var requestHeaders = context.request.headers;
                                    var proxyedUrl = ['http://',requestHeaders.host,'/proxy_url'].join('');

                                    content = proxyLinks.proxyLinks(content, proxyedUrl);
                                    content = AssembleTemplate.disassemble(content);
                                    context.stop();

                                    // 在这里进行渲染，拿到渲染后的结果
                                    var queryObj = context.request.query;

                                    var promise = Render.render(indexer.getRenderConf(queryObj.wd));
                                    promise.done(function(output) {
                                        var data;
                                        if(!output) {
                                            data = {};
                                        } else {

                                            // 防止有notice和warming导致json串不能解析
                                            output = output.output.replace(/[^{}]*(.*)[^{}]*/g,
                                                function () {
                                                    return arguments[1];
                                                }
                                            );
                                            data = JSON.parse(output);
                                        }

                                        // 在这里进行拼装，将模板和渲染的数据进行拼装
                                        content = AssembleTemplate.assmeble(content, data);

                                        context.content = content;
                                        context.start();
                                    });
                                    promise.fail(function(output) {
                                        output = '
' + output.output + '
';

                                        context.content = output;
                                        context.status = 500;
                                        context.start();
                                    });
                                } else {
                                    // 发生服务器错误
                                    context.status = 500;
                                    // 这一步发生错误，也得到最后啊
                                    context.start();
                                }

                            });

                        }
                    ]
                },
                {
                    location: /^\/proxy_url.*/,
                    handler: [
                        function(context) {
                            var query = context.request.query;
                            if(query.url) {

                                var urlLib = require('url');
                                var url = urlLib.parse(query.url);
                                // 重写request的url
                                context.request.url = url.path;
                                context.request.headers.host = url.hostname;
                                //增加referer，以通过百度对图片的验证
                                context.request.headers.referer = 'http://' + gConf.proxy.hostname;
                                // 代理一下
                                (proxy(url.hostname, url.port ? url.port : 80))(context);
                            }
                        }
                    ]
                },
                {
                    location: /^.*$/,
                    handler: [
                        function(context) {
                            var req = context.request;
                            req.headers.Host = gConf.proxy.hostname
                        },
                        proxy(gConf.proxy.hostname, gConf.proxy.port)
                    ]
                }
            ];
        },

        injectResource: function ( res ) {
            for ( var key in res ) {
                global[ key ] = res[ key ];
            }
        }
    };

    // 建立query到数据的索引
    indexer.index(root)
        .done(function() {
            ws.start(edpWSConfig);
        })
        .fail(function(er) {
            edp.log.fatal(er);
        });
};
<|endoftext|>


<commit_before>/**
 * datastructures-js/Set
 * @class
 * @copyright 2018 Eyas Ranjous <eyas.ranjous@gmail.com>
 * @license MIT
 */

class Set {

  /**
   * @constructor
   */
  constructor() {
    this._init();
  }

  /**
   * @public
   * gets the size of the set
   * @returns {number}
   */
  size() {
    return this._count;
  }

  /**
   * @public
   * checks if the set is empty
   * @returns {boolean}
   */
  isEmpty() {
    return this._count === 0;
  }

  /**
   * @public
   * checks if the set contains an element
   * @param {(string|number|boolean)} element
   * @returns {number}
   */
  contains(element) {
    return this._elements[element] === true;
  }

  /**
   * @public
   * adds an element to the set
   * @param {(string|number|boolean)} element
   */
  add(element) {
    if (!this._elements[element]) {
      this._elements[element] = true;
      this._count++;
    }
  }

  /**
   * @public
   * removes an element from the set
   * @param {(string|number|boolean)} element
   */
  remove(element){
    if (this._elements[element]) {
      this._elements[element] = false;
      this._count--;
    }
  }

  /**
   * @public
   * joins the actual set with a another set
   * @param {Set} s
   * @returns {Set}
   * @throws {Error} - when s type is not Set
   */
  union(s) {
    if (s instanceof Set) {
      return this._unionSet(s);
    }
    else {
      throw new Error('.union expects a set as a param');
    }
  }

  /**
   * @public
   * intersects the actual set with another set
   * @param {Set} s
   * @returns {Set}
   * @throws {Error} - when s type is not Set
   */
  intersect(s) {
    if (s instanceof Set) {
      return this._intersectSet(s);
    }
    else {
      throw new Error('.intersect expects a set as a param');
    }
  }

  /**
   * @public
   * returns a set with elements that exists
   * in the actual set but not in the given set
   * @param {Set} s
   * @returns {Set}
   * @throws {Error} - when s type is not Set
   */
  diff(s) {
    if (s instanceof Set) {
      return this._diffSet(s);
    }
    else {
      throw new Error('.diff expects a set as a param');
    }
  }

  /**
   * @public
   * checks if the actual set is a subset of another set
   * @param {Set} s
   * @returns {boolean}
   * @throws {Error} - when s type is not Set
   */
  isSubset(s) {
    if (s instanceof Set && this._count <= s.size()) {
      return this._isSetSubsetOf(s);
    }
    else if (s instanceof Set && this._count > s.size()) {
      return false;
    }
    else {
      throw new Error('.isSubset expects a set as a param');
    }
  }

  /**
   * @public
   * converts the set into an array
   * @returns {array}
   */
  toArray() {
    let elements = [];
    for (let el in this._elements) {
      if (this.contains(el)) {
        elements.push(isNaN(el) ? el : Number(el));
      }
    }
    return elements;
  }

  /**
   * @public
   * clears the set
   */
  clear() {
    this._init();
  }

  /**
   * @private
   * @param {Set} s
   * @returns {Set}
   */
  _unionSet(s) {
    let union = new Set();
    for (let el in this._elements) {
      if (this.contains(el)) {
        union.add(el);
      }
    }
    s.toArray().forEach((el) => {
      union.add(el);
    });
    return union;
  }

  /**
   * @private
   * @param {Set} s
   * @returns {Set}
   */
  _intersectSet(s) {
    let intersect = new Set();
    for (let el in this._elements) {
      if (this.contains(el) && s.contains(el)) {
        intersect.add(el);
      }
    }
    return intersect;
  }

  /**
   * @private
   * @param {Set} s
   * @returns {Set}
   */
  _diffSet(s) {
    let diffSet = new Set();
    for (let el in this._elements) {
      if (this.contains(el) && !s.contains(el)) {
        diffSet.add(el);
      }
    }
    return diffSet;
  }

  /**
   * @private
   * @param {Set} s
   * @returns {boolean}
   */
  _isSetSubsetOf(s) {
    for (let el in this._elements) {
      if (this.contains(el) && !s.contains(el)) {
        return false;
      }
    }
    return true;
  }

  /**
   * @private
   * inits the set properties
   */
  _init() {
    this._elements = {};
    this._count = 0;
  }

}

module.exports = Set;<commit_msg>refactor<commit_after>/**
 * datastructures-js/Set
 * @class
 * @copyright 2018 Eyas Ranjous <eyas.ranjous@gmail.com>
 * @license MIT
 */

class Set {

  /**
   * @constructor
   */
  constructor() {
    this._init();
  }

  /**
   * @public
   * gets the size of the set
   * @returns {number}
   */
  size() {
    return this._count;
  }

  /**
   * @public
   * checks if the set is empty
   * @returns {boolean}
   */
  isEmpty() {
    return this._count === 0;
  }

  /**
   * @public
   * checks if the set contains an element
   * @param {(string|number|boolean)} element
   * @returns {number}
   */
  contains(element) {
    return this._elements[element] === true;
  }

  /**
   * @public
   * adds an element to the set
   * @param {(string|number|boolean)} element
   */
  add(element) {
    if (!this._elements[element]) {
      this._elements[element] = true;
      this._count++;
    }
  }

  /**
   * @public
   * removes an element from the set
   * @param {(string|number|boolean)} element
   */
  remove(element){
    if (this._elements[element]) {
      this._elements[element] = false;
      this._count--;
    }
  }

  /**
   * @public
   * joins the actual set with a another set
   * @param {Set} s
   * @returns {Set}
   * @throws {Error} - when s type is not Set
   */
  union(s) {
    return this._operate(s, 'union');
  }

  /**
   * @public
   * intersects the actual set with another set
   * @param {Set} s
   * @returns {Set}
   * @throws {Error} - when s type is not Set
   */
  intersect(s) {
    return this._operate(s, 'intersect');
  }

  /**
   * @public
   * returns a set with elements that exists
   * in the actual set but not in the given set
   * @param {Set} s
   * @returns {Set}
   * @throws {Error} - when s type is not Set
   */
  diff(s) {
    return this._operate(s, 'diff');
  }

  /**
   * @public
   * checks if the actual set is a subset of another set
   * @param {Set} s
   * @returns {boolean}
   * @throws {Error} - when s type is not Set
   */
  isSubset(s) {
    if (s instanceof Set && this._count <= s.size()) {
      return this._isSetSubsetOf(s);
    }
    else if (s instanceof Set && this._count > s.size()) {
      return false;
    }
    else {
      throw new Error('.isSubset expects a set as a param');
    }
  }

  /**
   * @public
   * converts the set into an array
   * @returns {array}
   */
  toArray() {
    let elements = [];
    for (let el in this._elements) {
      if (this.contains(el)) {
        elements.push(isNaN(el) ? el : Number(el));
      }
    }
    return elements;
  }

  /**
   * @public
   * clears the set
   */
  clear() {
    this._init();
  }

  /**
   * @private
   * @param {Set} s
   * @param {string} type
   * @returns {Set}
   * @throws {Error}
   */
  _operate(s, type) {
    if (s instanceof Set) {
      return this[`_${type}Set`](s);
    }
    else {
      throw new Error(`.${type} expects a set as a param`);
    }
  }

  /**
   * @private
   * @param {Set} s
   * @returns {Set}
   */
  _unionSet(s) {
    let union = new Set();
    for (let el in this._elements) {
      if (this.contains(el)) {
        union.add(el);
      }
    }
    s.toArray().forEach((el) => {
      union.add(el);
    });
    return union;
  }

  /**
   * @private
   * @param {Set} s
   * @returns {Set}
   */
  _intersectSet(s) {
    let intersect = new Set();
    for (let el in this._elements) {
      if (this.contains(el) && s.contains(el)) {
        intersect.add(el);
      }
    }
    return intersect;
  }

  /**
   * @private
   * @param {Set} s
   * @returns {Set}
   */
  _diffSet(s) {
    let diffSet = new Set();
    for (let el in this._elements) {
      if (this.contains(el) && !s.contains(el)) {
        diffSet.add(el);
      }
    }
    return diffSet;
  }

  /**
   * @private
   * @param {Set} s
   * @returns {boolean}
   */
  _isSetSubsetOf(s) {
    for (let el in this._elements) {
      if (this.contains(el) && !s.contains(el)) {
        return false;
      }
    }
    return true;
  }

  /**
   * @private
   * inits the set properties
   */
  _init() {
    this._elements = {};
    this._count = 0;
  }

}

module.exports = Set;<|endoftext|>


<commit_before>/**
 * The unit tests for the exported functions from `audio-over-socket.js`.
 */

import autobahn from 'autobahn';
import * as aos from './audio-over-socket';
import { settings } from '../communication';
import * as communication from '../communication/websocket';
import * as utils from '.';
import broadcaster from '../broadcaster';

describe('Audio Over socket', () => {
  beforeEach(() => {
    // Make sure we have enough time to complete some tests.
    jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000;
  });

  beforeAll(() => {
    settings.wsUrl = 'wss://fake.ws.url';
  });

  describe('registerStreamForRecorder', () => {
    const rpcName = 'rpcName';
    let recorderStub;
    let connectionOpenSpy;
    let connectionSessionStub;

    beforeEach(() => {
      recorderStub = jasmine.createSpyObj('Recorder', [
        'addEventListener',
        'dispatchEvent',
      ]);

      // recorderStub.dispatchEvent.and.callFake((event, callback) => {
      //   Pretend as if the event has been fired and thus call the callback.
      // callback(event.type);
      // });

      spyOn(autobahn.Connection.prototype, 'close');
      connectionOpenSpy = spyOn(autobahn.Connection.prototype, 'open');
      connectionSessionStub = jasmine.createSpyObj('Session', [
        'call',
        'register',
        'unregister',
      ]);
      connectionSessionStub.call.and.callFake(() => {
        // eslint-disable-next-line new-cap
        const defer = new autobahn.when.defer();
        defer.resolve();
        return defer.promise;
      });

      connectionSessionStub.register.and.callFake((...args) => {
        const [rpc, callback] = args;

        return Promise.resolve({
          id: '123',
          rpc,
          callback,
        });
      });

      connectionSessionStub.unregister.and.returnValue(Promise.resolve());

      // We cannot use arrow functions because of `this` scope.
      // eslint-disable-next-line func-names
      connectionOpenSpy.and.callFake(function() {
        // This property is returned through the session "property" of a
        // connection instance. Sadly only the get is defined with the
        // `Object.defineProperty` which forces us to mock the internals.
        this._session = connectionSessionStub; // eslint-disable-line no-underscore-dangle
        this.onopen();
      });
    });

    it('should register an RPC call named nl.itslanguage.rpcName', async () => {
      await expectAsync(
        aos.registerStreamForRecorder(recorderStub, rpcName),
      ).toBeResolvedTo({
        id: '123',
        rpc: `nl.itslanguage.${rpcName}`,
        callback: jasmine.any(Function),
      });
    });

    it('should emit websocketserverreadyforaudio when ready to receive audio', async () => {
      const broadcastSpy = spyOn(broadcaster, 'emit');

      await aos.registerStreamForRecorder(recorderStub, rpcName);

      expect(broadcastSpy).toHaveBeenCalledWith('websocketserverreadyforaudio');
    });

    it('should stream audio to the backend', async () => {
      const data = {
        data: new Blob(['Knees weak, arms are heavy.'], { type: 'text/plain' }),
      };

      // Make sure to convert the data to what is actually being sent to the backend: an array
      // with integers.
      const arrayBuffer = await utils.asyncBlobToArrayBuffer(data.data);
      const intArray = Array.from(new Uint8Array(arrayBuffer));

      recorderStub.addEventListener.and.callFake((event, callback) => {
        // Pretend as if the event has been fired and thus call the callback.
        callback(data);
      });

      const result = await aos.registerStreamForRecorder(recorderStub, rpcName);

      const detailsSpy = jasmine.createSpyObj('details', ['progress']);
      await result.callback([], {}, detailsSpy);

      expect(detailsSpy.progress).toHaveBeenCalledWith([intArray]);
    });

    it('should not stream audio if the progress function does not exist', async () => {
      recorderStub.addEventListener.and.callFake((event, callback) => {
        // Pretend as if the event has been fired and thus call the callback.
        callback({
          data: new Blob(['Knees weak, arms are heavy.'], {
            type: 'text/plain',
          }),
        });
      });

      const result = await aos.registerStreamForRecorder(recorderStub, rpcName);

      await expectAsync(result.callback([], {}, {})).toBeRejectedWith(
        'no progress function registered',
      );
    });

    it('should only resolve on the last chunk', async () => {
      let dataavailableCallback = null;
      let stopCallback = null;
      const blob = {
        data: new Blob(['Knees weak, arms are heavy.'], { type: 'text/plain' }),
      };

      recorderStub.addEventListener.and.callFake((event, callback) => {
        switch (event) {
          case 'dataavailable':
            dataavailableCallback = callback;
            break;
          case 'stop':
            stopCallback = callback;
            break;
          default:
            break;
        }
      });

      const result = await aos.registerStreamForRecorder(recorderStub, rpcName);
      const detailsSpy = jasmine.createSpyObj('details', ['progress']);
      result.callback([], {}, detailsSpy);

      dataavailableCallback(blob);

      // We need to wait a bit before we can send the rest.
      setTimeout(async () => {
        // Send the stop event
        stopCallback();

        // Send the final chunk!
        dataavailableCallback(blob);
      }, 1000);

      await result.callback([], {}, detailsSpy);

      expect(detailsSpy.progress).toHaveBeenCalledTimes(2);
    });
  });

  describe('encodeAndSendAudioOnDataAvailable', () => {
    let recorderStub;
    let makeWebsocketCallSpy;
    let dataToBase64Spy;

    beforeEach(() => {
      recorderStub = jasmine.createSpyObj('Recorder', [
        'addEventListener',
        'dispatchEvent',
      ]);
      makeWebsocketCallSpy = spyOn(communication, 'makeWebsocketCall');
      dataToBase64Spy = spyOn(utils, 'dataToBase64');
    });

    it('should send the data when the recorder fires the event', async () => {
      dataToBase64Spy.and.returnValue(
        "There's vomit on his sweater already, mom's spaghetti",
      );
      makeWebsocketCallSpy.and.returnValue(
        Promise.resolve(
          "He's nervous, but on the surface he looks calm and ready",
        ),
      );
      recorderStub.addEventListener.and.callFake((event, callback) => {
        // Pretend as if the event has been fired and thus call the callback.
        callback({
          data: new Blob(['Knees weak, arms are heavy.'], {
            type: 'text/plain',
          }),
        });
      });

      const result = await aos.encodeAndSendAudioOnDataAvailable(
        'r353rv3d1d',
        recorderStub,
        'his.palms.are.sweaty',
      );

      expect(makeWebsocketCallSpy).toHaveBeenCalledWith(
        'his.palms.are.sweaty',
        {
          args: [
            'r353rv3d1d',
            "There's vomit on his sweater already, mom's spaghetti",
            'base64',
          ],
        },
      );

      expect(result).toEqual(
        "He's nervous, but on the surface he looks calm and ready",
      );
    });

    it('should reject if the `makeWebsocketCall` rejected', async () => {
      dataToBase64Spy.and.returnValue(
        "There's vomit on his sweater already, mom's spaghetti",
      );
      makeWebsocketCallSpy.and.returnValue(
        Promise.reject(
          new Error('Websocket server has received and rejected the call.'),
        ),
      );
      recorderStub.addEventListener.and.callFake((event, callback) => {
        // Pretend as if the event has been fired and thus call the callback.
        callback({
          data: new Blob(['Knees weak, arms are heavy.'], {
            type: 'text/plain',
          }),
        });
      });

      try {
        await aos.encodeAndSendAudioOnDataAvailable(
          'r353rv3d1d',
          recorderStub,
          'his.palms.are.sweaty',
        );
        fail('encodeAndSendAudioOnDataAvailable should have failed');
      } catch ({ message }) {
        expect(message).toBe(
          'Websocket server has received and rejected the call.',
        );

        expect(makeWebsocketCallSpy).toHaveBeenCalledWith(
          'his.palms.are.sweaty',
          {
            args: [
              'r353rv3d1d',
              "There's vomit on his sweater already, mom's spaghetti",
              'base64',
            ],
          },
        );
      }
    });
  });

  describe('prepareServerForAudio', () => {
    let recorderStub;
    let makeWebsocketCallSpy;
    let broadcasterSpy;

    beforeEach(() => {
      recorderStub = jasmine.createSpyObj('Recorder', [
        'getAudioSpecs',
        'dispatchEvent',
      ]);
      makeWebsocketCallSpy = spyOn(communication, 'makeWebsocketCall');
      broadcasterSpy = spyOn(broadcaster, 'emit');
    });

    it('should broadcast when the websocket server has successfully been prepped and resolve in the reserved ID', async () => {
      recorderStub.getAudioSpecs.and.returnValue({
        audioFormat: 'audio/ogg',
        audioParameters: {
          bitrate: 9001,
        },
      });
      makeWebsocketCallSpy.and.returnValue(
        Promise.resolve('Websocket server has received and handled the call.'),
      );

      const result = await aos.prepareServerForAudio(
        'r353rv3d1d',
        recorderStub,
        'write.this.down.kiddo',
      );

      expect(makeWebsocketCallSpy).toHaveBeenCalledWith(
        'write.this.down.kiddo',
        {
          args: ['r353rv3d1d', 'audio/ogg'],
          kwargs: {
            bitrate: 9001,
          },
        },
      );

      expect(result).toEqual('r353rv3d1d');

      expect(broadcasterSpy).toHaveBeenCalledWith(
        'websocketserverreadyforaudio',
      );
    });

    it('should reject if the `makeWebsocketCall` rejected', async () => {
      recorderStub.getAudioSpecs.and.returnValue({
        audioFormat: 'audio/ogg',
        audioParameters: {
          bitrate: 9001,
        },
      });
      makeWebsocketCallSpy.and.returnValue(
        Promise.reject(
          new Error('Websocket server has received and rejected the call.'),
        ),
      );

      try {
        await aos.prepareServerForAudio(
          'r353rv3d1d',
          recorderStub,
          'write.this.down.kiddo',
        );
        fail('prepareServerForAudio should have failed');
      } catch (error) {
        expect(makeWebsocketCallSpy).toHaveBeenCalledWith(
          'write.this.down.kiddo',
          {
            args: ['r353rv3d1d', 'audio/ogg'],
            kwargs: {
              bitrate: 9001,
            },
          },
        );
      }
    });
  });
});
<commit_msg>refactor: remove unintentional committed code<commit_after>/**
 * The unit tests for the exported functions from `audio-over-socket.js`.
 */

import autobahn from 'autobahn';
import * as aos from './audio-over-socket';
import { settings } from '../communication';
import * as communication from '../communication/websocket';
import * as utils from '.';
import broadcaster from '../broadcaster';

describe('Audio Over socket', () => {
  beforeEach(() => {
    // Make sure we have enough time to complete some tests.
    jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000;
  });

  beforeAll(() => {
    settings.wsUrl = 'wss://fake.ws.url';
  });

  describe('registerStreamForRecorder', () => {
    const rpcName = 'rpcName';
    let recorderStub;
    let connectionOpenSpy;
    let connectionSessionStub;

    beforeEach(() => {
      recorderStub = jasmine.createSpyObj('Recorder', [
        'addEventListener',
        'dispatchEvent',
      ]);

      spyOn(autobahn.Connection.prototype, 'close');
      connectionOpenSpy = spyOn(autobahn.Connection.prototype, 'open');
      connectionSessionStub = jasmine.createSpyObj('Session', [
        'call',
        'register',
        'unregister',
      ]);
      connectionSessionStub.call.and.callFake(() => {
        // eslint-disable-next-line new-cap
        const defer = new autobahn.when.defer();
        defer.resolve();
        return defer.promise;
      });

      connectionSessionStub.register.and.callFake((...args) => {
        const [rpc, callback] = args;

        return Promise.resolve({
          id: '123',
          rpc,
          callback,
        });
      });

      connectionSessionStub.unregister.and.returnValue(Promise.resolve());

      // We cannot use arrow functions because of `this` scope.
      // eslint-disable-next-line func-names
      connectionOpenSpy.and.callFake(function() {
        // This property is returned through the session "property" of a
        // connection instance. Sadly only the get is defined with the
        // `Object.defineProperty` which forces us to mock the internals.
        this._session = connectionSessionStub; // eslint-disable-line no-underscore-dangle
        this.onopen();
      });
    });

    it('should register an RPC call named nl.itslanguage.rpcName', async () => {
      await expectAsync(
        aos.registerStreamForRecorder(recorderStub, rpcName),
      ).toBeResolvedTo({
        id: '123',
        rpc: `nl.itslanguage.${rpcName}`,
        callback: jasmine.any(Function),
      });
    });

    it('should emit websocketserverreadyforaudio when ready to receive audio', async () => {
      const broadcastSpy = spyOn(broadcaster, 'emit');

      await aos.registerStreamForRecorder(recorderStub, rpcName);

      expect(broadcastSpy).toHaveBeenCalledWith('websocketserverreadyforaudio');
    });

    it('should stream audio to the backend', async () => {
      const data = {
        data: new Blob(['Knees weak, arms are heavy.'], { type: 'text/plain' }),
      };

      // Make sure to convert the data to what is actually being sent to the backend: an array
      // with integers.
      const arrayBuffer = await utils.asyncBlobToArrayBuffer(data.data);
      const intArray = Array.from(new Uint8Array(arrayBuffer));

      recorderStub.addEventListener.and.callFake((event, callback) => {
        // Pretend as if the event has been fired and thus call the callback.
        callback(data);
      });

      const result = await aos.registerStreamForRecorder(recorderStub, rpcName);

      const detailsSpy = jasmine.createSpyObj('details', ['progress']);
      await result.callback([], {}, detailsSpy);

      expect(detailsSpy.progress).toHaveBeenCalledWith([intArray]);
    });

    it('should not stream audio if the progress function does not exist', async () => {
      recorderStub.addEventListener.and.callFake((event, callback) => {
        // Pretend as if the event has been fired and thus call the callback.
        callback({
          data: new Blob(['Knees weak, arms are heavy.'], {
            type: 'text/plain',
          }),
        });
      });

      const result = await aos.registerStreamForRecorder(recorderStub, rpcName);

      await expectAsync(result.callback([], {}, {})).toBeRejectedWith(
        'no progress function registered',
      );
    });

    it('should only resolve on the last chunk', async () => {
      let dataavailableCallback = null;
      let stopCallback = null;
      const blob = {
        data: new Blob(['Knees weak, arms are heavy.'], { type: 'text/plain' }),
      };

      recorderStub.addEventListener.and.callFake((event, callback) => {
        switch (event) {
          case 'dataavailable':
            dataavailableCallback = callback;
            break;
          case 'stop':
            stopCallback = callback;
            break;
          default:
            break;
        }
      });

      const result = await aos.registerStreamForRecorder(recorderStub, rpcName);
      const detailsSpy = jasmine.createSpyObj('details', ['progress']);
      result.callback([], {}, detailsSpy);

      dataavailableCallback(blob);

      // We need to wait a bit before we can send the rest.
      setTimeout(async () => {
        // Send the stop event
        stopCallback();

        // Send the final chunk!
        dataavailableCallback(blob);
      }, 1000);

      await result.callback([], {}, detailsSpy);

      expect(detailsSpy.progress).toHaveBeenCalledTimes(2);
    });
  });

  describe('encodeAndSendAudioOnDataAvailable', () => {
    let recorderStub;
    let makeWebsocketCallSpy;
    let dataToBase64Spy;

    beforeEach(() => {
      recorderStub = jasmine.createSpyObj('Recorder', [
        'addEventListener',
        'dispatchEvent',
      ]);
      makeWebsocketCallSpy = spyOn(communication, 'makeWebsocketCall');
      dataToBase64Spy = spyOn(utils, 'dataToBase64');
    });

    it('should send the data when the recorder fires the event', async () => {
      dataToBase64Spy.and.returnValue(
        "There's vomit on his sweater already, mom's spaghetti",
      );
      makeWebsocketCallSpy.and.returnValue(
        Promise.resolve(
          "He's nervous, but on the surface he looks calm and ready",
        ),
      );
      recorderStub.addEventListener.and.callFake((event, callback) => {
        // Pretend as if the event has been fired and thus call the callback.
        callback({
          data: new Blob(['Knees weak, arms are heavy.'], {
            type: 'text/plain',
          }),
        });
      });

      const result = await aos.encodeAndSendAudioOnDataAvailable(
        'r353rv3d1d',
        recorderStub,
        'his.palms.are.sweaty',
      );

      expect(makeWebsocketCallSpy).toHaveBeenCalledWith(
        'his.palms.are.sweaty',
        {
          args: [
            'r353rv3d1d',
            "There's vomit on his sweater already, mom's spaghetti",
            'base64',
          ],
        },
      );

      expect(result).toEqual(
        "He's nervous, but on the surface he looks calm and ready",
      );
    });

    it('should reject if the `makeWebsocketCall` rejected', async () => {
      dataToBase64Spy.and.returnValue(
        "There's vomit on his sweater already, mom's spaghetti",
      );
      makeWebsocketCallSpy.and.returnValue(
        Promise.reject(
          new Error('Websocket server has received and rejected the call.'),
        ),
      );
      recorderStub.addEventListener.and.callFake((event, callback) => {
        // Pretend as if the event has been fired and thus call the callback.
        callback({
          data: new Blob(['Knees weak, arms are heavy.'], {
            type: 'text/plain',
          }),
        });
      });

      try {
        await aos.encodeAndSendAudioOnDataAvailable(
          'r353rv3d1d',
          recorderStub,
          'his.palms.are.sweaty',
        );
        fail('encodeAndSendAudioOnDataAvailable should have failed');
      } catch ({ message }) {
        expect(message).toBe(
          'Websocket server has received and rejected the call.',
        );

        expect(makeWebsocketCallSpy).toHaveBeenCalledWith(
          'his.palms.are.sweaty',
          {
            args: [
              'r353rv3d1d',
              "There's vomit on his sweater already, mom's spaghetti",
              'base64',
            ],
          },
        );
      }
    });
  });

  describe('prepareServerForAudio', () => {
    let recorderStub;
    let makeWebsocketCallSpy;
    let broadcasterSpy;

    beforeEach(() => {
      recorderStub = jasmine.createSpyObj('Recorder', [
        'getAudioSpecs',
        'dispatchEvent',
      ]);
      makeWebsocketCallSpy = spyOn(communication, 'makeWebsocketCall');
      broadcasterSpy = spyOn(broadcaster, 'emit');
    });

    it('should broadcast when the websocket server has successfully been prepped and resolve in the reserved ID', async () => {
      recorderStub.getAudioSpecs.and.returnValue({
        audioFormat: 'audio/ogg',
        audioParameters: {
          bitrate: 9001,
        },
      });
      makeWebsocketCallSpy.and.returnValue(
        Promise.resolve('Websocket server has received and handled the call.'),
      );

      const result = await aos.prepareServerForAudio(
        'r353rv3d1d',
        recorderStub,
        'write.this.down.kiddo',
      );

      expect(makeWebsocketCallSpy).toHaveBeenCalledWith(
        'write.this.down.kiddo',
        {
          args: ['r353rv3d1d', 'audio/ogg'],
          kwargs: {
            bitrate: 9001,
          },
        },
      );

      expect(result).toEqual('r353rv3d1d');

      expect(broadcasterSpy).toHaveBeenCalledWith(
        'websocketserverreadyforaudio',
      );
    });

    it('should reject if the `makeWebsocketCall` rejected', async () => {
      recorderStub.getAudioSpecs.and.returnValue({
        audioFormat: 'audio/ogg',
        audioParameters: {
          bitrate: 9001,
        },
      });
      makeWebsocketCallSpy.and.returnValue(
        Promise.reject(
          new Error('Websocket server has received and rejected the call.'),
        ),
      );

      try {
        await aos.prepareServerForAudio(
          'r353rv3d1d',
          recorderStub,
          'write.this.down.kiddo',
        );
        fail('prepareServerForAudio should have failed');
      } catch (error) {
        expect(makeWebsocketCallSpy).toHaveBeenCalledWith(
          'write.this.down.kiddo',
          {
            args: ['r353rv3d1d', 'audio/ogg'],
            kwargs: {
              bitrate: 9001,
            },
          },
        );
      }
    });
  });
});
<|endoftext|>