<commit_before>'use strict'

const pkg = require('../package.json')
const Configstore = require('configstore')
const defaultConfig = require('../defaultConfig')
const neonjs = require('neon-js')
const chalk = require('chalk')
const q = require('q')
const asTable = require('as-table').configure({
  title: x => chalk.bold.green(x),
  delimiter: chalk.dim.green(' | '),
  dash: chalk.dim.green('-'),
  print: obj => (typeof obj === 'boolean') ? (obj ? 'yes' : 'no') : String(obj)
})
const network = require('./network')

const conf = new Configstore(pkg.name, defaultConfig)

function walletCreate(self, args, cb) {
  self.prompt([
    {
      type: 'input',
      name: 'label',
      message: chalk.green('? Give this address a label [optional] : ')
    },
    {
      type: 'password',
      name: 'passphrase',
      message: chalk.green('? Provide a passphrase : ')
    },
    {
      type: 'password',
      name: 'passphrase2',
      message: chalk.green('? Confirm your passphrase : ')
    }
  ], function (inputs) {
    if (inputs.passphrase.length <= 4) {
      self.log(' Passphrase must be longer than 4 characters.')
      cb()
    } else if (inputs.passphrase !== inputs.passphrase2) {
      self.log(' Passphrase and confirmation don\'t match.')
      cb()
    } else {
      let newPrivateKey = neonjs.generatePrivateKey()
      let newWif = neonjs.getWIFFromPrivateKey(newPrivateKey)
      encryptKey(self, newWif, inputs)
        .then((outputs) => {
          cb()
        })
    }
  })
}

function walletImport(self, args, cb) {
  self.prompt([
    {
      type: 'password',
      name: 'existingWif',
      message: chalk.green(' Enter your existing private key in WIF format : ')
    },
    {
      type: 'input',
      name: 'label',
      message: chalk.green('? Give this address a label [optional] : ')
    },
    {
      type: 'password',
      name: 'passphrase',
      message: chalk.green('? Provide a passphrase : ')
    },
    {
      type: 'password',
      name: 'passphrase2',
      message: chalk.green('? Confirm your passphrase : ')
    }
  ], function (inputs) {
    if (inputs.passphrase.length <= 4) {
      self.log(' Passphrase must be longer than 4 characters.')
      cb()
    } else if (inputs.passphrase !== inputs.passphrase2) {
      self.log(' Passphrase and confirmation don\'t match.')
      cb()
    } else {
      encryptKey(self, inputs.existingWif.toString(), inputs)
        .then((outputs) => {
          cb()
        })
    }
  })
}

function walletList(self, args, cb) {
  let tableData = [];
  let addresses = conf.get('addresses')
  if (addresses.length <= 0) {
    self.log(' No addresses found.')
  } else {
    let addressList = []
    for (let i = 0; i < addresses.length; i++) {
      let row = {
        Label: chalk.green(addresses[i].label),
        Address: chalk.green(addresses[i].address)
      }
      for (let asset in addresses[i].balances) {
        if (asset != 'unspent') {
          row[asset] = chalk.green(addresses[i].balances[asset])
        }
      }
      tableData.push(row)
    }
    self.log(asTable(tableData).toString());
  }
  cb()
}

function walletRemove(self, args, cb) {
  let addresses = conf.get('addresses')
  let addressList = []
  let removed = false
  if (addresses.length <= 0) {
    self.log(' No addresses found.')
    cb()
  } else {
    for (let i = 0; i < addresses.length; i++) {
      addressList.push((addresses[i].label ? addresses[i].label + ' (' : '') + addresses[i].address + (addresses[i].label ? ')' : ''))
    }
    self.prompt({
      type: 'list',
      name: 'addressSelection',
      message: chalk.green('Which address would you like to remove?'),
      choices: addressList
    }, (result) => {
      let address = result.addressSelection;
      if (address.indexOf('(') >= 0) {
        let foundAddress = address.match(/\((.*)\)/)
        address = foundAddress[1]
      }
      for (let i = 0; i < addresses.length; i++) {
        if (addresses[i].address == address) {
          addresses.splice(i, 1)
          self.log(chalk.green(' Removed ' + address))
          removed = true
        }
      }
      conf.set('addresses', addresses)
      if (!removed) {
        self.log(' ' + address + ' not found in local storage.')
      }
      cb()
    })
  }
}

function walletClear(self, args, cb) {
  self.prompt({
    type: 'confirm',
    name: 'doClear',
    message: chalk.bold.red('Are you certain you\'d like to purge locally saved addresses and encrypted private keys?'),
    default: false
  }, (result) => {
    if (result.doClear) {
      conf.set('addresses', [])
      self.log(chalk.white(' Wallet cleared.'))
    }
    cb()
  })
}

function encryptKey(self, newWif, inputs) {
  let deferred = q.defer();

  neonjs.encryptWifAccount(newWif, inputs.passphrase.toString())
    .then((newAccount) => {
      let wallet = {
        label: (inputs.label != undefined ? inputs.label : ''),
        address: newAccount.address,
        encryptedWif: newAccount.encryptedWif
      }
      let addresses = conf.get('addresses')
      addresses.push(wallet)
      conf.set('addresses', addresses);
      self.log(chalk.bold.green(' This information will only be displayed once!'))
      self.log(chalk.green(' Your address and encrypted private key will be stored locally on your machine.'))
      self.log(chalk.green(' Your private key and passphrase will not be stored anywhere.'))
      self.log(chalk.green(' Label: ') + chalk.bold.green(inputs.label))
      self.log(chalk.green(' Public Address: ') + chalk.bold.green(newAccount.address))
      self.log(chalk.green(' Private Key: ') + chalk.bold.green(newAccount.wif))
      self.log(chalk.green(' Encrypted Key: ') + chalk.bold.green(newAccount.encryptedWif))
      self.log(chalk.green(' Passphrase: ') + chalk.bold.green(newAccount.passphrase))
      self.log(chalk.bold.red(' Now is your only chance to make a secure copy of your private key!'))
      self.prompt({
        type: 'confirm',
        name: 'keysaved',
        message: chalk.green('Have you saved your private key securely? '),
        default: true
      }, function (answer) {
        self.log(chalk.green(' I must believe you have.'))
        deferred.resolve(answer)
      })
    })

  return deferred.promise;
}

function walletShowBalances(self, args, cb) {
  let addresses = conf.get('addresses')
  let addressList = []
  let addressIndex
  if (addresses.length <= 0) {
    self.log(' No addresses found.')
    cb()
  } else {
    for (let i = 0; i < addresses.length; i++) {
      addressList.push((addresses[i].label ? addresses[i].label + ' (' : '') + addresses[i].address + (addresses[i].label ? ')' : ''))
    }
    self.prompt({
      type: 'list',
      name: 'addressSelection',
      message: chalk.green('Which address would you like to see the balance of?'),
      choices: addressList
    }, (result) => {
      let address = result.addressSelection;
      if (address.indexOf('(') >= 0) {
        let foundAddress = address.match(/\((.*)\)/)
        address = foundAddress[1]
      }
      for (let i = 0; i < addresses.length; i++) {
        if (addresses[i].address == address) {
          addressIndex = i
        }
      }
      let tableData = []
      for (let asset in addresses[addressIndex].balances) {
        if (asset != 'unspent') {
          let row = {
            Asset: chalk.green(asset),
            Balance: chalk.green(addresses[addressIndex].balances[asset])
          }
          tableData.push(row)
        }
      }
      self.log(asTable(tableData).toString())
      cb()
    })
  }
}

function walletUpdateBalances(self) {
  let addresses = conf.get('addresses')
  for (let i = 0; i < addresses.length; i++) {
    neonjs.getBalance(network.get(), addresses[i].address)
      .then((result) => {
        addresses[i].balances = result
        conf.set('addresses', addresses)
      })
  }
}

module.exports.create = walletCreate
module.exports.import = walletImport
module.exports.list = walletList
module.exports.remove = walletRemove
module.exports.clear = walletClear
module.exports.showBalances = walletShowBalances
module.exports.updateBalances = walletUpdateBalances
<commit_msg>Minor WIF validation<commit_after>'use strict'

const pkg = require('../package.json')
const Configstore = require('configstore')
const defaultConfig = require('../defaultConfig')
const neonjs = require('neon-js')
const chalk = require('chalk')
const q = require('q')
const asTable = require('as-table').configure({
  title: x => chalk.bold.green(x),
  delimiter: chalk.dim.green(' | '),
  dash: chalk.dim.green('-'),
  print: obj => (typeof obj === 'boolean') ? (obj ? 'yes' : 'no') : String(obj)
})
const network = require('./network')

const conf = new Configstore(pkg.name, defaultConfig)

function walletCreate(self, args, cb) {
  self.prompt([
    {
      type: 'input',
      name: 'label',
      message: chalk.green('? Give this address a label [optional] : ')
    },
    {
      type: 'password',
      name: 'passphrase',
      message: chalk.green('? Provide a passphrase : ')
    },
    {
      type: 'password',
      name: 'passphrase2',
      message: chalk.green('? Confirm your passphrase : ')
    }
  ], function (inputs) {
    if (inputs.passphrase.length <= 4) {
      self.log(' Passphrase must be longer than 4 characters.')
      cb()
    } else if (inputs.passphrase !== inputs.passphrase2) {
      self.log(' Passphrase and confirmation don\'t match.')
      cb()
    } else {
      let newPrivateKey = neonjs.generatePrivateKey()
      let newWif = neonjs.getWIFFromPrivateKey(newPrivateKey)
      encryptKey(self, newWif, inputs)
        .then((outputs) => {
          cb()
        })
    }
  })
}

function walletImport(self, args, cb) {
  self.prompt([
    {
      type: 'password',
      name: 'existingWif',
      message: chalk.green(' Enter your existing private key in WIF format : ')
    },
    {
      type: 'input',
      name: 'label',
      message: chalk.green('? Give this address a label [optional] : ')
    },
    {
      type: 'password',
      name: 'passphrase',
      message: chalk.green('? Provide a passphrase : ')
    },
    {
      type: 'password',
      name: 'passphrase2',
      message: chalk.green('? Confirm your passphrase : ')
    }
  ], function (inputs) {
    if (inputs.existingWif.toString().length != 52) {
      self.log(' Please provide a valid private key in WIF format.')
      cb()
    } else if (inputs.passphrase.length <= 4) {
      self.log(' Passphrase must be longer than 4 characters.')
      cb()
    } else if (inputs.passphrase !== inputs.passphrase2) {
      self.log(' Passphrase and confirmation don\'t match.')
      cb()
    } else {
      encryptKey(self, inputs.existingWif.toString(), inputs)
        .then((outputs) => {
          cb()
        })
    }
  })
}

function walletList(self, args, cb) {
  let tableData = [];
  let addresses = conf.get('addresses')
  if (addresses.length <= 0) {
    self.log(' No addresses found.')
  } else {
    let addressList = []
    for (let i = 0; i < addresses.length; i++) {
      let row = {
        Label: chalk.green(addresses[i].label),
        Address: chalk.green(addresses[i].address)
      }
      for (let asset in addresses[i].balances) {
        if (asset != 'unspent') {
          row[asset] = chalk.green(addresses[i].balances[asset])
        }
      }
      tableData.push(row)
    }
    self.log(asTable(tableData).toString());
  }
  cb()
}

