提交 e391a2e4 编写于 作者: Huan (李卓桓)'s avatar Huan (李卓桓)

doc

......@@ -16,5 +16,5 @@ notifications:
urls:
- ${GITTER_IM_URL}
on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_failure: change # options: [always|never|change] default: always
on_start: never # options: [always|never|change] default: always
{
"name": "Wechaty Cloud Bot for IO",
"description": "Wechat for Bot. Get your own cloud bot by deploy me",
"name": "Wechaty Cloud Bot for IO @ Heroku",
"description": "Wechat for Bot. Get your Heroku cloud bot by deploy me",
"repository": "https://github.com/zixia/wechaty",
"logo": "https://raw.githubusercontent.com/zixia/wechaty/master/image/wechaty-icon.png",
"keywords": ["wechaty", "wechat", "bot", "chatbot", "framework", "cloudbot"],
......
#!/usr/bin/env node
const Wechaty = require('..')
const log = Wechaty.log
......
......@@ -31,6 +31,7 @@ const bot = new Wechaty({ profile: 'example-bot.wechaty.json' })
bot
.on('login' , user => log.info('Bot', `${user.name()} logined`))
.on('logout' , user => log.info('Bot', `${user.name()} logouted`))
.on('error' , e => log.info('Bot', 'error: %s', e))
.on('scan', ({url, code}) => {
if (!/201|200/.test(code)) {
let loginUrl = url.replace(/\/qrcode\//, '/l/')
......
{
"name": "wechaty",
"version": "0.2.7",
"version": "0.2.8",
"description": "Wechat for Bot. (Personal Account NOT Official Account)",
"main": "index.js",
"scripts": {
"lint": "eslint src test",
"pretest": "npm run lint",
"start": "node bin/io-bot.js",
"start": "node bin/io-bot",
"demo": "node example/ding-dong-bot.js",
"test": "cross-env TAP_TIMEOUT=600 tap --reporter=tap test"
"test": "cross-env TAP_TIMEOUT=600 tap --reporter=tap test/{*,**/*}.spec.js"
},
"repository": {
"type": "git",
......@@ -52,7 +52,7 @@
"phantomjs-prebuilt": "latest",
"ps-tree": "latest",
"retry-promise": "latest",
"selenium-webdriver": "^2.53.2",
"selenium-webdriver": "latest",
"socket.io": "latest",
"ws": "latest"
},
......
......@@ -167,3 +167,7 @@ Object.keys(Message.Type).forEach(k => {
Message.attach = function(puppet) { Message.puppet = puppet }
module.exports = Message
/*
* join room in mac client: https://support.weixin.qq.com/cgi-bin/mmsupport-bin/addchatroombyinvite?ticket=AUbv%2B4GQA1Oo65ozlIqRNw%3D%3D&exportkey=AS9GWEg4L82fl3Y8e2OeDbA%3D&lang=en&pass_ticket=T6dAZXE27Y6R29%2FFppQPqaBlNwZzw9DAN5RJzzzqeBA%3D&wechat_real_lang=en
*/
const log = require('npmlog')
const level = process.env.WECHATY_LOG
const levelRegexStr = 'silly|verbose|info|warn|error|silent'
const levelRegex = new RegExp(levelRegexStr, 'i')
if (levelRegex.test(level)) {
log.level = level.toLowerCase()
log.verbose('NpmLog', 'WECHATY_LOG set level to %s', level)
}
else if (level){
log.warn('NpmLog', 'env WECHATY_LOG(%s) must be one of silly|verbose|info|warn|error|silent', level)
}
module.exports = log
const log = require('npmlog')
const level = process.env.WECHATY_LOG
const levelRegexStr = 'silly|verbose|info|warn|error|silent'
const levelRegex = new RegExp(levelRegexStr, 'i')
if (levelRegex.test(level)) {
log.level = level.toLowerCase()
log.verbose('NpmLog', 'WECHATY_LOG set level to %s', level)
}
else if (level){
log.warn('NpmLog', 'env WECHATY_LOG(%s) must be one of silly|verbose|info|warn|error|silent', level)
}
module.exports = log
......@@ -108,13 +108,20 @@ class Browser extends EventEmitter {
// const phantomjsExe = require('phantomjs2').path
const phantomjsArgs = [
'--ignore-ssl-errors=true' // this help socket.io connect with localhost
, '--load-images=false'
// , '--webdriver-logfile=/tmp/wd.log'
// , '--webdriver-loglevel=DEBUG'
'--load-images=false'
, '--ignore-ssl-errors=true' // this help socket.io connect with localhost
, '--web-security=false' // https://github.com/ariya/phantomjs/issues/12440#issuecomment-52155299
, '--ssl-protocol=TLSv1' // https://github.com/ariya/phantomjs/issues/11239#issuecomment-42362211
// issue: Secure WebSocket(wss) do not work with Self Signed Certificate in PhantomJS #12
// , '--ssl-certificates-path=D:\\cygwin64\\home\\zixia\\git\\wechaty' // http://stackoverflow.com/a/32690349/1123955
// , '--ssl-client-certificate-file=cert.pem' //
]
if (process.env.WECHATY_DEBUG) {
phantomjsArgs.push('--remote-debugger-port=8080') // XXX: be careful when in production usage.
phantomjsArgs.push('--remote-debugger-port=8080') // XXX: be careful when in production env.
phantomjsArgs.push('--webdriver-loglevel=DEBUG')
// phantomjsArgs.push('--webdriver-logfile=webdriver.debug.log')
}
const customPhantom = WebDriver.Capabilities.phantomjs()
......@@ -208,22 +215,24 @@ class Browser extends EventEmitter {
return
}
let browserRe
switch (this.head) {
case true:
case 'chrome':
browserRe = 'chrome(?!driver)'
break
case false:
case undefined:
case null:
case 'phantomjs':
switch (true) {
case !this.head: // no head default to phantomjs
case /phantomjs/i.test(this.head):
case /phantom/i.test(this.head):
browserRe = 'phantomjs'
break
case this.head: // head default to chrome
case /chrome/i.test(this.head):
browserRe = 'chrome(?!driver)'
break
default:
log.warn('PuppetWebBrowser', 'getBrowserPids() for unsupported head: %s', this.head)
browserRe = this.head
}
let matchRegex = new RegExp(browserRe, 'i')
const pids = children.filter(child => {
// https://github.com/indexzero/ps-tree/issues/18
......@@ -284,6 +293,11 @@ class Browser extends EventEmitter {
})
}
/**
*
* check whether browser is full functional
*
*/
readyLive() {
log.verbose('PuppetWebBrowser', 'readyLive()')
if (this.dead()) {
......
......@@ -48,7 +48,7 @@ function onBrowserDead(e) {
// guard by variable: isBrowserBirthing to prevent the 2nd time entrance.
if (this.isBrowserBirthing) {
if (this.isBrowserBirthing === true) {
log.warn('PuppetWebEvent', 'onBrowserDead() Im busy, dont call me again before I return. this time will return and do nothing')
log.verbose('PuppetWebEvent', 'onBrowserDead() Im busy, dont call me again before I return. this time will return and do nothing')
return
} else {
log.warn('PuppetWebEvent', 'onBrowserDead() Im FAKE busy? isBrowserBirthing is not boolean true!')
......@@ -56,7 +56,7 @@ function onBrowserDead(e) {
}
return co.call(this, function* () {
log.warn('PuppetWebEvent', 'onBrowserDead() co() set isBrowserBirthing true')
log.verbose('PuppetWebEvent', 'onBrowserDead() co() set isBrowserBirthing true')
this.isBrowserBirthing = true
const TIMEOUT = 180000 // 180s / 3m
......@@ -171,7 +171,10 @@ function onServerDisconnect(data) {
// because the browser has just refreshed, need some time to re-init to ready.
// if the browser is not ready, bridge init will fail,
// caused browser dead and have to be restarted. 2016/6/12
setTimeout(() => {
setTimeout(_ => {
if (!this.bridge) {
return // XXX: sometimes this.bridge gone in this timeout. why? what's happend between the last if(!this.bridge) check and the timeout call?
}
this.bridge.init()
.then(r => log.verbose('PuppetWebEvent', 'onServerDisconnect() bridge re-inited: %s', r))
.catch(e => log.error('PuppetWebEvent', 'onServerDisconnect() exception: [%s]', e))
......
......@@ -449,7 +449,7 @@ return (function(port) {
}
/*global io*/ // Wechaty global variable: socket
var socket = Wechaty.vars.socket = io.connect('https://127.0.0.1:' + port)
var socket = Wechaty.vars.socket = io.connect('wss://127.0.0.1:' + port/*, {transports: ['websocket']}*/)
// ding -> dong. for test & live check purpose
// ping/pong are reserved by socket.io https://github.com/socketio/socket.io/issues/2414
......
......@@ -99,7 +99,8 @@ class Server extends EventEmitter {
})
socketServer.sockets.on('connection', (s) => {
log.verbose('PuppetWebServer', 'createSocketIo() got connection from browser')
if (this.socketClient) { this.socketClient = null } // close() ???
// console.log(s.handshake)
if (this.socketClient) { this.socketClient = undefined } // close() ???
this.socketClient = s
this.initEventsFromClient(s)
})
......@@ -112,9 +113,9 @@ class Server extends EventEmitter {
this.emit('connection', client)
client.on('disconnect', e => {
log.verbose('PuppetWebServer', 'socket.io disconnect: %s', e)
log.silly('PuppetWebServer', 'socket.io disconnect: %s', e)
// 1. Browser reload / 2. Lost connection(Bad network)
this.socketClient = null
this.socketClient = undefined
this.emit('disconnect', e)
})
......
......@@ -6,8 +6,11 @@
* so it will not be a security issue.
*
* http://blog.mgechev.com/2014/02/19/create-https-tls-ssl-application-with-express-nodejs/
* openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365
* openssl req -x509 -days 3650 -nodes -newkey rsa:2048 -keyout key.pem -out cert.pem
* openssl rsa -in key.pem -out newkey.pem && mv newkey.pem key.pem
*
* Reference:
* What is a Pem file - http://serverfault.com/a/9717
*/
const key = `
-----BEGIN RSA PRIVATE KEY-----
......
......@@ -32,6 +32,9 @@ function onFeed({
, timeout = 60000 // 60s default. can be override in options but be careful about the number zero(0)
} = {}) {
type = type || 'HEARTBEAT' // BUG compatible with issue: node-tap strange behaviour cause CircleCI & Travis-CI keep failing #11
timeout = timeout || 60000 // BUG compatible with issue: node-tap strange behaviour cause CircleCI & Travis-CI keep failing #11
if (!this) {
throw new Error('onFeed() must has `this` of instanceof PuppetWeb')
}
......@@ -66,7 +69,9 @@ function clearWatchDogTimer() {
if (this.watchDogTimer) {
clearTimeout(this.watchDogTimer)
this.watchDogTimer = null
log.silly('PuppetWebWatchdog', 'clearWatchDogTimer() cleared')
const timeLeft = this.watchDogTimerTime - Date.now()
log.silly('PuppetWebWatchdog', 'clearWatchDogTimer() [%d] seconds left', Math.ceil(timeLeft / 1000))
} else {
log.silly('PuppetWebWatchdog', 'clearWatchDogTimer() nothing to clear')
}
......@@ -79,6 +84,7 @@ function setWatchDogTimer(timeout) {
log.silly('PuppetWebWatchdog', 'setWatchDogTimer(%d)', timeout)
this.watchDogTimer = setTimeout(watchDogReset.bind(this, timeout), timeout)
this.watchDogTimerTime = Date.now() + timeout
// block quit, force to use quit() // this.watchDogTimer.unref() // dont block quit
}
......
......@@ -12,7 +12,20 @@ const PROFILE = 'unit-test-session.wechaty.json'
const PuppetWeb = require('../../src/puppet-web')
const Message = require('../../src/message')
test('PuppetWeb smoke testing', function(t) {
test('Puppet Web Self Message Identification', function(t) {
const p = new PuppetWeb({port: PORT, head: HEAD, profile: PROFILE})
t.ok(p, 'should instantiated a PuppetWeb')
const EXPECTED_USER_ID = 'zixia'
const m = new Message()
m.set('from', EXPECTED_USER_ID)
p.userId = EXPECTED_USER_ID
t.ok(p.self(m), 'should identified self for message which from is self')
t.end()
})
false && test('PuppetWeb smoke testing', function(t) {
let pw = new PuppetWeb({port: PORT, head: HEAD, profile: PROFILE})
t.ok(pw, 'should instantiated a PuppetWeb')
......@@ -63,7 +76,6 @@ test('Puppet Web server/browser communication', function(t) {
yield pw.init()
t.pass('should be inited')
log.level = 'silly'
const ret = yield dingSocket(pw.server)
t.equal(ret, EXPECTED_DING_DATA, 'should got EXPECTED_DING_DATA after resolved dingSocket()')
})
......@@ -74,8 +86,6 @@ log.level = 'silly'
.then(r => { // Finally
pw.quit()
.then(t.end)
log.level = 'info'
})
.catch(e => { t.fail(e) }) // Exception
......@@ -83,7 +93,7 @@ log.level = 'info'
/////////////////////////////////////////////////////////////////////////////
function dingSocket(server) {
const maxTime = 60000 // 60s
const waitTime = 500
const waitTime = 3000
let totalTime = 0
return new Promise((resolve, reject) => {
log.verbose('TestPuppetWeb', 'dingSocket()')
......@@ -96,7 +106,7 @@ log.level = 'info'
return testDing()
function testDing() {
// log.silly('TestPuppetWeb', server.socketio)
log.silly('TestPuppetWeb', 'dingSocket() server.socketServer: %s', server.socketServer)
if (!server.socketClient) {
totalTime += waitTime
if (totalTime > maxTime) {
......@@ -107,7 +117,7 @@ log.level = 'info'
setTimeout(testDing, waitTime)
return
}
//log.silly('TestPuppetWebServer', server.socketClient)
log.silly('TestPuppetWeb', 'dingSocket() server.socketClient: %s', server.socketClient)
server.socketClient.once('dong', data => {
log.verbose('TestPuppetWeb', 'socket recv event dong: ' + data)
return resolve(data)
......@@ -117,16 +127,3 @@ log.level = 'info'
})
}
})
test('Puppet Web Self Message Identification', function(t) {
const p = new PuppetWeb({port: PORT, head: HEAD, profile: PROFILE})
t.ok(p, 'should instantiated a PuppetWeb')
const EXPECTED_USER_ID = 'zixia'
const m = new Message()
m.set('from', EXPECTED_USER_ID)
p.userId = EXPECTED_USER_ID
t.ok(p.self(m), 'should identified self for message which from is self')
t.end()
})
......@@ -21,6 +21,12 @@ test('Puppet Web watchdog timer', function(t) {
co(function* () {
const origLogLevel = log.level
if (log.level === 'info') {
log.level = 'silent'
t.pass('set log.level = silent to mute log when watchDog reset wechaty temporary')
}
yield pw.init()
pw.quit()
// yield pw.bridge.quit()
......@@ -34,7 +40,7 @@ test('Puppet Web watchdog timer', function(t) {
data: 'active_for_timeout_1ms'
, timeout: 1
})
yield new Promise((resolve) => setTimeout(_ => resolve(), 10)) // wait untill reset
yield new Promise(resolve => setTimeout(resolve, 1000)) // wait untill reset
t.equal(errorCounter, 1, 'should get event[error] after watchdog timeout')
pw.once('error', e => t.fail('waitDing() triggered watchDogReset()'))
......@@ -42,12 +48,11 @@ test('Puppet Web watchdog timer', function(t) {
const EXPECTED_DING_DATA = 'dingdong'
pw.emit('watchdog', { data: 'feed to extend the dog life' })
const origLogLevel = log.level
log.level = 'silly'
t.pass('set log.level = silent to mute log when watchDog reset wechaty temporary')
const dong = yield waitDing(EXPECTED_DING_DATA)
log.level = origLogLevel
t.equal(dong, EXPECTED_DING_DATA, 'should get EXPECTED_DING_DATA from ding after watchdog reset, and restored log level')
log.level = origLogLevel
})
.catch(e => { // Exception
t.fail('co exception: ' + e.message)
......@@ -73,6 +78,7 @@ test('Puppet Web watchdog timer', function(t) {
return retryPromise({max: max, backoff: backoff}, function(attempt) {
log.silly('TestPuppetWeb', 'waitDing() retryPromise: attampt %s/%s time for timeout %s'
, attempt, max, timeout)
return pw.ding(data)
.then(r => {
if (!r) {
......@@ -85,6 +91,7 @@ test('Puppet Web watchdog timer', function(t) {
log.verbose('TestPuppetWeb', 'waitDing() exception: %s', e.message)
throw e
})
})
.catch(e => {
log.error('TestPuppetWeb', 'retryPromise() waitDing() finally FAIL: %s', e.message)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册