config.ts 7.1 KB
Newer Older
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
1
/**
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
2
 *   Wechaty - https://github.com/chatie/wechaty
3
 *
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
4
 *   @copyright 2016-2018 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
// tslint:disable-next-line:no-reference
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
20
/// <reference path="./typings.d.ts" />
21

22 23 24
import fs    from 'fs'
import os    from 'os'
import path  from 'path'
25

26
import qrImage   from 'qr-image'
27
import Raven     from 'raven'
28 29 30 31

import { log }    from 'brolog'
import {
  FileBox,
32 33
}                from 'file-box'
import readPkgUp  from 'read-pkg-up'
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
34

35
import {
36
  PuppetModuleName,
37 38
}                      from './puppet-config'
import { VERSION }      from './version'
39

40
// https://github.com/Microsoft/TypeScript/issues/14151#issuecomment-280812617
41 42 43
// if (!Symbol.asyncIterator) {
//   (Symbol as any).asyncIterator = Symbol.for('Symbol.asyncIterator')
// }
44

45 46
const pkg = readPkgUp.sync({ cwd: __dirname })!.package

47 48 49 50 51 52
/**
 * Raven.io
 */
Raven.disableConsoleAlerts()

Raven
53 54 55 56 57 58 59 60
  .config(
    isProduction()
      && 'https://f6770399ee65459a82af82650231b22c:d8d11b283deb441e807079b8bb2c45cd@sentry.io/179672',
    {
      release: VERSION,
      tags: {
        git_commit: '',
        platform: process.env.WECHATY_DOCKER
61 62
          ? 'docker'
          : os.platform(),
63
      },
64
    },
65 66
  )
  .install()
67 68 69 70 71 72 73 74 75 76 77 78

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

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

80
const logLevel = process.env.WECHATY_LOG
81
if (logLevel) {
82
  log.level(logLevel.toLowerCase() as any)
Huan (李卓桓)'s avatar
wip...  
Huan (李卓桓) 已提交
83
  log.silly('Config', 'WECHATY_LOG set level to %s', logLevel)
84 85 86 87 88
}

/**
 * to handle unhandled exceptions
 */
Huan (李卓桓)'s avatar
wip...  
Huan (李卓桓) 已提交
89
if (log.level() === 'verbose' || log.level() === 'silly') {
90 91 92 93 94 95
  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 => {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
96
      log.error('Config', 'process.on(unhandledRejection) promise.catch(%s)', err.message)
97 98 99
      console.error('Config', err) // I don't know if log.error has similar full trace print support like console.error
    })
  })
100
}
101

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
102
export interface DefaultSetting {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
103 104
  DEFAULT_HEAD     : number,
  DEFAULT_PORT     : number,
105
  // DEFAULT_PUPPET   : PuppetName,
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
106
  DEFAULT_APIHOST  : string,
107
  // DEFAULT_PROFILE  : string,
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
108 109
  DEFAULT_TOKEN    : string,
  DEFAULT_PROTOCOL : string,
110
}
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
111

112 113
/* tslint:disable:variable-name */
/* tslint:disable:no-var-requires */
Huan (李卓桓)'s avatar
wip...  
Huan (李卓桓) 已提交
114
const DEFAULT_SETTING = pkg.wechaty as DefaultSetting
115

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
116
export class Config {
117

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
118
  public default = DEFAULT_SETTING
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
119

120 121
  public apihost = process.env.WECHATY_APIHOST    || DEFAULT_SETTING.DEFAULT_APIHOST
  public head    = ('WECHATY_HEAD' in process.env) ? (!!process.env.WECHATY_HEAD) : (!!(DEFAULT_SETTING.DEFAULT_HEAD))
122

123
  public systemPuppetName (): PuppetModuleName {
124
    return (
125
      process.env.WECHATY_PUPPET || 'default'
126
    ).toLowerCase() as PuppetModuleName
127
  }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
128

129 130 131 132 133 134
  // DEPRECATED: Use WECHATY_NAME instead
  public profile = process.env.WECHATY_PROFILE