function walletRemove(self, args, cb) {
  let addresses = conf.get('addresses')
  let addressList = []
  let removed = false
  if (addresses.length <= 0) {
    self.log(' No addresses found.')
    cb()
  } else {
    for (let i = 0; i < addresses.length; i++) {
      addressList.push((addresses[i].label ? addresses[i].label + ' (' : '') + addresses[i].address + (addresses[i].label ? ')' : ''))
    }
    self.prompt({
      type: 'list',
      name: 'addressSelection',
      message: chalk.green('Which address would you like to remove?'),
      choices: addressList
    }, (result) => {
      let address = result.addressSelection;
      if (address.indexOf('(') >= 0) {
        let foundAddress = address.match(/\((.*)\)/)
        address = foundAddress[1]
      }
      for (let i = 0; i < addresses.length; i++) {
        if (addresses[i].address == address) {
          addresses.splice(i, 1)
          self.log(chalk.green(' Removed ' + address))
          removed = true
        }
      }
      conf.set('addresses', addresses)
      if (!removed) {
        self.log(' ' + address + ' not found in local storage.')
      }
      cb()
    })
  }
}

function walletClear(self, args, cb) {
  self.prompt({
    type: 'confirm',
    name: 'doClear',
    message: chalk.bold.red('Are you certain you\'d like to purge locally saved addresses and encrypted private keys?'),
    default: false
  }, (result) => {
    if (result.doClear) {
      conf.set('addresses', [])
      self.log(chalk.white(' Wallet cleared.'))
    }
    cb()
  })
}

function encryptKey(self, newWif, inputs) {
  let deferred = q.defer();

  neonjs.encryptWifAccount(newWif, inputs.passphrase.toString())
    .then((newAccount) => {
      let wallet = {
        label: (inputs.label != undefined ? inputs.label : ''),
        address: newAccount.address,
        encryptedWif: newAccount.encryptedWif
      }
      let addresses = conf.get('addresses')
      addresses.push(wallet)
      conf.set('addresses', addresses);
      self.log(chalk.bold.green(' This information will only be displayed once!'))
      self.log(chalk.green(' Your address and encrypted private key will be stored locally on your machine.'))
      self.log(chalk.green(' Your private key and passphrase will not be stored anywhere.'))
      self.log(chalk.green(' Label: ') + chalk.bold.green(inputs.label))
      self.log(chalk.green(' Public Address: ') + chalk.bold.green(newAccount.address))
      self.log(chalk.green(' Private Key: ') + chalk.bold.green(newAccount.wif))
      self.log(chalk.green(' Encrypted Key: ') + chalk.bold.green(newAccount.encryptedWif))
      self.log(chalk.green(' Passphrase: ') + chalk.bold.green(newAccount.passphrase))
      self.log(chalk.bold.red(' Now is your only chance to make a secure copy of your private key!'))
      self.prompt({
        type: 'confirm',
        name: 'keysaved',
        message: chalk.green('Have you saved your private key securely? '),
        default: true
      }, function (answer) {
        self.log(chalk.green(' I must believe you have.'))
        deferred.resolve(answer)
      })
    })

  return deferred.promise;
}

function walletShowBalances(self, args, cb) {
  let addresses = conf.get('addresses')
  let addressList = []
  let addressIndex
  if (addresses.length <= 0) {
    self.log(' No addresses found.')
    cb()
  } else {
    for (let i = 0; i < addresses.length; i++) {
      addressList.push((addresses[i].label ? addresses[i].label + ' (' : '') + addresses[i].address + (addresses[i].label ? ')' : ''))
    }
    self.prompt({
      type: 'list',
      name: 'addressSelection',
      message: chalk.green('Which address would you like to see the balance of?'),
      choices: addressList
    }, (result) => {
      let address = result.addressSelection;
      if (address.indexOf('(') >= 0) {
        let foundAddress = address.match(/\((.*)\)/)
        address = foundAddress[1]
      }
      for (let i = 0; i < addresses.length; i++) {
        if (addresses[i].address == address) {
          addressIndex = i
        }
      }
      let tableData = []
      for (let asset in addresses[addressIndex].balances) {
        if (asset != 'unspent') {
          let row = {
            Asset: chalk.green(asset),
            Balance: chalk.green(addresses[addressIndex].balances[asset])
          }
          tableData.push(row)
        }
      }
      self.log(asTable(tableData).toString())
      cb()
    })
  }
}

function walletUpdateBalances(self) {
  let addresses = conf.get('addresses')
  for (let i = 0; i < addresses.length; i++) {
    neonjs.getBalance(network.get(), addresses[i].address)
      .then((result) => {
        addresses[i].balances = result
        conf.set('addresses', addresses)
      })
  }
}

module.exports.create = walletCreate
module.exports.import = walletImport
module.exports.list = walletList
module.exports.remove = walletRemove
module.exports.clear = walletClear
module.exports.showBalances = walletShowBalances
module.exports.updateBalances = walletUpdateBalances
<|endoftext|>


<commit_before>var PathObserver = require('observe-js').PathObserver
var ObjectObserver = require('observe-js').ObjectObserver
var ArrayObserver = require('observe-js').ArrayObserver

var observers = new WeakMap()

function getStore (obj) {
  var store = observers.get(obj)
  if (store === undefined) {
    store = []
    observers.set(obj, store)
  }
  return store
}

function getObserverInStore (store, keypath) {
  if (!store) {
    return
  }
  for (var i = 0, len = store.length; i < len; i++) {
    if (store[i].keypath === keypath) {
      return store[i]
    }
  }
}

function getObserverFor (obj, keypath) {
  var store = observers.get(obj)
  var observer = getObserverInStore(store, keypath)
  if (!observer) {
    store = store || getStore(obj)
    observer = getObserverInStore(store, keypath)
    if (!observer) {
      observer = new WatchyObserver(obj, keypath)
      store.push(observer)
    }
  }
  return observer
}

function removeObserver (obj, keypath, callback) {
  var store = observers.get(obj)
  var observer = getObserverInStore(store, keypath)
  if (!store || !observer) {
    return
  }
  observer.remove(callback)
  if (observer.isEmpty()) {
    observer.close()
    store.splice(store.indexOf(observer), 1)
    if (!store.length) {
      observers.delete(obj)
    }
  }
}

exports.observe = function (obj, keypath, callback) {
  var observer = getObserverFor(obj, keypath)
  observer.add(callback)
  return {
    close: function () {
      exports.unobserve(obj, keypath, callback)
    },
    getValue: function () {
      return exports.get(obj, keypath)
    },
    setValue: function (value) {
      return exports.set(obj, keypath, value)
    }
  }
}

exports.unobserve = function (obj, keypath, callback) {
  removeObserver(obj, keypath, callback)
}

exports.get = function (obj, keypath) {
  return obj[keypath]
}

exports.set = function (obj, keypath, value) {
  obj[keypath] = value
  if (window.Platform && window.Platform.performMicrotaskCheckpoint) {
    window.Platform.performMicrotaskCheckpoint()
  }
  return obj[keypath]
}

function WatchyObserver (obj, keypath) {
  var self = this
  WatchyObserver._count++
  self.obj = obj
  self.keypath = keypath
  self.callbacks = []

  self.pathObs = new PathObserver(obj, keypath)
  self.valueObs

  function callback (newValue, oldValue) {
    console.log('tick', keypath, obj)
    var cbs = self.callbacks
    for (var c = 0, len = cbs.length, cb; c < len && (cb = cbs[c]); c++) {
      cb(newValue, oldValue)
    }
  }

  function updateSubObserver (newValue, oldValue) {
    if (self.valueObs) {
      self.valueObs.close()
      self.valueObs = null
    }

    if ((typeof (newValue) === 'object') && (newValue !== null)) {
      if (Array.isArray(newValue)) {
        self.valueObs = new ArrayObserver(newValue)
        self.valueObs.open(function (splice) {
          callback(obj[keypath])
        })
      } else {
        self.valueObs = new ObjectObserver(newValue)
        self.valueObs.open(function (added, removed, changed, getOldValueFn) {
          callback(obj[keypath])
        })
      }
    }
  }

  self.pathObs.open(function (newValue, oldValue) {
    updateSubObserver(newValue, oldValue)
    callback(newValue, oldValue)
  })

  updateSubObserver(obj[keypath])
}

WatchyObserver.prototype.add = function (callback) {
  var index = this.callbacks.indexOf(callback)
  if (index === -1) {
    this.callbacks.push(callback)
  }
}

WatchyObserver.prototype.remove = function (callback) {
  var index = this.callbacks.indexOf(callback)
  if (index !== -1) {
    this.callbacks.splice(index, 1)
  }
}

WatchyObserver.prototype.isEmpty = function () {
  return !this.callbacks.length
}

WatchyObserver.prototype.close = function () {
  WatchyObserver._count--
  this.pathObs.close()
  if (this.valueObs) {
    this.valueObs.close()
    this.valueObs = null
  }
  this.obj = null
  this.keypath = null
  this.callbacks = []
}

WatchyObserver._count = 0

exports.WatchyObserver = WatchyObserver
<commit_msg>chore: Remove console.log<commit_after>var PathObserver = require('observe-js').PathObserver
var ObjectObserver = require('observe-js').ObjectObserver
var ArrayObserver = require('observe-js').ArrayObserver

var observers = new WeakMap()

function getStore (obj) {
  var store = observers.get(obj)
  if (store === undefined) {
    store = []
    observers.set(obj, store)
  }
  return store
}

function getObserverInStore (store, keypath) {
  if (!store) {
    return
  }
  for (var i = 0, len = store.length; i < len; i++) {
    if (store[i].keypath === keypath) {
      return store[i]
    }
  }
}

function getObserverFor (obj, keypath) {
  var store = observers.get(obj)
  var observer = getObserverInStore(store, keypath)
  if (!observer) {
    store = store || getStore(obj)
    observer = getObserverInStore(store, keypath)
    if (!observer) {
      observer = new WatchyObserver(obj, keypath)
      store.push(observer)
    }
  }
  return observer
}

function removeObserver (obj, keypath, callback) {
  var store = observers.get(obj)
  var observer = getObserverInStore(store, keypath)
  if (!store || !observer) {
    return
  }
  observer.remove(callback)
  if (observer.isEmpty()) {
    observer.close()
    store.splice(store.indexOf(observer), 1)
    if (!store.length) {
      observers.delete(obj)
    }
  }
}

exports.observe = function (obj, keypath, callback) {
  var observer = getObserverFor(obj, keypath)
  observer.add(callback)
  return {
    close: function () {
      exports.unobserve(obj, keypath, callback)
    },
    getValue: function () {
      return exports.get(obj, keypath)
    },
    setValue: function (value) {
      return exports.set(obj, keypath, value)
    }
  }
}

exports.unobserve = function (obj, keypath, callback) {
  removeObserver(obj, keypath, callback)
}

exports.get = function (obj, keypath) {
  return obj[keypath]
}

exports.set = function (obj, keypath, value) {
  obj[keypath] = value
  if (window.Platform && window.Platform.performMicrotaskCheckpoint) {
    window.Platform.performMicrotaskCheckpoint()
  }
  return obj[keypath]
}

