config.ts 6.5 KB
Newer Older
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
1
/**
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
2
 *   Wechaty - https://github.com/chatie/wechaty
3
 *
4
 *   @copyright 2016-2017 Huan LI <zixia@zixia.net>
5 6 7 8 9 10 11 12 13 14 15 16
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
17
 *
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
18
 */
19 20 21 22
import * as fs    from 'fs'
import * as os    from 'os'
import * as path  from 'path'

23 24
import * as readPkgUp from 'read-pkg-up'

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
25
const pkg = readPkgUp.sync({ cwd: __dirname }).pkg
26 27
export const VERSION = pkg.version

28 29 30 31 32 33 34 35 36 37 38
/**
 * Raven.io
 */
import * as Raven from 'raven'
Raven.disableConsoleAlerts()

Raven
.config(
  process.env.NODE_ENV === 'production'
    && 'https://f6770399ee65459a82af82650231b22c:d8d11b283deb441e807079b8bb2c45cd@sentry.io/179672',
  {
39
    release: VERSION,
40 41
    tags: {
      git_commit: 'c0deb10c4',
42
      platform:   !!process.env['WECHATY_DOCKER']
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
                  ? 'docker'
                  : os.platform(),
    },
  },
)
.install()

/*
try {
    doSomething(a[0])
} catch (e) {
    Raven.captureException(e)
}

Raven.context(function () {
  doSomething(a[0])
})
 */
61

62 63
import Brolog from 'brolog'
export const log = new Brolog()
64

65
import { Puppet } from './puppet'
66

67
const logLevel = process.env['WECHATY_LOG'] || 'info'
68
if (logLevel) {
69
  log.level(logLevel.toLowerCase() as any)
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
  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
    })
  })
87
}
88

89 90 91 92
export type PuppetName = 'web'
                        | 'android'
                        | 'ios'

93
export interface ConfigSetting {
94

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
95 96 97 98 99 100 101 102 103 104 105
  DEFAULT_HEAD     : number,
  DEFAULT_PORT     : number,
  DEFAULT_PUPPET   : PuppetName
  DEFAULT_APIHOST  : string
  DEFAULT_PROFILE  : string
  DEFAULT_TOKEN    : string
  DEFAULT_PROTOCOL : string

  profile : string
  token   : string
  debug   : boolean
106

107
  head: boolean
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
108
  puppet: PuppetName
109 110

  apihost: string
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
111
  validApiHost: (host: string) => boolean
112 113 114

  httpPort: number

115 116 117
  _puppetInstance: Puppet | null
  puppetInstance(): Puppet
  puppetInstance(empty: null): void
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
118
  puppetInstance(instance: Puppet): void
119
  puppetInstance(instance?: Puppet | null): Puppet | void,
120

121
  gitRevision(): string | null,
122

123
  docker: boolean,
124
}
125 126
/* tslint:disable:variable-name */
/* tslint:disable:no-var-requires */
127
export const config: ConfigSetting = pkg.wechaty
128

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
129 130 131
/**
 * 1. ENVIRONMENT VARIABLES + PACKAGES.JSON (default)
 */
132
Object.assign(config, {
133 134 135
  apihost:    process.env['WECHATY_APIHOST']    || config.DEFAULT_APIHOST,
  head:       ('WECHATY_HEAD' in process.env) ? (!!process.env['WECHATY_HEAD']) : (!!(config.DEFAULT_HEAD)),
  puppet:     process.env['WECHATY_PUPPET']     || config.DEFAULT_PUPPET,
L
lijiarui 已提交
136
  validApiHost,
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
137 138
})

139
function validApiHost(apihost: string): boolean {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
140 141 142 143 144
  if (/^[a-zA-Z0-9\.\-\_]+:?[0-9]*$/.test(apihost)) {
    return true
  }
  throw new Error('validApiHost() fail for ' + apihost)
}
145
validApiHost(config.apihost)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
146

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
147 148 149
/**
 * 2. ENVIRONMENT VARIABLES (only)
 */
150
Object.assign(config, {
151
  // port:       process.env['WECHATY_PORT']     || null, // 0 for disable port
L
lijiarui 已提交
152 153 154
  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 (李卓桓) 已提交
155
})
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
156

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
157 158 159
/**
 * 3. Service Settings
 */
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
160
Object.assign(config, {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
161
  // get PORT form cloud service env, ie: heroku
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
162 163
  httpPort: process.env['PORT'] || process.env['WECHATY_PORT'] || config.DEFAULT_PORT,
})
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
164 165 166 167

/**
 * 4. Envioronment Identify
 */
168
Object.assign(config, {
169
  docker: !!process.env['WECHATY_DOCKER'],
170
  isGlobal:  isWechatyInstalledGlobal(),
171
})
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
172

173 174 175 176 177 178 179 180 181 182
function isWechatyInstalledGlobal() {
  /**
   * TODO:
   * 1. check /node_modules/wechaty
   * 2. return true if exists
   * 3. otherwise return false
   */
   return false
}

183 184 185
/**
 * 5. live setting
 */
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
186 187 188 189
function puppetInstance(): Puppet
function puppetInstance(empty: null): void
function puppetInstance(instance: Puppet): void

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

192
  if (typeof instance === 'undefined') {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
193
    if (!this._puppetInstance) {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
194
      throw new Error('no puppet instance')
195
    }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
196
    return this._puppetInstance
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
197 198

  } else if (instance === null) {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
199
    log.verbose('Config', 'puppetInstance(null)')
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
200
    this._puppetInstance = null
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
201
    return
202
  }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
203

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
204
  log.verbose('Config', 'puppetInstance(%s)', instance.constructor.name)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
205
  this._puppetInstance = instance
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
206 207
  return

208 209
}

210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
function gitVersion(): string | null {
  const dotGitPath  = path.join(__dirname, '..', '.git') // only for ts-node, not for dist
  // const gitLogArgs  = ['log', '--oneline', '-1']
  // TODO: use git rev-parse HEAD ?
  const gitArgs  = ['rev-parse', 'HEAD']

  try {
    // Make sure this is a Wechaty repository
    fs.statSync(dotGitPath).isDirectory()

    const ss = require('child_process')
                .spawnSync('git', gitArgs, { cwd:  __dirname })

    if (ss.status !== 0) {
      throw new Error(ss.error)
    }

    const revision = ss.stdout
                      .toString()
                      .trim()
                      .slice(0, 7)
    return revision

  } catch (e) { /* fall safe */
    /**
     *  1. .git not exist
     *  2. git log fail
     */
    log.silly('Wechaty', 'version() form development environment is not availble: %s', e.message)
    return null
  }
}

Object.assign(config, {
  gitVersion,
L
lijiarui 已提交
245
  puppetInstance,
246 247
})

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

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
252 253 254
export interface Sleepable {
  sleep(millisecond: number): Promise<void>
}
255

256
export {
257
  Raven,
258 259
}

260
export default config