  public name    = process.env.WECHATY_NAME || process.env.WECHATY_PROFILE  // replace WECHATY_PROFILE

  public token   = process.env.WECHATY_TOKEN      // DO NOT set DEFAULT, because sometimes user do not want to connect to io cloud service
135
  public debug   = !!(process.env.WECHATY_DEBUG)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
136

137 138
  public httpPort = process.env.PORT || process.env.WECHATY_PORT || DEFAULT_SETTING.DEFAULT_PORT
  public docker = !!(process.env.WECHATY_DOCKER)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
139

140
  // private _puppetInstance: Puppet | null = null
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
141

142
  constructor () {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
143 144
    log.verbose('Config', 'constructor()')
    this.validApiHost(this.apihost)
145 146 147 148

    if (this.profile) {
      log.warn('Config', 'constructor() WECHATY_PROFILE is DEPRECATED, use WECHATY_NAME instead.')
    }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
149
  }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
150

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

158
  // public puppetInstance(instance?: Puppet | null): Puppet | void {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
159

160 161 162 163 164
  //   if (typeof instance === 'undefined') {
  //     if (!this._puppetInstance) {
  //       throw new Error('no puppet instance')
  //     }
  //     return this._puppetInstance
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
165

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

172 173 174
  //   log.verbose('Config', 'puppetInstance(%s)', instance.constructor.name)
  //   this._puppetInstance = instance
  //   return
175

176
  // }
177

178
  public gitRevision (): string | null {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
179 180 181 182 183 184 185 186 187 188
    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')
189
        .spawnSync('git', gitArgs, { cwd:  __dirname })
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
190 191 192 193 194 195

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

      const revision = ss.stdout
196 197 198
        .toString()
        .trim()
        .slice(0, 7)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
199 200 201 202 203 204 205 206 207
      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
208
    }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
209
  }
210

211
  public validApiHost (apihost: string): boolean {
212
    if (/^[a-zA-Z0-9.\-_]+:?[0-9]*$/.test(apihost)) {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
213 214 215
      return true
    }
    throw new Error('validApiHost() fail for ' + apihost)
216
  }
217

218 219
}

220 221
export const CHATIE_OFFICIAL_ACCOUNT_ID = 'gh_051c89260e5d'

222
export function qrCodeForChatie (): FileBox {
223 224 225 226 227 228 229 230
  const CHATIE_OFFICIAL_ACCOUNT_QRCODE = 'http://weixin.qq.com/r/qymXj7DEO_1ErfTs93y5'
  const name                           = 'qrcode-for-chatie.png'
  const type                           = 'png'

  const qrStream = qrImage.image(CHATIE_OFFICIAL_ACCOUNT_QRCODE, { type })
  return FileBox.fromStream(qrStream, name)
}

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
231 232 233
// http://jkorpela.fi/chars/spaces.html
// String.fromCharCode(8197)
export const FOUR_PER_EM_SPACE = String.fromCharCode(0x2005)
江子健 已提交
234 235
// mobile: \u2005, PC、mac: \u0020
export const AT_SEPRATOR_REGEX = /[\u2005\u0020]/
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
236

237
export function qrcodeValueToImageUrl (qrcodeValue: string): string {
238 239 240
  return [
    'https://api.qrserver.com/v1/create-qr-code/?data=',
    encodeURIComponent(qrcodeValue),
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
241
    '&size=220x220&margin=20',
242 243 244
  ].join('')
}

245
export function isProduction (): boolean {
246 247 248 249
  return process.env.NODE_ENV === 'production'
      || process.env.NODE_ENV === 'prod'
}

250
export {
Huan (李卓桓)'s avatar
wip...  
Huan (李卓桓) 已提交
251
  log,
252
  Raven,
253
  VERSION,
254 255
}

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
256
export const config = new Config()