function WatchyObserver (obj, keypath) {
  var self = this
  WatchyObserver._count++
  self.obj = obj
  self.keypath = keypath
  self.callbacks = []

  self.pathObs = new PathObserver(obj, keypath)
  self.valueObs

  function callback (newValue, oldValue) {
    var cbs = self.callbacks
    for (var c = 0, len = cbs.length, cb; c < len && (cb = cbs[c]); c++) {
      cb(newValue, oldValue)
    }
  }

  function updateSubObserver (newValue, oldValue) {
    if (self.valueObs) {
      self.valueObs.close()
      self.valueObs = null
    }

    if ((typeof (newValue) === 'object') && (newValue !== null)) {
      if (Array.isArray(newValue)) {
        self.valueObs = new ArrayObserver(newValue)
        self.valueObs.open(function (splice) {
          callback(obj[keypath])
        })
      } else {
        self.valueObs = new ObjectObserver(newValue)
        self.valueObs.open(function (added, removed, changed, getOldValueFn) {
          callback(obj[keypath])
        })
      }
    }
  }

  self.pathObs.open(function (newValue, oldValue) {
    updateSubObserver(newValue, oldValue)
    callback(newValue, oldValue)
  })

  updateSubObserver(obj[keypath])
}

WatchyObserver.prototype.add = function (callback) {
  var index = this.callbacks.indexOf(callback)
  if (index === -1) {
    this.callbacks.push(callback)
  }
}

WatchyObserver.prototype.remove = function (callback) {
  var index = this.callbacks.indexOf(callback)
  if (index !== -1) {
    this.callbacks.splice(index, 1)
  }
}

WatchyObserver.prototype.isEmpty = function () {
  return !this.callbacks.length
}

WatchyObserver.prototype.close = function () {
  WatchyObserver._count--
  this.pathObs.close()
  if (this.valueObs) {
    this.valueObs.close()
    this.valueObs = null
  }
  this.obj = null
  this.keypath = null
  this.callbacks = []
}

WatchyObserver._count = 0

exports.WatchyObserver = WatchyObserver
<|endoftext|>


<commit_before>
const fs = require('fs')
const mysql = require('mysql')
const KEY = JSON.parse( fs.readFileSync(`${__dirname}/../secret/key.json`) )
const { INTERVAL, AUTO } = JSON.parse( fs.readFileSync(`${__dirname}/../config.json`) )
const parser = require('./parser')

const state = {
  idols: [],
  endDate: 0,
  valid: false
}

const QUERY_TEST = `
  SELECT name
  FROM idol
  WHERE name = ?
`

function start(func, time) {
  func()
  setInterval(func, time)
}

/**
 * 신규 아이돌 가져오기
 */
function detectNewIdols(keyboard) {
  return parser.gachaParse()
  .then(({type, idols, ssrNames, endDate}) => {
    const ssr = ssrNames.reduce((p, n) => `${p}, ${n}`)
    const date = '~' + endDate
      .replace(/월\s/, '/')
      .replace(/일.*/, '')
    const str = `${ssr} ${type} ${date}`

    state.endDate = new Date(endDate.replace(/월\s/, '/').replace('일', ''))
    state.endDate.setYear(new Date().getFullYear())

    if (keyboard.now != str) {
      keyboard.now = str
      parser.idolParse(idols)
      state.idols = idols
    }
  })
}

/**
 * 신규 아이돌 수동설정
 */
function setNewIdols(keyboard) {
  return new Promise((resolve, reject) => {
    state.endDate = new Date('9/3 14:59')
    state.endDate.setYear(new Date().getFullYear())
    state.endDate.setMilliseconds(INTERVAL.parse)
    state.valid = true
    state.idols = [
      '[프라이빗 메이드] 토토키 아이리',
    ]
    keyboard.now = '신데페스 ~9/3'

    parser.idolParse(state.idols)
    resolve()
  })
}

/**
 * DB에 확률업 아이돌 추가됐는지 확인
 */
function DBcheck() {
  const connection = mysql.createConnection(KEY.DB)
  connection.connect()

  const promises = state.idols.map(idol => new Promise((resolve, reject) => {
    connection.query(QUERY_TEST, idol, (err, result) => {
      if (err) reject(err)
      else if (!result.length) reject(err)
      else resolve(result)
    })
  }))

  Promise.all(promises)
  .then(() => state.valid = true)
  .catch(() => state.valid = false)
  .then(() => connection.end())
}

module.exports = function(border, keyboard) {
  start(() => {
    if (!state.valid || new Date() > state.endDate) {
      (AUTO ? detectNewIdols : setNewIdols)(keyboard).then(DBcheck)
    }
  }, INTERVAL.parse)
  start(border.getNowBorder, INTERVAL.now)
  start(border.getPredictBorder, INTERVAL.predict)
}
<commit_msg>DB 체크 정상화<commit_after>
const fs = require('fs')
const mysql = require('mysql')
const KEY = JSON.parse( fs.readFileSync(`${__dirname}/../secret/key.json`) )
const { INTERVAL, AUTO } = JSON.parse( fs.readFileSync(`${__dirname}/../config.json`) )
const parser = require('./parser')

const state = {
  idols: [],
  endDate: 0,
  valid: false
}

const QUERY_TEST = `
  SELECT name
  FROM idol
  WHERE name = ?
`

function start(func, time) {
  func()
  setInterval(func, time)
}

/**
 * 신규 아이돌 가져오기
 */
function detectNewIdols(keyboard) {
  return parser.gachaParse()
  .then(({type, idols, ssrNames, endDate}) => {
    const ssr = ssrNames.reduce((p, n) => `${p}, ${n}`)
    const date = '~' + endDate
      .replace(/월\s/, '/')
      .replace(/일.*/, '')
    const str = `${ssr} ${type} ${date}`

    state.endDate = new Date(endDate.replace(/월\s/, '/').replace('일', ''))
    state.endDate.setYear(new Date().getFullYear())

    if (!state.valid || keyboard.now != str) {
      keyboard.now = str
      parser.idolParse(idols)
      state.idols = idols
    }
  })
}

/**
 * 신규 아이돌 수동설정
 */
function setNewIdols(keyboard) {
  return new Promise((resolve, reject) => {
    state.endDate = new Date('9/3 14:59')
    state.endDate.setYear(new Date().getFullYear())
    state.endDate.setMilliseconds(INTERVAL.parse)
    state.valid = true
    state.idols = [
      '[프라이빗 메이드] 토토키 아이리',
    ]
    keyboard.now = '신데페스 ~9/3'

    parser.idolParse(state.idols)
    resolve()
  })
}

/**
 * DB에 확률업 아이돌 추가됐는지 확인
 */
function DBcheck() {
  const connection = mysql.createConnection(KEY.DB)
  connection.connect()

  const promises = state.idols.map(idol => new Promise((resolve, reject) => {
    connection.query(QUERY_TEST, idol, (err, result) => {
      if (err) reject(err)
      else if (!result.length) reject(err)
      else resolve(result)
    })
  }))

  Promise.all(promises)
  .then(() => state.valid = true)
  .catch(() => state.valid = false)
  .then(() => connection.end())
}

module.exports = function(border, keyboard) {
  start(() => {
    if (!state.valid || new Date() > state.endDate) {
      (AUTO ? detectNewIdols : setNewIdols)(keyboard).then(DBcheck)
    }
  }, INTERVAL.parse)
  start(border.getNowBorder, INTERVAL.now)
  start(border.getPredictBorder, INTERVAL.predict)
}
<|endoftext|>


