<commit_before>/**
 * Wechaty - Wechaty for Bot, Connect ChatBots, Chat as a Service
 *
 * https://github.com/wechaty/wechaty/
 */
import { execSync } from 'child_process'
import * as fs from 'fs'

import { Puppet } from './puppet'
import { log }    from './brolog-env'

export type PuppetName = 'web' | 'android' | 'ios'
export type HeadName = 'chrome' | 'phantomjs' | 'firefox'

export interface ConfigSetting {

  DEFAULT_HEAD: HeadName
  DEFAULT_PUPPET: PuppetName
  DEFAULT_APIHOST: string
  DEFAULT_PROFILE: string
  DEFAULT_TOKEN:  string
  DEFAULT_PROTOCOL: string
  CMD_CHROMIUM: string
  DEFAULT_PORT: number

  port: number
  profile: string
  token: string
  debug: boolean

  puppet: PuppetName
  head: HeadName

  apihost: string
  validApiHost: (host: string) => boolean

  httpPort: number

  _puppetInstance: Puppet | null
  puppetInstance(): Puppet
  puppetInstance(empty: null): void
  puppetInstance(instance: Puppet): void
  puppetInstance(instance?: Puppet | null): Puppet | void

  isDocker: boolean

}
/* tslint:disable:variable-name */
/* tslint:disable:no-var-requires */
export const Config: ConfigSetting = require('../package.json').wechaty

/**
 * 1. ENVIRONMENT VARIABLES + PACKAGES.JSON (default)
 */
Object.assign(Config, {
  head:       process.env['WECHATY_HEAD']      || Config.DEFAULT_HEAD
  , puppet:   process.env['WECHATY_PUPPET']    || Config.DEFAULT_PUPPET
  , apihost:  process.env['WECHATY_APIHOST']   || Config.DEFAULT_APIHOST
  , validApiHost
})

function validApiHost(apihost: string): boolean {
  if (/^[a-zA-Z0-9\.\-\_]+:?[0-9]*$/.test(apihost)) {
    return true
  }
  throw new Error('validApiHost() fail for ' + apihost)
}
validApiHost(Config.apihost)

/**
 * 2. ENVIRONMENT VARIABLES (only)
 */
Object.assign(Config, {
  port:       process.env['WECHATY_PORT']       || null // 0 for disable port
  , profile:  process.env['WECHATY_PROFILE']    || null // DO NOT set DEFAULT_PROFILE, because sometimes user do not want to save session
  , token:    process.env['WECHATY_TOKEN']      || null // DO NOT set DEFAULT, because sometimes user do not want to connect to io cloud service
  , debug:    !!(process.env['WECHATY_DEBUG'])  || false
})

/**
 * 3. Service Settings
 */
Object.assign(Config, {
  // get PORT form cloud service env, ie: heroku
  httpPort: process.env['PORT'] || process.env['WECHATY_PORT'] || Config.DEFAULT_PORT
})

/**
 * 4. Envioronment Identify
 */
Object.assign(Config, {
  isDocker:   isWechatyDocker()
})

function isWechatyDocker() {
  /**
   * Continuous Integration System
   */
  const isCi = require('is-ci')
  if (isCi) {
    return false
  }

  /**
   * Cloud9 IDE
   */
  const c9 = Object.keys(process.env)
                  .filter(k => /^C9_/.test(k))
                  .length
  if (c9 > 7 && process.env['C9_PORT']) {
    return false
  }

  const cgroup = '/proc/1/cgroup'
  try       { fs.statSync(cgroup).isFile() }
  catch (e) { return false }

  // http://stackoverflow.com/a/20624315/1123955
  const line = execSync(`sort -n ${cgroup} 2>/dev/null | head -1`)
                .toString()
                .replace(/\n$/, '')

  // instead of `/`, docker will end with a container id
  if (/\/$/.test(line)) {
    return false
  }

  return true
}

/**
 * 5. live setting
 */
function puppetInstance(): Puppet
function puppetInstance(empty: null): void
function puppetInstance(instance: Puppet): void

