config.ts 5.5 KB
Newer Older
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
1 2
/**
 * Wechaty - Wechaty for Bot, Connect ChatBots, Chat as a Service
3
 *
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
4 5
 * https://github.com/wechaty/wechaty/
 */
6 7
const isCi      = require('is-ci')
const isDocker  = require('is-docker')
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
8

9 10
import { log }    from 'brolog'

11
import { Puppet } from './puppet'
12

13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
const logLevel = process.env['WECHATY_LOG']
if (logLevel) {
  log.level(logLevel.toLowerCase())
  log.silly('Brolog', 'WECHATY_LOG set level to %s', logLevel)
}

/**
 * to handle unhandled exceptions
 */
if (/verbose|silly/i.test(logLevel)) {
  log.info('Config', 'registering process.on("unhandledRejection") for development/debug')
  process.on('unhandledRejection', (reason, promise) => {
    log.error('Config', '###########################')
    log.error('Config', 'unhandledRejection: %s %s', reason, promise)
    log.error('Config', '###########################')
    promise.catch(err => {
      log.error('Config', 'unhandledRejection::catch(%s)', err.message)
      console.error('Config', err) // I don't know if log.error has similar full trace print support like console.error
    })
  })
33
}
34

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
35
export type PuppetName = 'web' | 'android' | 'ios'
36
export type HeadName = 'chrome' | 'phantomjs' | 'firefox'
37

38
export interface ConfigSetting {
39

40
  DEFAULT_HEAD: HeadName
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
41
  DEFAULT_PUPPET: PuppetName
42 43 44
  DEFAULT_APIHOST: string
  DEFAULT_PROFILE: string
  DEFAULT_TOKEN:  string
45 46
  DEFAULT_PROTOCOL: string
  CMD_CHROMIUM: string
47 48 49 50 51 52 53
  DEFAULT_PORT: number

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

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
54
  puppet: PuppetName
55
  head: HeadName
56 57

  apihost: string
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
58
  validApiHost: (host: string) => boolean
59 60 61

  httpPort: number

62 63 64
  _puppetInstance: Puppet | null
  puppetInstance(): Puppet
  puppetInstance(empty: null): void
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
65
  puppetInstance(instance: Puppet): void
66
  puppetInstance(instance?: Puppet | null): Puppet | void
67

68
  isDocker: boolean
69 70

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

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
75 76 77
/**
 * 1. ENVIRONMENT VARIABLES + PACKAGES.JSON (default)
 */
78
Object.assign(Config, {
L
lijiarui 已提交
79 80 81 82
  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,
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
83 84
})

85
function validApiHost(apihost: string): boolean {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
86 87 88 89 90 91 92
  if (/^[a-zA-Z0-9\.\-\_]+:?[0-9]*$/.test(apihost)) {
    return true
  }
  throw new Error('validApiHost() fail for ' + apihost)
}
validApiHost(Config.apihost)

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
93 94 95 96
/**
 * 2. ENVIRONMENT VARIABLES (only)
 */
Object.assign(Config, {
L
lijiarui 已提交
97 98 99 100
  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,
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
101
})
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
102

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
103 104 105 106 107
/**
 * 3. Service Settings
 */
Object.assign(Config, {
  // get PORT form cloud service env, ie: heroku
L
lijiarui 已提交
108
  httpPort: process.env['PORT'] || process.env['WECHATY_PORT'] || Config.DEFAULT_PORT,
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
109 110 111 112 113 114
})

/**
 * 4. Envioronment Identify
 */
Object.assign(Config, {
115 116
  isDocker:  isWechatyDocker(),
  isGlobal:  isWechatyInstalledGlobal(),
117
})
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
118

119 120 121 122 123 124 125 126 127 128
function isWechatyInstalledGlobal() {
  /**
   * TODO:
   * 1. check /node_modules/wechaty
   * 2. return true if exists
   * 3. otherwise return false
   */
   return false
}

129
function isWechatyDocker() {
130
  /**
131
   * false for Continuous Integration System
132
   */
133 134 135
  if (isCi) {
    return false
  }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
136

137
  /**
138
   * false Cloud9 IDE
139 140 141 142 143 144 145
   */
  const c9 = Object.keys(process.env)
                  .filter(k => /^C9_/.test(k))
                  .length
  if (c9 > 7 && process.env['C9_PORT']) {
    return false
  }
Huan (李卓桓)'s avatar
lint  
Huan (李卓桓) 已提交
146

147 148 149
  /**
   * return indentify result by NPM module `is-docker`
   */
150
  return isDocker()
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
151 152
}

153 154 155
/**
 * 5. live setting
 */
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
156 157 158 159
function puppetInstance(): Puppet
function puppetInstance(empty: null): void
function puppetInstance(instance: Puppet): void

160
function puppetInstance(instance?: Puppet | null): Puppet | void {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
161 162

  if (instance === undefined) {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
163
    if (!this._puppetInstance) {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
164
      throw new Error('no puppet instance')
165
    }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
166
    return this._puppetInstance
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
167 168

  } else if (instance === null) {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
169
    log.verbose('Config', 'puppetInstance(null)')
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
170
    this._puppetInstance = null
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
171
    return
172
  }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
173

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
174
  log.verbose('Config', 'puppetInstance(%s)', instance.constructor.name)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
175
  this._puppetInstance = instance
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
176 177
  return

178 179
}

180
Object.assign(Config, {
L
lijiarui 已提交
181
  puppetInstance,
182 183
})

Huan (李卓桓)'s avatar
bug fix  
Huan (李卓桓) 已提交
184 185 186 187
export type WatchdogFoodName = 'HEARTBEAT'
                              | 'POISON'
                              | 'SCAN'

188
export interface WatchdogFood {
L
lijiarui 已提交
189 190 191
  data: any,
  timeout?: number,  // millisecond
  type?: WatchdogFoodName,
192 193
}

194
export interface ScanInfo {
L
lijiarui 已提交
195 196
  url: string,
  code: number,
197 198
}

199 200 201
/**
 * from Message
 */
202
export interface RecommendInfo {
L
lijiarui 已提交
203 204 205 206
  UserName:   string,
  NickName:   string,  // display_name
  Content:    string,  // request message
  HeadImgUrl: string,  // message.RecommendInfo.HeadImgUrl
207

L
lijiarui 已提交
208 209
  Ticket:     string,  // a pass token
  VerifyFlag: number,
210

211 212
}

213
export interface Sayable {
214
  say(content: string, replyTo?: any|any[]): Promise<boolean>
215
}
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
216

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
217 218 219
export interface Sleepable {
  sleep(millisecond: number): Promise<void>
}
220

221 222 223 224 225 226 227 228
/**
 * ISSUE #72
 * Introduce the SELENIUM_PROMISE_MANAGER environment variable.
 * When set to 1, selenium-webdriver will use the existing ControlFlow scheduler.
 * When set to 0, the SimpleScheduler will be used.
 */
process.env['SELENIUM_PROMISE_MANAGER'] = 0

229 230 231 232
export {
  log,
}

233
export default Config