<commit_before>(function () {

    var sax;

    if (typeof module !== 'undefined' && module.exports) {
      // We're being used in a Node-like environment
      sax = require('sax');
    }
    else {
      // assume it's attached to the Window object in a browser
      sax = this.sax;

      if (!sax) // no sax for you!
        throw new Error("Expected sax to be defined. Make sure you're including sax.js before this file.");
    }

    /*
    XmlElement is our basic building block. Everything is an XmlElement; even XmlDocument
    behaves like an XmlElement by inheriting its attributes and functions.
    */

    function XmlElement(tag) {
      // Capture the parser object off of the XmlDocument delegate
      var parser = sax.parser(false, {lowercase: true});

      this.name = tag.name;
      this.attr = tag.attributes || {};
      this.val = "";
      this.children = [];
      this.firstChild = null;
      this.lastChild = null;

      // Assign parse information
      this.line = parser.line;
      this.column = parser.column;
      this.position = parser.position;
      this.startTagPosition = parser.startTagPosition;
    }

    // SaxParser handlers

    XmlElement.prototype._opentag = function(tag) {

      var child = new XmlElement(tag);

      // add to our children array
      this.children.push(child);

      // update first/last pointers
      if (!this.firstChild) this.firstChild = child;
      this.lastChild = child;

      delegates.unshift(child);
    };

    XmlElement.prototype._closetag = function() {
      delegates.shift();
    };

    XmlElement.prototype._text = function(text) {
      if (text) this.val += text;
    };

    XmlElement.prototype._cdata = function(cdata) {
      if (cdata) this.val += cdata;
    };

    XmlElement.prototype._error = function(err) {
      throw err;
    };

    // Useful functions

    XmlElement.prototype.eachChild = function(iterator, context) {
      for (var i=0, l=this.children.length; i<l; i++)
        if (iterator.call(context, this.children[i], i, this.children) === false) return;
    };

    XmlElement.prototype.childNamed = function(name) {
      for (var i=0, l=this.children.length; i<l; i++) {
        var child = this.children[i];
        if (child.name === name) return child;
      }
      return undefined;
    };

    XmlElement.prototype.childrenNamed = function(name) {
      var matches = [];

      for (var i=0, l=this.children.length; i<l; i++)
        if (this.children[i].name === name)
          matches.push(this.children[i]);

      return matches;
    };

    XmlElement.prototype.childWithAttribute = function(name,value) {
      for (var i=0, l=this.children.length; i<l; i++) {
        var child = this.children[i];
        if ( (value && child.attr[name] === value) || (!value && child.attr[name]) )
          return child;
      }
      return undefined;
    };

    XmlElement.prototype.descendantWithPath = function(path) {
      var descendant = this;
      var components = path.split('.');

      for (var i=0, l=components.length; i<l; i++)
        if (descendant)
          descendant = descendant.childNamed(components[i]);
        else
          return undefined;

      return descendant;
    };

    XmlElement.prototype.valueWithPath = function(path) {
      var components = path.split('@');
      var descendant = this.descendantWithPath(components[0]);
      if (descendant)
        return components.length > 1 ? descendant.attr[components[1]] : descendant.val;
      else
        return undefined;
    };

    // String formatting (for debugging)

    XmlElement.prototype.toString = function(options) {
      return this.toStringWithIndent("", options);
    };

    XmlElement.prototype.toStringWithIndent = function(indent, options) {
      var s = indent + "<" + this.name;
      var linebreak = options && options.compressed ? "" : "\n";

      for (var name in this.attr)
        if (Object.prototype.hasOwnProperty.call(this.attr, name))
            s += " " + name + '="' + encodeURIComponent(this.attr[name]) + '"';

      var finalVal = this.val.trim().replace(/</g, "<").replace(/>/g, ">").replace(/&/g, '&');

      if (options && options.trimmed && finalVal.length > 25)
        finalVal = finalVal.substring(0,25).trim() + "…";

      if (this.children.length) {
        s += ">" + linebreak;

        var childIndent = indent + (options && options.compressed ? "" : "  ");

        if (finalVal.length)
          s += childIndent + finalVal + linebreak;

        for (var i=0, l=this.children.length; i<l; i++)
          s += this.children[i].toStringWithIndent(childIndent, options) + linebreak;

        s += indent + "</" + this.name + ">";
      }
      else if (finalVal.length) {
        s += ">" + finalVal + "</" + this.name +">";
      }
      else s += "/>";

      return s;
    };

    /*
    XmlDocument is the class we expose to the user; it uses the sax parser to create a hierarchy
    of XmlElements.
    */

    function XmlDocument(xml) {
      xml && (xml = xml.toString().trim());

      if (!xml)
        throw new Error("No XML to parse!");

      // Expose the parser to the other delegates while the parser is running
      this.parser = sax.parser(true); // strict
      addParserEvents(this.parser);

      // We'll use the file-scoped "delegates" var to remember what elements we're currently
      // parsing; they will push and pop off the stack as we get deeper into the XML hierarchy.
      // It's safe to use a global because JS is single-threaded.
      delegates = [this];

      this.parser.write(xml);

      // Remove the parser as it is no longer needed and should not be exposed to clients
      delete this.parser;
    }

    // make XmlDocument inherit XmlElement's methods
    extend(XmlDocument.prototype, XmlElement.prototype);

    XmlDocument.prototype._opentag = function(tag) {
      if (typeof this.children === 'undefined')
        // the first tag we encounter should be the root - we'll "become" the root XmlElement
        XmlElement.call(this,tag);
      else
        // all other tags will be the root element's children
        XmlElement.prototype._opentag.apply(this,arguments);
    };

    // file-scoped global stack of delegates
    var delegates = null;

    /*
    Helper functions
    */

    function addParserEvents(parser) {
      parser.onopentag = parser_opentag;
      parser.onclosetag = parser_closetag;
      parser.ontext = parser_text;
      parser.oncdata = parser_cdata;
      parser.onerror = parser_error;
    }

    // create these closures and cache them by keeping them file-scoped
    function parser_opentag() { delegates[0]._opentag.apply(delegates[0],arguments) }
    function parser_closetag() { delegates[0]._closetag.apply(delegates[0],arguments) }
    function parser_text() { delegates[0]._text.apply(delegates[0],arguments) }
    function parser_cdata() { delegates[0]._cdata.apply(delegates[0],arguments) }
    function parser_error() { delegates[0]._error.apply(delegates[0],arguments) }

    // a relatively standard extend method
    function extend(destination, source) {
      for (var prop in source)
        if (source.hasOwnProperty(prop))
          destination[prop] = source[prop];
    }

    // Are we being used in a Node-like environment?
    if (typeof module !== 'undefined' && module.exports) {
        module.exports.XmlDocument = XmlDocument;
        module.exports.XmlElement = XmlElement;
    } else {
        this.XmlDocument = XmlDocument;
        this.XmlElement = XmlElement;
    }
})();
<commit_msg>getting parser via different means than official repo<commit_after>(function () {

    var sax;

    if (typeof module !== 'undefined' && module.exports) {
      // We're being used in a Node-like environment
      sax = require('sax');
    }
    else {
      // assume it's attached to the Window object in a browser
      sax = this.sax;

      if (!sax) // no sax for you!
        throw new Error("Expected sax to be defined. Make sure you're including sax.js before this file.");
    }

    /*
    XmlElement is our basic building block. Everything is an XmlElement; even XmlDocument
    behaves like an XmlElement by inheriting its attributes and functions.
    */

    function XmlElement(tag) {
      // Capture the parser object off of the XmlDocument delegate
      var parser = sax.parser(false, {lowercase: true});

      this.name = tag.name;
      this.attr = tag.attributes || {};
      this.val = "";
      this.children = [];
      this.firstChild = null;
      this.lastChild = null;

      // Assign parse information
      this.line = parser.line;
      this.column = parser.column;
      this.position = parser.position;
      this.startTagPosition = parser.startTagPosition;
    }

    // SaxParser handlers

    XmlElement.prototype._opentag = function(tag) {

      var child = new XmlElement(tag);

      // add to our children array
      this.children.push(child);

      // update first/last pointers
      if (!this.firstChild) this.firstChild = child;
      this.lastChild = child;

      delegates.unshift(child);
    };

    XmlElement.prototype._closetag = function() {
      delegates.shift();
    };

    XmlElement.prototype._text = function(text) {
      if (text) this.val += text;
    };

    XmlElement.prototype._cdata = function(cdata) {
      if (cdata) this.val += cdata;
    };

    XmlElement.prototype._error = function(err) {
      throw err;
    };

    // Useful functions

    XmlElement.prototype.eachChild = function(iterator, context) {
      for (var i=0, l=this.children.length; i<l; i++)
        if (iterator.call(context, this.children[i], i, this.children) === false) return;
    };

    XmlElement.prototype.childNamed = function(name) {
      for (var i=0, l=this.children.length; i<l; i++) {
        var child = this.children[i];
        if (child.name === name) return child;
      }
      return undefined;
    };

    XmlElement.prototype.childrenNamed = function(name) {
      var matches = [];

      for (var i=0, l=this.children.length; i<l; i++)
        if (this.children[i].name === name)
          matches.push(this.children[i]);

      return matches;
    };

    XmlElement.prototype.childWithAttribute = function(name,value) {
      for (var i=0, l=this.children.length; i<l; i++) {
        var child = this.children[i];
        if ( (value && child.attr[name] === value) || (!value && child.attr[name]) )
          return child;
      }
      return undefined;
    };

    XmlElement.prototype.descendantWithPath = function(path) {
      var descendant = this;
      var components = path.split('.');

      for (var i=0, l=components.length; i<l; i++)
        if (descendant)
          descendant = descendant.childNamed(components[i]);
        else
          return undefined;

      return descendant;
    };

    XmlElement.prototype.valueWithPath = function(path) {
      var components = path.split('@');
      var descendant = this.descendantWithPath(components[0]);
      if (descendant)
        return components.length > 1 ? descendant.attr[components[1]] : descendant.val;
      else
        return undefined;
    };

    // String formatting (for debugging)

    XmlElement.prototype.toString = function(options) {
      return this.toStringWithIndent("", options);
    };

    XmlElement.prototype.toStringWithIndent = function(indent, options) {
      var s = indent + "<" + this.name;
      var linebreak = options && options.compressed ? "" : "\n";

      for (var name in this.attr)
        if (Object.prototype.hasOwnProperty.call(this.attr, name))
            s += " " + name + '="' + encodeURIComponent(this.attr[name]) + '"';

      var finalVal = this.val.trim().replace(/</g, "<").replace(/>/g, ">").replace(/&/g, '&');

      if (options && options.trimmed && finalVal.length > 25)
        finalVal = finalVal.substring(0,25).trim() + "…";

      if (this.children.length) {
        s += ">" + linebreak;

        var childIndent = indent + (options && options.compressed ? "" : "  ");

        if (finalVal.length)
          s += childIndent + finalVal + linebreak;

        for (var i=0, l=this.children.length; i<l; i++)
          s += this.children[i].toStringWithIndent(childIndent, options) + linebreak;

        s += indent + "</" + this.name + ">";
      }
      else if (finalVal.length) {
        s += ">" + finalVal + "</" + this.name +">";
      }
      else s += "/>";

      return s;
    };

    /*
    XmlDocument is the class we expose to the user; it uses the sax parser to create a hierarchy
    of XmlElements.
    */

    function XmlDocument(xml) {
      xml && (xml = xml.toString().trim());

      if (!xml)
        throw new Error("No XML to parse!");

      // Expose the parser to the other delegates while the parser is running
      this.parser = sax.parser(false, {lowercase: true}); // strict
      addParserEvents(this.parser);

      // We'll use the file-scoped "delegates" var to remember what elements we're currently
      // parsing; they will push and pop off the stack as we get deeper into the XML hierarchy.
      // It's safe to use a global because JS is single-threaded.
      delegates = [this];

      this.parser.write(xml);

      // Remove the parser as it is no longer needed and should not be exposed to clients
      delete this.parser;
    }

    // make XmlDocument inherit XmlElement's methods
    extend(XmlDocument.prototype, XmlElement.prototype);

    XmlDocument.prototype._opentag = function(tag) {
      if (typeof this.children === 'undefined')
        // the first tag we encounter should be the root - we'll "become" the root XmlElement
        XmlElement.call(this,tag);
      else
        // all other tags will be the root element's children
        XmlElement.prototype._opentag.apply(this,arguments);
    };

    // file-scoped global stack of delegates
    var delegates = null;

    /*
    Helper functions
    */

    function addParserEvents(parser) {
      parser.onopentag = parser_opentag;
      parser.onclosetag = parser_closetag;
      parser.ontext = parser_text;
      parser.oncdata = parser_cdata;
      parser.onerror = parser_error;
    }

    // create these closures and cache them by keeping them file-scoped
    function parser_opentag() { delegates[0]._opentag.apply(delegates[0],arguments) }
    function parser_closetag() { delegates[0]._closetag.apply(delegates[0],arguments) }
    function parser_text() { delegates[0]._text.apply(delegates[0],arguments) }
    function parser_cdata() { delegates[0]._cdata.apply(delegates[0],arguments) }
    function parser_error() { delegates[0]._error.apply(delegates[0],arguments) }

    // a relatively standard extend method
    function extend(destination, source) {
      for (var prop in source)
        if (source.hasOwnProperty(prop))
          destination[prop] = source[prop];
    }

    // Are we being used in a Node-like environment?
    if (typeof module !== 'undefined' && module.exports) {
        module.exports.XmlDocument = XmlDocument;
        module.exports.XmlElement = XmlElement;
    } else {
        this.XmlDocument = XmlDocument;
        this.XmlElement = XmlElement;
    }
})();
<|endoftext|>


<commit_before>var path = require('path');
var math = require(path.join(process.cwd(),'/lib/maths'));

var zeller = {

  convertMonth : function(m) {

    return (m === 1) ? 13 :
           (m === 2) ? 14 :
           m;

  },
  decodeDay : function(d) {

    return (d === 0) ? 7 : d;

  },
  decodeMonth : function(m) {

    return (m === 13 || m === 14) ? (m - 12) : m;

  },
  decodeYear : function(m,y) {

    return (m === 13 || m === 14) ? (y + 1) : y;

  },
  weekday : function(y,m,d) {

    m = this.convertMonth(m);
    var K = this.yearOfTheCentury(y),
        J = this.zeroBasedCentury(y);
    var encodedWeekday = math.mod((
      d
      + Math.floor( (13*(m+1)) / 5 )
      + K
      + Math.floor( K / 4 )
      + Math.floor( J / 4 )
      - 2*J
    ), 7);

    return this.decodeDay(encodedWeekday);

  },
  yearOfTheCentury : function(y) {

    return y % 100;

  },
  zeroBasedCentury : function(y) {

    return Math.floor(y / 100);

  },

};