function puppetInstance(instance?: Puppet | null): Puppet | void {

  if (instance === undefined) {
    if (!Config._puppetInstance) {
      throw new Error('no puppet instance')
    }
    return Config._puppetInstance

  } else if (instance === null) {
    log.verbose('Config', 'puppetInstance(null)')
    Config._puppetInstance = null
    return

  }

  log.verbose('Config', 'puppetInstance(%s)', instance.constructor.name)
  Config._puppetInstance = instance
  return<commit_msg>fix #70 ,it maybe cause by designing the ConfigSetting as an interface, work around it putting the _puppetinstace in to global<commit_after>/**
 * Wechaty - Wechaty for Bot, Connect ChatBots, Chat as a Service
 *
 * https://github.com/wechaty/wechaty/
 */
import { execSync } from 'child_process'
import * as fs from 'fs'

import { Puppet } from './puppet'
import { log }    from './brolog-env'

export type PuppetName = 'web' | 'android' | 'ios'
export type HeadName = 'chrome' | 'phantomjs' | 'firefox'

export interface ConfigSetting {

  DEFAULT_HEAD: HeadName
  DEFAULT_PUPPET: PuppetName
  DEFAULT_APIHOST: string
  DEFAULT_PROFILE: string
  DEFAULT_TOKEN:  string
  DEFAULT_PROTOCOL: string
  CMD_CHROMIUM: string
  DEFAULT_PORT: number

  port: number
  profile: string
  token: string
  debug: boolean

  puppet: PuppetName
  head: HeadName

  apihost: string
  validApiHost: (host: string) => boolean

  httpPort: number

  _puppetInstance: Puppet | null
  puppetInstance(): Puppet
  puppetInstance(empty: null): void
  puppetInstance(instance: Puppet): void
  puppetInstance(instance?: Puppet | null): Puppet | void

  isDocker: boolean

}
/* tslint:disable:variable-name */
/* tslint:disable:no-var-requires */
export const Config: ConfigSetting = require('../package.json').wechaty

/**
 * 1. ENVIRONMENT VARIABLES + PACKAGES.JSON (default)
 */
Object.assign(Config, {
  head:       process.env['WECHATY_HEAD']      || Config.DEFAULT_HEAD
  , puppet:   process.env['WECHATY_PUPPET']    || Config.DEFAULT_PUPPET
  , apihost:  process.env['WECHATY_APIHOST']   || Config.DEFAULT_APIHOST
  , validApiHost
})

function validApiHost(apihost: string): boolean {
  if (/^[a-zA-Z0-9\.\-\_]+:?[0-9]*$/.test(apihost)) {
    return true
  }
  throw new Error('validApiHost() fail for ' + apihost)
}
validApiHost(Config.apihost)

/**
 * 2. ENVIRONMENT VARIABLES (only)
 */
Object.assign(Config, {
  port:       process.env['WECHATY_PORT']       || null // 0 for disable port
  , profile:  process.env['WECHATY_PROFILE']    || null // DO NOT set DEFAULT_PROFILE, because sometimes user do not want to save session
  , token:    process.env['WECHATY_TOKEN']      || null // DO NOT set DEFAULT, because sometimes user do not want to connect to io cloud service
  , debug:    !!(process.env['WECHATY_DEBUG'])  || false
})

/**
 * 3. Service Settings
 */
Object.assign(Config, {
  // get PORT form cloud service env, ie: heroku
  httpPort: process.env['PORT'] || process.env['WECHATY_PORT'] || Config.DEFAULT_PORT
})

/**
 * 4. Envioronment Identify
 */
Object.assign(Config, {
  isDocker:   isWechatyDocker()
})

function isWechatyDocker() {
  /**
   * Continuous Integration System
   */
  const isCi = require('is-ci')
  if (isCi) {
    return false
  }

  /**
   * Cloud9 IDE
   */
  const c9 = Object.keys(process.env)
                  .filter(k => /^C9_/.test(k))
                  .length
  if (c9 > 7 && process.env['C9_PORT']) {
    return false
  }

  const cgroup = '/proc/1/cgroup'
  try       { fs.statSync(cgroup).isFile() }
  catch (e) { return false }

  // http://stackoverflow.com/a/20624315/1123955
  const line = execSync(`sort -n ${cgroup} 2>/dev/null | head -1`)
                .toString()
                .replace(/\n$/, '')

  // instead of `/`, docker will end with a container id
  if (/\/$/.test(line)) {
    return false
  }

  return true
}

/**
 * 5. live setting
 */
function puppetInstance(): Puppet
function puppetInstance(empty: null): void
function puppetInstance(instance: Puppet): void

function puppetInstance(instance?: Puppet | null): Puppet | void {

  if (instance === undefined) {
    if (!global['_puppetInstance']) {
      throw new Error('no puppet instance')
    }
    return global['_puppetInstance']

  } else if (instance === null) {
    log.verbose('Config', 'puppetInstance(null)')
    global['_puppetInstance'] = null
    return

  }

  log.verbose('Config', 'puppetInstance(%s)', instance.constructor.name)
  global['_puppetInstance'] = instance
  return
{'fraction_non_alphanumeric': 0.13836398224476854, 'fraction_numerical': 0.008877615726062143, 'mean_word_length': 3.2742547425474253, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7097877', 'n_tokens_mistral': 2754, 'n_tokens_neox': 2650, 'n_words': 651}