module.exports = zeller;
<commit_msg>Fixing Zeller function, or at least changing it<commit_after>var path = require('path');
var math = require(path.join(process.cwd(),'/lib/maths'));

var zeller = {

  convertMonth : function(m) {

    return (m === 1) ? 13 :
           (m === 2) ? 14 :
           m;

  },
  decodeDay : function(d) {

    return (d === 0) ? 7 : d;

  },
  decodeMonth : function(m) {

    return (m === 13 || m === 14) ? (m - 12) : m;

  },
  decodeYear : function(m,y) {

    return (m === 13 || m === 14) ? (y + 1) : y;

  },
  weekday : function(y,m,d) {

    m = this.convertMonth(m);
    var K = this.yearOfTheCentury(y),
        J = this.zeroBasedCentury(y);
    var encodedWeekday = math.mod((
      d
      + Math.floor( (13*(m+1)) / 5 )
      + K
      + Math.floor( K / 4 )
      + Math.floor( J / 4 )
      + 5*J
    ), 7);

    return this.decodeDay(encodedWeekday);

  },
  yearOfTheCentury : function(y) {

    return y % 100;

  },
  zeroBasedCentury : function(y) {

    return Math.floor(y / 100);

  },

};

module.exports = zeller;
<|endoftext|>


<commit_before>var util = require('util');
var path = require('path');
var http = require('http');
var url = require('url');
var extend = require('extend');
var iconv = require('iconv-lite');
var isUtf8 = require('../util/is-utf8');
var ca = require('../https/ca');
var Storage = require('../rules/storage');
var getServer = require('hagent').create(null, 40500);

var QUERY_RE = /\?.*$/;
var REQ_ID_RE = /^\d{13,15}-\d{1,5}$/;
var reqOpts, REQ_ID_HEADER, pending;
var reqCallbacks = {};
var resCallbacks = {};
var MAX_LENGTH = 100;
var TIMEOUT = 600;
var timer;

var toBuffer = function(base64) {
  if (base64) {
    try {
      return new Buffer(base64, 'base64');
    } catch(e) {}
  }
};
var getBuffer = function(item) {
  return toBuffer(item && item.base64);
};
var getText = function(item) {
  var body = toBuffer(item && item.base64) || '';
  if (body && !isUtf8(body)) {
    try {
      body = iconv.encode(body, 'GB18030');
    } catch(e) {}
  }
  return body + '';
};

var execCallback = function(id, cbs, item) {
  var cb = cbs[id];
  if (cbs === reqCallbacks || (!item || item.endTime)) {
    cb(item);
    delete cbs[id];
  }
};

var retryRequest = function() {
  if (!timer) {
    timer = setTimeout(request, TIMEOUT);
  }
};

var request = function() {
  clearTimeout(timer);
  timer = null;
  if (pending) {
    return;
  }
  var reqList = Object.keys(reqCallbacks);
  var resList = Object.keys(resCallbacks);
  if (!reqList.length && !resList.length) {
    return;
  }
  pending = true;
  var execCb = function(err, result) {
    pending = false;
    if (err || !result) {
      return retryRequest();
    }
    Object.keys(result).forEach(function(id) {
      var item = result[id];
      execCallback(id, reqCallbacks, item);
      execCallback(id, resCallbacks, item);
      retryRequest();
    });
  };
  var _reqList = reqList.slice(0, MAX_LENGTH);
  var _resList = resList.slice(0, MAX_LENGTH);
  var query = '?reqList=' + JSON.stringify(_reqList) + '&resList=' + JSON.stringify(_resList);

  reqOpts.path = reqOpts.path.replace(QUERY_RE, query);
  http.get(reqOpts, function(res) {
    if (res.statusCode !== 200) {
      return execCb(true);
    }
    var body;
    res.on('data', function(data) {
      body = body ? Buffer.concat([body, data]) : data;
    });
    res.on('end', function() {
      if (body) {
        try {
          return execCb(null, JSON.parse(String(body)));
        } catch(e) {}
      }
      execCb(true);
    });
  }).on('error', execCb);
};

var getReqId = function(req, fn) {
  if (!req || typeof fn !== 'function' || !req.headers) {
    return;
  }
  var reqId = req.headers[REQ_ID_HEADER];
  return REQ_ID_RE.test(reqId) ? reqId : null;
};

var getResponseData = function(req, cb, isReq) {
  var reqId = getReqId(req, cb);
  if (!reqId) {
    return;
  }
  if (isReq) {
    reqCallbacks[reqId] = cb;
  } else {
    resCallbacks[reqId] = cb;
  }
  retryRequest();
};

var getRequestData = function(req, cb) {
  getResponseData(req, cb, true);
};

var loadModule = function(filepath) {
  try {
    return require(filepath);
  } catch (e) {}
};

module.exports = function(options, callback) {
  options.getRootCAFile = ca.getRootCAFile;
  options.createCertificate = ca.createCertificate;
  options.Storage = Storage;
  options.storage = new Storage(path.join(options.config.baseDir, '.plugins', options.name));
  var config = options.config;
  REQ_ID_HEADER = options.REQ_ID_HEADER;
  reqOpts = url.parse('http://127.0.0.1:' + config.uiport + '/cgi-bin/get-item?');
  reqOpts.headers = { 'x-whistle-auth-key': config.authKey };
  delete config.authKey;
  if (options.debugMode) {
    var cacheLogs = [];
    /*eslint no-console: "off"*/
    console.log = function() {
      var msg = util.format.apply(this, arguments);
      if (cacheLogs) {
        cacheLogs.push(msg);
      } else {
        process.sendData({
          type: 'console.log',
          message: msg
        });
      }
    };
    process.on('data', function(data) {
      if (cacheLogs && data && data.type == 'console.log' && data.status == 'ready') {
        var _cacheLogs = cacheLogs;
        cacheLogs = null;
        _cacheLogs.forEach(function(msg) {
          process.sendData({
            type: 'console.log',
            message: msg
          });
        });
      }
    });
  }

  var port, statsPort, resStatsPort, uiPort, rulesPort, resRulesPort, tunnelRulesPort, tunnelPort;
  var count = 0;
  var callbackHandler = function() {
    if (--count <= 0) {
      callback(null, {
        port: port,
        statsPort: statsPort,
        resStatsPort: resStatsPort,
        uiPort: uiPort,
        rulesPort: rulesPort,
        resRulesPort: resRulesPort,
        tunnelRulesPort: tunnelRulesPort,
        tunnelPort: tunnelPort
      });
    }
  };

  try {
    require.resolve(options.value);
  } catch(e) {
    return callbackHandler();
  }
  var initial = loadModule(path.join(options.value, 'initial.js'));
  if (typeof initial === 'function') {
    initial(options);
  }
  var execPlugin = require(options.value);
  var startServer = execPlugin.pluginServer || execPlugin.server || execPlugin;
  if (typeof startServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startServer(server, options);
      port = _port;
      callbackHandler();
    });
  }

  var startStatsServer = execPlugin.statsServer || execPlugin.reqStatsServer;
  if (typeof startStatsServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startStatsServer(server, extend({
        getRequestData: getRequestData,
        getResponseData: getResponseData,
        getBuffer: getBuffer,
        getText: getText
      }, options));
      statsPort = _port;
      callbackHandler();
    });
  }

  var startResStatsServer = execPlugin.resStatsServer;
  if (typeof startResStatsServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startResStatsServer(server, extend({
        getRequestData: getRequestData,
        getResponseData: getResponseData,
        getBuffer: getBuffer,
        getText: getText
      }, options));
      resStatsPort = _port;
      callbackHandler();
    });
  }

  var startUIServer = execPlugin.uiServer || execPlugin.innerServer || execPlugin.internalServer;
  if (typeof startUIServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startUIServer(server, options);
      uiPort = _port;
      callbackHandler();
    });
  }

  var startRulesServer = execPlugin.pluginRulesServer || execPlugin.rulesServer || execPlugin.reqRulesServer;
  if (typeof startRulesServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startRulesServer(server, options);
      rulesPort = _port;
      callbackHandler();
    });
  }

  var startResRulesServer = execPlugin.resRulesServer;
  if (typeof startResRulesServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startResRulesServer(server, extend({
        getRequestData: getRequestData,
        getBuffer: getBuffer,
        getText: getText
      }, options));
      resRulesPort = _port;
      callbackHandler();
    });
  }

  var startTunnelRulesServer = execPlugin.pluginRulesServer || execPlugin.tunnelRulesServer;
  if (typeof startTunnelRulesServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startTunnelRulesServer(server, options);
      tunnelRulesPort = _port;
      callbackHandler();
    });
  }

  var startTunnelServer = execPlugin.pluginServer || execPlugin.tunnelServer || execPlugin.connectServer;
  if (typeof startTunnelServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startTunnelServer(server, options);
      tunnelPort = _port;
      callbackHandler();
    });
  }

  if (!count) {
    callbackHandler();
  }
};

<commit_msg>feat: supports to get network data in plugin<commit_after>var util = require('util');
var path = require('path');
var http = require('http');
var url = require('url');
var extend = require('extend');
var iconv = require('iconv-lite');
var isUtf8 = require('../util/is-utf8');
var ca = require('../https/ca');
var Storage = require('../rules/storage');
var getServer = require('hagent').create(null, 40500);

var QUERY_RE = /\?.*$/;
var REQ_ID_RE = /^\d{13,15}-\d{1,5}$/;
var reqOpts, REQ_ID_HEADER, pending;
var reqCallbacks = {};
var resCallbacks = {};
var MAX_LENGTH = 100;
var TIMEOUT = 600;
var timer;

var toBuffer = function(base64) {
  if (base64) {
    try {
      return new Buffer(base64, 'base64');
    } catch(e) {}
  }
};
var getBuffer = function(item) {
  return toBuffer(item && item.base64);
};
var getText = function(item) {
  var body = toBuffer(item && item.base64) || '';
  if (body && !isUtf8(body)) {
    try {
      body = iconv.encode(body, 'GB18030');
    } catch(e) {}
  }
  return body + '';
};

var execCallback = function(id, cbs, item) {
  var cb = cbs[id];
  if (cbs === reqCallbacks || !item || item.endTime) {
    cb(item);
    delete cbs[id];
  }
};

var retryRequest = function() {
  if (!timer) {
    timer = setTimeout(request, TIMEOUT);
  }
};

var request = function() {
  clearTimeout(timer);
  timer = null;
  if (pending) {
    return;
  }
  var reqList = Object.keys(reqCallbacks);
  var resList = Object.keys(resCallbacks);
  if (!reqList.length && !resList.length) {
    return;
  }
  pending = true;
  var execCb = function(err, result) {
    pending = false;
    if (err || !result) {
      return retryRequest();
    }
    Object.keys(result).forEach(function(id) {
      var item = result[id];
      execCallback(id, reqCallbacks, item);
      execCallback(id, resCallbacks, item);
      retryRequest();
    });
  };
  var _reqList = reqList.slice(0, MAX_LENGTH);
  var _resList = resList.slice(0, MAX_LENGTH);
  var query = '?reqList=' + JSON.stringify(_reqList) + '&resList=' + JSON.stringify(_resList);

  reqOpts.path = reqOpts.path.replace(QUERY_RE, query);
  http.get(reqOpts, function(res) {
    if (res.statusCode !== 200) {
      return execCb(true);
    }
    var body;
    res.on('data', function(data) {
      body = body ? Buffer.concat([body, data]) : data;
    });
    res.on('end', function() {
      if (body) {
        try {
          return execCb(null, JSON.parse(String(body)));
        } catch(e) {}
      }
      execCb(true);
    });
  }).on('error', execCb);
};

var getReqId = function(req, fn) {
  if (!req || typeof fn !== 'function' || !req.headers) {
    return;
  }
  var reqId = req.headers[REQ_ID_HEADER];
  return REQ_ID_RE.test(reqId) ? reqId : null;
};

var getResponseData = function(req, cb, isReq) {
  var reqId = getReqId(req, cb);
  if (!reqId) {
    return;
  }
  if (isReq) {
    reqCallbacks[reqId] = cb;
  } else {
    resCallbacks[reqId] = cb;
  }
  retryRequest();
};

var getRequestData = function(req, cb) {
  getResponseData(req, cb, true);
};

var loadModule = function(filepath) {
  try {
    return require(filepath);
  } catch (e) {}
};

module.exports = function(options, callback) {
  options.getRootCAFile = ca.getRootCAFile;
  options.createCertificate = ca.createCertificate;
  options.Storage = Storage;
  options.storage = new Storage(path.join(options.config.baseDir, '.plugins', options.name));
  var config = options.config;
  REQ_ID_HEADER = options.REQ_ID_HEADER;
  reqOpts = url.parse('http://127.0.0.1:' + config.uiport + '/cgi-bin/get-item?');
  reqOpts.headers = { 'x-whistle-auth-key': config.authKey };
  delete config.authKey;
  if (options.debugMode) {
    var cacheLogs = [];
    /*eslint no-console: "off"*/
    console.log = function() {
      var msg = util.format.apply(this, arguments);
      if (cacheLogs) {
        cacheLogs.push(msg);
      } else {
        process.sendData({
          type: 'console.log',
          message: msg
        });
      }
    };
    process.on('data', function(data) {
      if (cacheLogs && data && data.type == 'console.log' && data.status == 'ready') {
        var _cacheLogs = cacheLogs;
        cacheLogs = null;
        _cacheLogs.forEach(function(msg) {
          process.sendData({
            type: 'console.log',
            message: msg
          });
        });
      }
    });
  }

  var port, statsPort, resStatsPort, uiPort, rulesPort, resRulesPort, tunnelRulesPort, tunnelPort;
  var count = 0;
  var callbackHandler = function() {
    if (--count <= 0) {
      callback(null, {
        port: port,
        statsPort: statsPort,
        resStatsPort: resStatsPort,
        uiPort: uiPort,
        rulesPort: rulesPort,
        resRulesPort: resRulesPort,
        tunnelRulesPort: tunnelRulesPort,
        tunnelPort: tunnelPort
      });
    }
  };

  try {
    require.resolve(options.value);
  } catch(e) {
    return callbackHandler();
  }
  var initial = loadModule(path.join(options.value, 'initial.js'));
  if (typeof initial === 'function') {
    initial(options);
  }
  var execPlugin = require(options.value);
  var startServer = execPlugin.pluginServer || execPlugin.server || execPlugin;
  if (typeof startServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startServer(server, options);
      port = _port;
      callbackHandler();
    });
  }

  var startStatsServer = execPlugin.statsServer || execPlugin.reqStatsServer;
  if (typeof startStatsServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startStatsServer(server, extend({
        getRequestData: getRequestData,
        getResponseData: getResponseData,
        getBuffer: getBuffer,
        getText: getText
      }, options));
      statsPort = _port;
      callbackHandler();
    });
  }

  var startResStatsServer = execPlugin.resStatsServer;
  if (typeof startResStatsServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startResStatsServer(server, extend({
        getRequestData: getRequestData,
        getResponseData: getResponseData,
        getBuffer: getBuffer,
        getText: getText
      }, options));
      resStatsPort = _port;
      callbackHandler();
    });
  }

  var startUIServer = execPlugin.uiServer || execPlugin.innerServer || execPlugin.internalServer;
  if (typeof startUIServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startUIServer(server, options);
      uiPort = _port;
      callbackHandler();
    });
  }

  var startRulesServer = execPlugin.pluginRulesServer || execPlugin.rulesServer || execPlugin.reqRulesServer;
  if (typeof startRulesServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startRulesServer(server, options);
      rulesPort = _port;
      callbackHandler();
    });
  }

  var startResRulesServer = execPlugin.resRulesServer;
  if (typeof startResRulesServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startResRulesServer(server, extend({
        getRequestData: getRequestData,
        getBuffer: getBuffer,
        getText: getText
      }, options));
      resRulesPort = _port;
      callbackHandler();
    });
  }

  var startTunnelRulesServer = execPlugin.pluginRulesServer || execPlugin.tunnelRulesServer;
  if (typeof startTunnelRulesServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startTunnelRulesServer(server, options);
      tunnelRulesPort = _port;
      callbackHandler();
    });
  }

  var startTunnelServer = execPlugin.pluginServer || execPlugin.tunnelServer || execPlugin.connectServer;
  if (typeof startTunnelServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startTunnelServer(server, options);
      tunnelPort = _port;
      callbackHandler();
    });
  }

  if (!count) {
    callbackHandler();
  }
};

<|endoftext|>


<commit_before>var util = require('util');
var path = require('path');
var http = require('http');
var url = require('url');
var extend = require('extend');
var iconv = require('iconv-lite');
var isUtf8 = require('../util/is-utf8');
var ca = require('../https/ca');
var Storage = require('../rules/storage');
var getServer = require('hagent').create(null, 40500);

var QUERY_RE = /\?.*$/;
var REQ_ID_RE = /^\d{13,15}-\d{1,5}$/;
var reqOpts, REQ_ID_HEADER, pending;
var reqCallbacks = {};
var resCallbacks = {};
var MAX_LENGTH = 100;
var TIMEOUT = 300;
var timer;

var toBuffer = function(base64) {
  if (base64) {
    try {
      return new Buffer(base64, 'base64');
    } catch(e) {}
  }
};
var getBuffer = function(item) {
  return toBuffer(item && item.base64);
};
var getText = function(item) {
  var body = toBuffer(item && item.base64) || '';
  if (body && !isUtf8(body)) {
    try {
      body = iconv.encode(body, 'GB18030');
    } catch(e) {}
  }
  return body + '';
};

var execCallback = function(id, cbs, item) {
  var cb = cbs[id];
  if (cb && (cbs === reqCallbacks || !item || item.endTime)) {
    cb(item);
    delete cbs[id];
  }
};

var retryRequest = function(time) {
  if (!timer) {
    timer = setTimeout(request, time || TIMEOUT);
  }
};

var request = function() {
  clearTimeout(timer);
  timer = null;
  if (pending) {
    return;
  }
  var reqList = Object.keys(reqCallbacks);
  var resList = Object.keys(resCallbacks);
  if (!reqList.length && !resList.length) {
    return;
  }
  pending = true;
  var execCb = function(err, result) {
    pending = false;
    if (err || !result) {
      return retryRequest();
    }
    Object.keys(result).forEach(function(id) {
      var item = result[id];
      execCallback(id, reqCallbacks, item);
      execCallback(id, resCallbacks, item);
    });
    retryRequest(30);
  };
  var _reqList = reqList.slice(0, MAX_LENGTH);
  var _resList = resList.slice(0, MAX_LENGTH);
  var query = '?reqList=' + JSON.stringify(_reqList) + '&resList=' + JSON.stringify(_resList);

  reqOpts.path = reqOpts.path.replace(QUERY_RE, query);
  var client = http.get(reqOpts, function(res) {
    if (res.statusCode !== 200) {
      return execCb(true);
    }
    var body;
    res.on('data', function(data) {
      body = body ? Buffer.concat([body, data]) : data;
    });
    res.on('end', function() {
      if (body) {
        try {
          return execCb(null, JSON.parse(String(body)));
        } catch(e) {}
      }
      execCb(true);
    });
  });
  client.on('error', execCb);
  client.setTimeout(6000, function() {
    client.abort();
  });
};

var getReqId = function(req, fn) {
  if (!req || typeof fn !== 'function' || !req.headers) {
    return;
  }
  var reqId = req.headers[REQ_ID_HEADER];
  return REQ_ID_RE.test(reqId) ? reqId : null;
};

var getResponseData = function(req, cb, isReq) {
  var reqId = getReqId(req, cb);
  if (!reqId) {
    return;
  }
  if (isReq) {
    reqCallbacks[reqId] = cb;
  } else {
    resCallbacks[reqId] = cb;
  }
  retryRequest(30);
};

var getRequestData = function(req, cb) {
  getResponseData(req, cb, true);
};

var loadModule = function(filepath) {
  try {
    return require(filepath);
  } catch (e) {}
};

module.exports = function(options, callback) {
  options.getRootCAFile = ca.getRootCAFile;
  options.createCertificate = ca.createCertificate;
  options.Storage = Storage;
  options.storage = new Storage(path.join(options.config.baseDir, '.plugins', options.name));
  var config = options.config;
  REQ_ID_HEADER = options.REQ_ID_HEADER;
  reqOpts = url.parse('http://127.0.0.1:' + config.uiport + '/cgi-bin/get-item?');
  reqOpts.headers = { 'x-whistle-auth-key': config.authKey };
  delete config.authKey;
  if (options.debugMode) {
    var cacheLogs = [];
    /*eslint no-console: "off"*/
    console.log = function() {
      var msg = util.format.apply(this, arguments);
      if (cacheLogs) {
        cacheLogs.push(msg);
      } else {
        process.sendData({
          type: 'console.log',
          message: msg
        });
      }
    };
    process.on('data', function(data) {
      if (cacheLogs && data && data.type == 'console.log' && data.status == 'ready') {
        var _cacheLogs = cacheLogs;
        cacheLogs = null;
        _cacheLogs.forEach(function(msg) {
          process.sendData({
            type: 'console.log',
            message: msg
          });
        });
      }
    });
  }

  var port, statsPort, resStatsPort, uiPort, rulesPort, resRulesPort, tunnelRulesPort, tunnelPort;
  var count = 0;
  var callbackHandler = function() {
    if (--count <= 0) {
      callback(null, {
        port: port,
        statsPort: statsPort,
        resStatsPort: resStatsPort,
        uiPort: uiPort,
        rulesPort: rulesPort,
        resRulesPort: resRulesPort,
        tunnelRulesPort: tunnelRulesPort,
        tunnelPort: tunnelPort
      });
    }
  };

  try {
    require.resolve(options.value);
  } catch(e) {
    return callbackHandler();
  }
  var initial = loadModule(path.join(options.value, 'initial.js'));
  if (typeof initial === 'function') {
    initial(options);
  }
  var execPlugin = require(options.value);
  var startServer = execPlugin.pluginServer || execPlugin.server || execPlugin;
  if (typeof startServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startServer(server, options);
      port = _port;
      callbackHandler();
    });
  }

  var startStatsServer = execPlugin.statsServer || execPlugin.reqStatsServer;
  if (typeof startStatsServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startStatsServer(server, extend({
        getRequestData: getRequestData,
        getResponseData: getResponseData,
        getBuffer: getBuffer,
        getText: getText
      }, options));
      statsPort = _port;
      callbackHandler();
    });
  }

  var startResStatsServer = execPlugin.resStatsServer;
  if (typeof startResStatsServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startResStatsServer(server, extend({
        getRequestData: getRequestData,
        getResponseData: getResponseData,
        getBuffer: getBuffer,
        getText: getText
      }, options));
      resStatsPort = _port;
      callbackHandler();
    });
  }

  var startUIServer = execPlugin.uiServer || execPlugin.innerServer || execPlugin.internalServer;
  if (typeof startUIServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startUIServer(server, options);
      uiPort = _port;
      callbackHandler();
    });
  }

  var startRulesServer = execPlugin.pluginRulesServer || execPlugin.rulesServer || execPlugin.reqRulesServer;
  if (typeof startRulesServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startRulesServer(server, options);
      rulesPort = _port;
      callbackHandler();
    });
  }

  var startResRulesServer = execPlugin.resRulesServer;
  if (typeof startResRulesServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startResRulesServer(server, extend({
        getRequestData: getRequestData,
        getBuffer: getBuffer,
        getText: getText
      }, options));
      resRulesPort = _port;
      callbackHandler();
    });
  }

  var startTunnelRulesServer = execPlugin.pluginRulesServer || execPlugin.tunnelRulesServer;
  if (typeof startTunnelRulesServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startTunnelRulesServer(server, options);
      tunnelRulesPort = _port;
      callbackHandler();
    });
  }

  var startTunnelServer = execPlugin.pluginServer || execPlugin.tunnelServer || execPlugin.connectServer;
  if (typeof startTunnelServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startTunnelServer(server, options);
      tunnelPort = _port;
      callbackHandler();
    });
  }

  if (!count) {
    callbackHandler();
  }
};

<commit_msg>feat: auto free connection of statsServer<commit_after>var util = require('util');
var path = require('path');
var http = require('http');
var url = require('url');
var extend = require('extend');
var iconv = require('iconv-lite');
var isUtf8 = require('../util/is-utf8');
var ca = require('../https/ca');
var Storage = require('../rules/storage');
var getServer = require('hagent').create(null, 40500);

var QUERY_RE = /\?.*$/;
var REQ_ID_RE = /^\d{13,15}-\d{1,5}$/;
var reqOpts, REQ_ID_HEADER, pending;
var reqCallbacks = {};
var resCallbacks = {};
var MAX_LENGTH = 100;
var TIMEOUT = 300;
var timer;

var endRes = function(req, res) {
  res.end();
};
var toBuffer = function(base64) {
  if (base64) {
    try {
      return new Buffer(base64, 'base64');
    } catch(e) {}
  }
};
var getBuffer = function(item) {
  return toBuffer(item && item.base64);
};
var getText = function(item) {
  var body = toBuffer(item && item.base64) || '';
  if (body && !isUtf8(body)) {
    try {
      body = iconv.encode(body, 'GB18030');
    } catch(e) {}
  }
  return body + '';
};

var execCallback = function(id, cbs, item) {
  var cb = cbs[id];
  if (cb && (cbs === reqCallbacks || !item || item.endTime)) {
    cb(item);
    delete cbs[id];
  }
};

var retryRequest = function(time) {
  if (!timer) {
    timer = setTimeout(request, time || TIMEOUT);
  }
};

var request = function() {
  clearTimeout(timer);
  timer = null;
  if (pending) {
    return;
  }
  var reqList = Object.keys(reqCallbacks);
  var resList = Object.keys(resCallbacks);
  if (!reqList.length && !resList.length) {
    return;
  }
  pending = true;
  var execCb = function(err, result) {
    pending = false;
    if (err || !result) {
      return retryRequest();
    }
    Object.keys(result).forEach(function(id) {
      var item = result[id];
      execCallback(id, reqCallbacks, item);
      execCallback(id, resCallbacks, item);
    });
    retryRequest(30);
  };
  var _reqList = reqList.slice(0, MAX_LENGTH);
  var _resList = resList.slice(0, MAX_LENGTH);
  var query = '?reqList=' + JSON.stringify(_reqList) + '&resList=' + JSON.stringify(_resList);

  reqOpts.path = reqOpts.path.replace(QUERY_RE, query);
  var client = http.get(reqOpts, function(res) {
    if (res.statusCode !== 200) {
      return execCb(true);
    }
    var body;
    res.on('data', function(data) {
      body = body ? Buffer.concat([body, data]) : data;
    });
    res.on('end', function() {
      if (body) {
        try {
          return execCb(null, JSON.parse(String(body)));
        } catch(e) {}
      }
      execCb(true);
    });
  });
  client.on('error', execCb);
  client.setTimeout(6000, function() {
    client.abort();
  });
};

var getReqId = function(req, fn) {
  if (!req || typeof fn !== 'function' || !req.headers) {
    return;
  }
  var reqId = req.headers[REQ_ID_HEADER];
  return REQ_ID_RE.test(reqId) ? reqId : null;
};

var getResponseData = function(req, cb, isReq) {
  var reqId = getReqId(req, cb);
  if (!reqId) {
    return;
  }
  if (isReq) {
    reqCallbacks[reqId] = cb;
  } else {
    resCallbacks[reqId] = cb;
  }
  retryRequest(30);
};

var getRequestData = function(req, cb) {
  getResponseData(req, cb, true);
};

var loadModule = function(filepath) {
  try {
    return require(filepath);
  } catch (e) {}
};

module.exports = function(options, callback) {
  options.getRootCAFile = ca.getRootCAFile;
  options.createCertificate = ca.createCertificate;
  options.Storage = Storage;
  options.storage = new Storage(path.join(options.config.baseDir, '.plugins', options.name));
  var config = options.config;
  REQ_ID_HEADER = options.REQ_ID_HEADER;
  reqOpts = url.parse('http://127.0.0.1:' + config.uiport + '/cgi-bin/get-item?');
  reqOpts.headers = { 'x-whistle-auth-key': config.authKey };
  delete config.authKey;
  if (options.debugMode) {
    var cacheLogs = [];
    /*eslint no-console: "off"*/
    console.log = function() {
      var msg = util.format.apply(this, arguments);
      if (cacheLogs) {
        cacheLogs.push(msg);
      } else {
        process.sendData({
          type: 'console.log',
          message: msg
        });
      }
    };
    process.on('data', function(data) {
      if (cacheLogs && data && data.type == 'console.log' && data.status == 'ready') {
        var _cacheLogs = cacheLogs;
        cacheLogs = null;
        _cacheLogs.forEach(function(msg) {
          process.sendData({
            type: 'console.log',
            message: msg
          });
        });
      }
    });
  }

  var port, statsPort, resStatsPort, uiPort, rulesPort, resRulesPort, tunnelRulesPort, tunnelPort;
  var count = 0;
  var callbackHandler = function() {
    if (--count <= 0) {
      callback(null, {
        port: port,
        statsPort: statsPort,
        resStatsPort: resStatsPort,
        uiPort: uiPort,
        rulesPort: rulesPort,
        resRulesPort: resRulesPort,
        tunnelRulesPort: tunnelRulesPort,
        tunnelPort: tunnelPort
      });
    }
  };

  try {
    require.resolve(options.value);
  } catch(e) {
    return callbackHandler();
  }
  var initial = loadModule(path.join(options.value, 'initial.js'));
  if (typeof initial === 'function') {
    initial(options);
  }
  var execPlugin = require(options.value);
  var startServer = execPlugin.pluginServer || execPlugin.server || execPlugin;
  if (typeof startServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startServer(server, options);
      port = _port;
      callbackHandler();
    });
  }

  var startStatsServer = execPlugin.statsServer || execPlugin.reqStatsServer;
  if (typeof startStatsServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      server.on('request', endRes);
      startStatsServer(server, extend({
        getRequestData: getRequestData,
        getResponseData: getResponseData,
        getBuffer: getBuffer,
        getText: getText
      }, options));
      statsPort = _port;
      callbackHandler();
    });
  }

  var startResStatsServer = execPlugin.resStatsServer;
  if (typeof startResStatsServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      server.on('request', endRes);
      startResStatsServer(server, extend({
        getRequestData: getRequestData,
        getResponseData: getResponseData,
        getBuffer: getBuffer,
        getText: getText
      }, options));
      resStatsPort = _port;
      callbackHandler();
    });
  }

  var startUIServer = execPlugin.uiServer || execPlugin.innerServer || execPlugin.internalServer;
  if (typeof startUIServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startUIServer(server, options);
      uiPort = _port;
      callbackHandler();
    });
  }

  var startRulesServer = execPlugin.pluginRulesServer || execPlugin.rulesServer || execPlugin.reqRulesServer;
  if (typeof startRulesServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startRulesServer(server, options);
      rulesPort = _port;
      callbackHandler();
    });
  }

  var startResRulesServer = execPlugin.resRulesServer;
  if (typeof startResRulesServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startResRulesServer(server, extend({
        getRequestData: getRequestData,
        getBuffer: getBuffer,
        getText: getText
      }, options));
      resRulesPort = _port;
      callbackHandler();
    });
  }

  var startTunnelRulesServer = execPlugin.pluginRulesServer || execPlugin.tunnelRulesServer;
  if (typeof startTunnelRulesServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startTunnelRulesServer(server, options);
      tunnelRulesPort = _port;
      callbackHandler();
    });
  }

  var startTunnelServer = execPlugin.pluginServer || execPlugin.tunnelServer || execPlugin.connectServer;
  if (typeof startTunnelServer == 'function') {
    ++count;
    getServer(function(server, _port) {
      startTunnelServer(server, options);
      tunnelPort = _port;
      callbackHandler();
    });
  }

  if (!count) {
    callbackHandler();
  }
};

<|endoftext|>


<commit_before>const ccxt = require('ccxt')

const BN = require('../../bn')
const { buildMarket, verifyFiatSupport } = require('../common/ccxt')
const { getRate } = require('../../../lib/forex')

const RETRIES = 2

function ticker (fiatCode, cryptoCode, tickerName) {
  const ticker = new ccxt[tickerName]({ timeout: 3000 })
  if (verifyFiatSupport(fiatCode, tickerName)) {
    return getCurrencyRates(ticker, fiatCode, cryptoCode)
  }

  return getRate(RETRIES, fiatCode)
    .then(({ fxRate }) => {
      try {
        return getCurrencyRates(ticker, 'USD', cryptoCode)
          .then(res => ({
            rates: {
              ask: res.rates.ask.times(fxRate),
              bid: res.rates.bid.times(fxRate)
            }
          }))
      } catch (e) {
        return Promise.reject(e)
      }
    })
}

function getCurrencyRates (ticker, fiatCode, cryptoCode) {
  try {
    if (!ticker.has['fetchTicker']) {
      throw new Error('Ticker not available')
    }
    const symbol = buildMarket(fiatCode, cryptoCode, ticker.id)
    return ticker.fetchTicker(symbol)
      .then(res => ({
        rates: {
          ask: new BN(res.ask),
          bid: new BN(res.bid)
        }
      }))
  } catch (e) {
    return Promise.reject(e)
  }
}

module.exports = { ticker }
<commit_msg>refactor: save CCXT ticker instance<commit_after>const ccxt = require('ccxt')

const BN = require('../../bn')
const { buildMarket, verifyFiatSupport } = require('../common/ccxt')
const { getRate } = require('../../../lib/forex')

const RETRIES = 2

const tickerObjects = {}

function ticker (fiatCode, cryptoCode, tickerName) {
  const ticker = tickerObjects[tickerName] ?
    tickerObjects[tickerName] :
    tickerObjects[tickerName] = new ccxt[tickerName]({ timeout: 3000 })

  if (verifyFiatSupport(fiatCode, tickerName)) {
    return getCurrencyRates(ticker, fiatCode, cryptoCode)
  }

  return getRate(RETRIES, fiatCode)
    .then(({ fxRate }) => {
      try {
        return getCurrencyRates(ticker, 'USD', cryptoCode)
          .then(res => ({
            rates: {
              ask: res.rates.ask.times(fxRate),
              bid: res.rates.bid.times(fxRate)
            }
          }))
      } catch (e) {
        return Promise.reject(e)
      }
    })
}

function getCurrencyRates (ticker, fiatCode, cryptoCode) {
  try {
    if (!ticker.has['fetchTicker']) {
      throw new Error('Ticker not available')
    }
    const symbol = buildMarket(fiatCode, cryptoCode, ticker.id)
    return ticker.fetchTicker(symbol)
      .then(res => ({
        rates: {
          ask: new BN(res.ask),
          bid: new BN(res.bid)
        }
      }))
  } catch (e) {
    return Promise.reject(e)
  }
}

module.exports = { ticker }
<|endoftext|>


<commit_before>var requests = require('./request-wrapper'),
    util = require('./util'),
    _ = require('lodash'),
    httpReasons = require('http-reasons'),

    /**
     * Creates a Chrome-compatible cookie from a tough-cookie compatible cookie.
     *
     * @param cookie
     * @returns {Object}
     */
    toChromeCookie = function (cookie) {
        cookie.toJSON && (cookie = cookie.toJSON());

        return {
            domain: cookie.domain,
            hostOnly: cookie.hostOnly,
            httpOnly: cookie.httpOnly,
            name: cookie.key,
            path: cookie.path,
            secure: cookie.secure,
            storeId: 'PostmanCookieStore',
            value: cookie.value
        }
    },

    /**
     * Creates a new Requester, which is used to make HTTP(s) requests.
     *
     * @param options
     * @param {Boolean} [options.keepAlive=true] Optimizes HTTP connections by keeping them alive, so that new requests
     * to the same host are made over the same underlying TCP connection.
     * @param {CookieJar} [options.cookieJar] A cookie jar to use with Node requests.
     * @param {CertificateManager} [options.certificateManager] Something to get certificates from
     * @param {FileResolver} {options.fileResolver} *Deprecated* An object that provides a function called
     * `createReadStream` which is called when uploading files.
     * @param {Boolean} [options.strictSSL]
     * @param {Boolean} [options.followRedirects=true] If false, returns a 301/302 as the response code instead of following the redirect
     * @note `options.keepAlive` is only supported in Node.
     * @note `options.cookieJar` is only supported in Node.
     * @constructor
     */
    Requester = function (options) {
        this.keepAlive = _.get(options, 'keepAlive') === undefined ? true : options.keepAlive;
        this.cookieJar = _.get(options, 'cookieJar');
        this.timeout = _.has(options, 'timeout') ? options.timeout : undefined;
        this.fileResolver = _.get(options, 'fileResolver');
        this.strictSSL = _.get(options, 'strictSSL');
        this.certificateManager = _.get(options, 'certificateManager');
        this.proxyManager = _.get(options, 'proxyManager');
        this.followRedirects = _.has(options, 'followRedirects') ? options.followRedirects : true;
    };

/**
 * Perform an HTTP request.
 *
 * @param item
 * @param cb
 * @param scope
 */
Requester.prototype.request = function (item, cb, scope) {
    var request = item.request,
        cookieJar = this.cookieJar,
        requestOptions = util.getRequestOptions(request, {
            keepAlive: this.keepAlive,
            cookieJar: cookieJar,
            timeout: this.timeout,
            strictSSL: this.strictSSL,
            followRedirects: this.followRedirects,
        }),
        startTime = Date.now();

    requestOptions.request = request;
    requestOptions.certificateManager = this.certificateManager;
    requestOptions.proxyManager = this.proxyManager;

    return requests(requestOptions, function (err, res, resBody) {
        if (err) {
            return cb.call(scope || this, err);
        }

        var responseString = (resBody != null && resBody.toString) ? resBody.toString() : resBody;
        if (responseString === '[object ArrayBuffer]') {
            responseString = util.arrayBufferToString(resBody);
        }

        var responseTime = Date.now() - startTime,
            responseJSON = util.jsonifyResponse(res, requestOptions, responseString),
            legacyRequest = _.extend(responseJSON.request, {
                id: item.id,
                name: item.name,
                description: item.request.description ? item.request.description.toString() : undefined
            }),
            cookies = (cookieJar && _.isFunction(cookieJar.getCookies)) ?
                _.transform(cookieJar.getCookies(requestOptions.url), function (acc, cookie) {
                    acc.push(toChromeCookie(cookie));
                }, []) : [],
            codeReason = httpReasons.lookup(responseJSON.statusCode), // returns blank object if not found
            legacyResponse = {
                responseBody: responseString,
                responseHeaders: responseJSON.headers,
                responseTime: responseTime,
                responseCode: {
                    code: responseJSON.statusCode,
                    name: codeReason.name || '',
                    detail: codeReason.detail || ''
                },
                responseCookies: cookies
            },
            response = { // @todo get rid of jsonifyResponse
                code: legacyResponse.responseCode.code,
                header: legacyResponse.responseHeaders,
                body: responseString,
                stream: resBody,
                cookie: undefined, // @todo get from cookieJar and implement loading/unloading in SDK
                responseTime: responseTime
            };

        // Insert the missing sent headers in the request object, so that they get bubbled up into the UI
        _.forOwn(legacyRequest.headers, function (value, key) {
            // todo: this should also be done in the request utils, so that it's appropriately updated there,
            // and there's a clear separation between what we added vs what Node added.
            if (!request.headers.one(key)) {
                request.addHeader({ key: key, value: value });
            }
        });

        cb.call(scope || this, null, legacyResponse, legacyRequest, response, request);
    });
};

module.exports.Requester = Requester;
<commit_msg>ensure that correct sent headers are bubbled up from the request<commit_after>var requests = require('./request-wrapper'),
    util = require('./util'),
    _ = require('lodash'),
    httpReasons = require('http-reasons'),

    /**
     * Creates a Chrome-compatible cookie from a tough-cookie compatible cookie.
     *
     * @param cookie
     * @returns {Object}
     */
    toChromeCookie = function (cookie) {
        cookie.toJSON && (cookie = cookie.toJSON());

        return {
            domain: cookie.domain,
            hostOnly: cookie.hostOnly,
            httpOnly: cookie.httpOnly,
            name: cookie.key,
            path: cookie.path,
            secure: cookie.secure,
            storeId: 'PostmanCookieStore',
            value: cookie.value
        }
    },

    /**
     * Creates a new Requester, which is used to make HTTP(s) requests.
     *
     * @param options
     * @param {Boolean} [options.keepAlive=true] Optimizes HTTP connections by keeping them alive, so that new requests
     * to the same host are made over the same underlying TCP connection.
     * @param {CookieJar} [options.cookieJar] A cookie jar to use with Node requests.
     * @param {CertificateManager} [options.certificateManager] Something to get certificates from
     * @param {FileResolver} {options.fileResolver} *Deprecated* An object that provides a function called
     * `createReadStream` which is called when uploading files.
     * @param {Boolean} [options.strictSSL]
     * @param {Boolean} [options.followRedirects=true] If false, returns a 301/302 as the response code instead of following the redirect
     * @note `options.keepAlive` is only supported in Node.
     * @note `options.cookieJar` is only supported in Node.
     * @constructor
     */
    Requester = function (options) {
        this.keepAlive = _.get(options, 'keepAlive') === undefined ? true : options.keepAlive;
        this.cookieJar = _.get(options, 'cookieJar');
        this.timeout = _.has(options, 'timeout') ? options.timeout : undefined;
        this.fileResolver = _.get(options, 'fileResolver');
        this.strictSSL = _.get(options, 'strictSSL');
        this.certificateManager = _.get(options, 'certificateManager');
        this.proxyManager = _.get(options, 'proxyManager');
        this.followRedirects = _.has(options, 'followRedirects') ? options.followRedirects : true;
    };

/**
 * Perform an HTTP request.
 *
 * @param item
 * @param cb
 * @param scope
 */
Requester.prototype.request = function (item, cb, scope) {
    var request = item.request,
        cookieJar = this.cookieJar,
        requestOptions = util.getRequestOptions(request, {
            keepAlive: this.keepAlive,
            cookieJar: cookieJar,
            timeout: this.timeout,
            strictSSL: this.strictSSL,
            followRedirects: this.followRedirects,
        }),
        startTime = Date.now();

    requestOptions.request = request;
    requestOptions.certificateManager = this.certificateManager;
    requestOptions.proxyManager = this.proxyManager;

    return requests(requestOptions, function (err, res, resBody) {
        if (err) {
            return cb.call(scope || this, err);
        }

        var responseString = (resBody != null && resBody.toString) ? resBody.toString() : resBody;
        if (responseString === '[object ArrayBuffer]') {
            responseString = util.arrayBufferToString(resBody);
        }

        var responseTime = Date.now() - startTime,
            responseJSON = util.jsonifyResponse(res, requestOptions, responseString),
            legacyRequest = _.extend(responseJSON.request, {
                id: item.id,
                name: item.name,
                description: item.request.description ? item.request.description.toString() : undefined
            }),
            cookies = (cookieJar && _.isFunction(cookieJar.getCookies)) ?
                _.transform(cookieJar.getCookies(requestOptions.url), function (acc, cookie) {
                    acc.push(toChromeCookie(cookie));
                }, []) : [],
            codeReason = httpReasons.lookup(responseJSON.statusCode), // returns blank object if not found
            legacyResponse = {
                responseBody: responseString,
                responseHeaders: responseJSON.headers,
                responseTime: responseTime,
                responseCode: {
                    code: responseJSON.statusCode,
                    name: codeReason.name || '',
                    detail: codeReason.detail || ''
                },
                responseCookies: cookies
            },
            response = { // @todo get rid of jsonifyResponse
                code: legacyResponse.responseCode.code,
                header: legacyResponse.responseHeaders,
                body: responseString,
                stream: resBody,
                cookie: undefined, // @todo get from cookieJar and implement loading/unloading in SDK
                responseTime: responseTime
            };

        // Insert the missing sent headers in the request object, so that they get bubbled up into the UI
        _.forOwn(legacyRequest.headers, function (value, key) {
            // todo: this should also be done in the request utils, so that it's appropriately updated there,
            // and there's a clear separation between what we added vs what Node added.
            request.upsertHeader({ key: key, value: value });
        });

        cb.call(scope || this, null, legacyResponse, legacyRequest, response, request);
    });
};

module.exports.Requester = Requester;
<|endoftext|>