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

merge

...@@ -39,3 +39,4 @@ t ...@@ -39,3 +39,4 @@ t
socket.io.min.js socket.io.min.js
.*.swp .*.swp
0
...@@ -2,7 +2,6 @@ language: node_js ...@@ -2,7 +2,6 @@ language: node_js
node_js: node_js:
- "6.1" - "6.1"
- "6" - "6"
sudo: required
dist: trusty dist: trusty
before_install: before_install:
- export DISPLAY=:99.0 - export DISPLAY=:99.0
......
![Wechaty](https://raw.githubusercontent.com/zixia/wechaty/master/images/wechaty-logo-en.png) ![Wechaty](https://raw.githubusercontent.com/zixia/wechaty/master/images/wechaty-logo-en.png)
# Wechaty [![Circle CI](https://circleci.com/gh/zixia/wechaty.svg?style=svg)](https://circleci.com/gh/zixia/wechaty) [![Build Status](https://travis-ci.org/zixia/wechaty.svg?branch=master)](https://travis-ci.org/zixia/wechaty) # Wechaty [![Circle CI](https://circleci.com/gh/zixia/wechaty.svg?style=svg)](https://circleci.com/gh/zixia/wechaty) [![Build Status](https://travis-ci.org/zixia/wechaty.svg?branch=master)](https://travis-ci.org/zixia/wechaty)
Wechaty is Wechat for Bot.(Personal Account Robot, NOT Official Account) Wechaty is a Bot-Enable Framework/Library for Personal Account of Wechat.
> Easy creating wechat robot code in 10 lines. > Easy creating personal account wechat robot code in 10 lines.
**Connecting Bots**
[![Join the chat at https://gitter.im/zixia/wechaty](https://badges.gitter.im/zixia/wechaty.svg)](https://gitter.im/zixia/wechaty?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/zixia/wechaty](https://badges.gitter.im/zixia/wechaty.svg)](https://gitter.im/zixia/wechaty?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![node](https://img.shields.io/node/v/wechaty.svg?maxAge=2592000)](https://nodejs.org/) [![node](https://img.shields.io/node/v/wechaty.svg?maxAge=2592000)](https://nodejs.org/)
...@@ -10,19 +12,19 @@ Wechaty is Wechat for Bot.(Personal Account Robot, NOT Official Account) ...@@ -10,19 +12,19 @@ Wechaty is Wechat for Bot.(Personal Account Robot, NOT Official Account)
[![Downloads][downloads-image]][downloads-url] [![Downloads][downloads-image]][downloads-url]
# Why # Why
My daily life/work depends on too much wechat. My daily life/work depends on too much chat on wechat.
* I almost have 14,000 wechat friends till May 2014, before wechat restricting total number of friends to 5,000. * I almost have 14,000 wechat friends till May 2014, before wechat restricts a total number of friends to 5,000.
* I almost have 400 wechat groups that most of them have more than 400 members. * I almost have 400 wechat groups that most of them have more than 400 members.
Can you image that? I'm dying... Can you image that? I'm dying...
So a tireless bot working for me 24x7 on wechat, moniting/filtering the most important messages is badly needed. For example: highlights discusstion which contains the KEYWORDS I want to follow up(especialy in a noisy group). ;-) So a tireless bot working for me 24x7 on wechat, moniting/filtering the most important message is badly needed. For example: highlights discusstion which contains the KEYWORDS I want to follow up(especially in a noisy group). ;-)
# Examples # Examples
Wechaty is super easy to use: 10 lines of javascript is enough for your first wechat robot. Wechaty is super easy to use: 10 lines of javascript is enough for your first wechat robot.
## 1. Basic: 10 lines ## 1. Basic: 10 lines
The following 10 lines of code will implement a bot who will reply message automaticaly for you: The following 10 lines of code will implement a bot that will reply a message automatically to you:
```javascript ```javascript
const Wechaty = require('wechaty') const Wechaty = require('wechaty')
...@@ -44,24 +46,58 @@ bot.on('message', m => { ...@@ -44,24 +46,58 @@ bot.on('message', m => {
}) })
``` ```
Notice that you need to wait a moment while bot trying to get the login QRCode from Wechat. As soon as the bot got login QRCode url, he will print url out. You need to scan the qrcode in wechat, and confirm login. Notice that you need to wait a moment while bot trys to get the login QRCode from Wechat. As soon as the bot gets login QRCode url, he will print url out. You need to scan the qrcode on wechat, and confirm login.
After that, bot will on duty. (roger-bot source can be found at [here](https://github.com/zixia/wechaty/blob/master/example/roger-bot.js)) After that, bot will be on duty. (roger-bot source can be found at [here](https://github.com/zixia/wechaty/blob/master/example/roger-bot.js))
## 2. Advanced: 50 lines ## 2. Advanced: 50 lines
There's another basic usage demo bot named [ding-dong-bot](https://github.com/zixia/wechaty/blob/master/example/ding-dong-bot.js), who can reply `dong` when receive a message `ding`. There's another basic usage demo bot named [ding-dong-bot](https://github.com/zixia/wechaty/blob/master/example/ding-dong-bot.js), who can reply _dong_ when bot receives a message _ding_.
## 3. Hardcore: 100 lines ## 3. Hardcore: 100 lines
To Be Wroten. To Be Written.
Plan to glued with Machine Learning/Deep Learning/Neural Network/Natural Language Processing. Plan to glue with Machine Learning/Deep Learning/Neural Network/Natural Language Processing.
# Installation # Installation & Usage
The recommended installation method is a local NPM install for your project: Use NPM is recommended to install Wechaty for you:
```bash ```bash
$ npm install --save wechaty $ npm install --save wechaty
``` ```
## Start from strach
In case that you do not know anything about nodejs, the follow instructions would help you to run Wechaty bot on your machine.
## 1. Install NodeJS
NodeJS Version 6.0 & above is required.
1. Visit [NodeJS](https://nodejs.org)
1. Download NodeJS Installer(i.e. "v6.2.0 Current")
1. Run Installer to install NodeJS to your machine
## 2. Checkout Wechaty
Use `git` to checkout Wechaty source code from [Github.com](https://github.com)
```shell
git clone git@github.com:zixia/wechaty.git
# git clone https://github.com/zixia/wechaty.git
```
## 3. Install Dependents
```shell
cd wechaty
npm install
```
## 4. Run Demo Bot
```shell
npm start
# node example/ding-dong-bot.js
```
# Trouble Shooting
If wechaty is not run as expected, run unit test maybe help to find some useful message.
```shell
npm test
```
# Requirement # Requirement
ECMAScript2015/ES6. I develop and test wechaty under nodejs6.0. ECMAScript2015/ES6. I develop and test wechaty under nodejs6.0.
...@@ -100,17 +136,18 @@ Emit when there's a new message. ...@@ -100,17 +136,18 @@ Emit when there's a new message.
```javascript ```javascript
bot.on('message', callback) bot.on('message', callback)
``` ```
Callback will get a instance of Message Class. (see `Class Message`) Callback will get an instance of Message Class. (see `Class Message`)
### Event: `login` & `logout` ### Event: `login` & `logout`
To-Be-Supported 1. After the bot login full successful, the event `login` will be emitted.
1. After the bot logout, the event `logout` will be emitted.
## Class Message ## Class Message
All messages will be encaped in Message. All messages will be encaped in Message.
### Message.ready() ### Message.ready()
A message may be not fully initialized yet. Call `ready()` to confirm we get all the data needed. A message may be not fully initialized yet. Call `ready()` to confirm we get all the data needed.
Return a Promise, will be resolved when all data is ready. Return a Promise, will be resolved when all data is ready.
...@@ -121,7 +158,7 @@ message.ready() ...@@ -121,7 +158,7 @@ message.ready()
}) })
``` ```
### Message.get(prop) ### Message.get(prop)
Get prop from a message. Get prop from a message.
Supported prop list: Supported prop list:
...@@ -147,7 +184,7 @@ message.set('content', 'Hello, World!') ...@@ -147,7 +184,7 @@ message.set('content', 'Hello, World!')
## Class Contact ## Class Contact
### Contact.ready() ### Contact.ready()
A Contact may be not fully initialized yet. Call `ready()` to confirm we get all the data needed. A Contact may be not fully initialized yet. Call `ready()` to confirm we get all the data needed.
Return a Promise, will be resolved when all data is ready. Return a Promise, will be resolved when all data is ready.
...@@ -158,7 +195,7 @@ contact.ready() ...@@ -158,7 +195,7 @@ contact.ready()
}) })
``` ```
### Contact.get(prop) ### Contact.get(prop)
Get prop from a contact. Get prop from a contact.
Supported prop list: Supported prop list:
...@@ -178,7 +215,7 @@ contact.get('name') ...@@ -178,7 +215,7 @@ contact.get('name')
## Class Group ## Class Group
### Group.ready() ### Group.ready()
A group may be not fully initialized yet. Call `ready()` to confirm we get all the data needed. A group may be not fully initialized yet. Call `ready()` to confirm we get all the data needed.
Return a Promise, will be resolved when all data is ready. Return a Promise, will be resolved when all data is ready.
...@@ -190,7 +227,7 @@ group.ready() ...@@ -190,7 +227,7 @@ group.ready()
``` ```
### Group.get(prop) ### Group.get(prop)
Get prop from a group. Get prop from a group.
Supported prop list: Supported prop list:
...@@ -217,11 +254,11 @@ Know more about tape: [Why I use Tape Instead of Mocha & So Should You](https:// ...@@ -217,11 +254,11 @@ Know more about tape: [Why I use Tape Instead of Mocha & So Should You](https://
# Version History # Version History
## v0.0.5 (2016/5/11) ## v0.0.5 (2016/5/11)
1. receive & send message 1. Receive & send message
1. show contacts info 1. Show contacts info
1. show groups info 1. Show groups info
1. 1st usable version 1. 1st usable version
1. start coding from 1st May 2016 1. Start coding from May 1st 2016
# Todo List # Todo List
1. Deal with friend request 1. Deal with friend request
...@@ -230,9 +267,6 @@ Know more about tape: [Why I use Tape Instead of Mocha & So Should You](https:// ...@@ -230,9 +267,6 @@ Know more about tape: [Why I use Tape Instead of Mocha & So Should You](https://
Everybody is welcome to issue your needs. Everybody is welcome to issue your needs.
# Known Issues & Support # Known Issues & Support
1. phantomjs not work(no socket.io connect from browser)
2. firefox need to use unstable mode(or inject will be blocked almost forever)
Github Issue - https://github.com/zixia/wechaty/issues Github Issue - https://github.com/zixia/wechaty/issues
# Contributing # Contributing
...@@ -241,7 +275,11 @@ Github Issue - https://github.com/zixia/wechaty/issues ...@@ -241,7 +275,11 @@ Github Issue - https://github.com/zixia/wechaty/issues
```bash ```bash
$ npm lint $ npm lint
``` ```
* Create a issue, fork, then send a pull request(with unit test please). * Create an issue, fork, then send a pull request(with unit test please).
# See Also
* [wxBot](https://github.com/liuwons/wxBot): Wechat Bot API in Python
* [ItChat](https://github.com/littlecodersh/ItChat): Command line talks through Wechat in Python
Author Author
----------------- -----------------
......
machine: machine:
node: node:
version: 6.0.0 version: 6.1.0
post:
- wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
- sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
- sudo apt-get update
- sudo apt-get install google-chrome-stable
dependencies:
post:
notify: notify:
webhooks: webhooks:
# A list of hook hashes, containing the url field # A list of hook hashes, containing the url field
......
此差异已折叠。
const log = require('npmlog') const log = require('npmlog')
//log.level = 'verbose' //log.level = 'verbose'
//log.level = 'silly' log.level = 'silly'
const Wechaty = require('../src/wechaty') const Wechaty = require('../src/wechaty')
const welcome = ` const welcome = `
...@@ -32,7 +33,11 @@ const bot = new Wechaty({head: true}) ...@@ -32,7 +33,11 @@ const bot = new Wechaty({head: true})
bot.init() bot.init()
.then(bot.getLoginQrImgUrl.bind(bot)) .then(bot.getLoginQrImgUrl.bind(bot))
.then(url => console.log(`Scan qrcode in url to login: \n${url}`)) .then(url => console.log(`Scan qrcode in url to login: \n${url}`))
.catch(e => log.error('Bot', 'bot.init() fail: ' + e)) .catch(e => {
log.error('Bot', 'init() fail:' + e)
bot.quit()
process.exit(-1)
})
bot.on('message', m => { bot.on('message', m => {
m.ready() m.ready()
...@@ -52,3 +57,4 @@ bot.on('message', m => { ...@@ -52,3 +57,4 @@ bot.on('message', m => {
bot.on('login' , () => npm.info('Bot', 'logined')) bot.on('login' , () => npm.info('Bot', 'logined'))
bot.on('logout' , () => npm.info('Bot', 'logouted')) bot.on('logout' , () => npm.info('Bot', 'logouted'))
const Wechaty = require('../src/wechaty')
const log = require('npmlog') const log = require('npmlog')
const bot = new Wechaty({head: true}) const bot = new Wechaty({head: true})
bot.init() bot.init()
.then(bot.getLoginQrImgUrl.bind(bot)) .then(bot.getLoginQrImgUrl.bind(bot))
.then(url => console.log(`Scan qrcode in url to login: \n${url}`)) .then(url => console.log(`Scan qrcode in url to login: \n${url}`))
.catch(e => console.error(e))
bot.on('message', m => { bot.on('message', m => {
console.log('RECV: ' + m.get('content')) // 1. print received message console.log('RECV: ' + m.get('content')) // 1. print received message
...@@ -15,4 +15,5 @@ bot.on('message', m => { ...@@ -15,4 +15,5 @@ bot.on('message', m => {
bot.send(reply) // 3. do reply! bot.send(reply) // 3. do reply!
.then(() => console.log('REPLY: roger.')) // 4. print reply message .then(() => console.log('REPLY: roger.')) // 4. print reply message
.catch(e => console.error(e))
}) })
/**
*
* Wechaty bot use a Tuling123.com brain
*
* Apply your own tuling123.com API_KEY
* at: http://www.tuling123.com/html/doc/api.html
*
* Enjoy!
*
* Wechaty - https://github.com/zixia/wechaty
*
*/
const log = require('npmlog')
const co = require('co')
const Tuling123 = require('tuling123-client')
const Wechaty = require('../src/wechaty')
//log.level = 'verbose'
log.level = 'silly'
const TULING123_API_KEY = '18f25157e0446df58ade098479f74b21'
const brain = new Tuling123(TULING123_API_KEY)
const bot = new Wechaty({head: true})
console.log(`
Welcome to Tuling Wechaty Bot.
Tuling API: http://www.tuling123.com/html/doc/api.html
Loading...
`)
bot.init()
.then(bot.getLoginQrImgUrl.bind(bot))
.then(url => console.log(`Scan to login:\n${url}`))
.catch(e => {
log.error('Bot', 'init() fail:' + e)
bot.quit()
process.exit(-1)
})
bot.on('message', m => {
co(function* () {
const msg = yield m.ready()
log.info('Bot', 'recv: %s' , msg)
if (!m.inGroup()) {
const r = new Wechaty.Message()
.set('to', m.get('from'))
const content = m.get('content').toString()
const answer = brain.ask(content, {userid: msg.get('from')})
r.set('content', answer)
yield bot.send(r)
log.info('Bot', `REPLY: ${answer}`)
}
})
.catch(e => log.error('Bot', 'on message rejected: %s' , e))
})
bot.on('login' , e => log.info('Bot', 'bot login.'))
bot.on('logout' , e => log.info('Bot', 'bot logout.'))
{ {
"name": "wechaty", "name": "wechaty",
"version": "0.0.6", "version": "0.0.7",
"description": "Wechat for Bot. (Personal Account, NOT Official Account)", "description": "Wechat for Bot. (Personal Account, NOT Official Account)",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
...@@ -14,14 +14,16 @@ ...@@ -14,14 +14,16 @@
}, },
"keywords": [ "keywords": [
"wechat", "wechat",
"微信",
"weixin",
"personal",
"account",
"bot", "bot",
"robot", "robot",
"framework", "framework",
"library", "library",
"api", "api",
"sdk", "sdk"
"weixin",
"微信"
], ],
"author": "Zhuohuan LI <zixia@zixia.net>", "author": "Zhuohuan LI <zixia@zixia.net>",
"license": "ISC", "license": "ISC",
...@@ -31,12 +33,13 @@ ...@@ -31,12 +33,13 @@
"homepage": "https://github.com/zixia/wechaty#readme", "homepage": "https://github.com/zixia/wechaty#readme",
"dependencies": { "dependencies": {
"body-parser": "^1.15.0", "body-parser": "^1.15.0",
"socket.io": "^1.4.5", "chromedriver": "^2.21.2",
"co": "^4.6.0",
"express": "^4.13.4", "express": "^4.13.4",
"selenium-webdriver": "", "npmlog": "^2.0.3",
"phantomjs-prebuilt": "^2.1.7", "phantomjs-prebuilt": "^2.1.7",
"chromedriver": "^2.21.2", "selenium-webdriver": "",
"npmlog": "^2.0.3" "socket.io": "^1.4.5"
}, },
"eslintConfig": { "eslintConfig": {
"env": { "env": {
...@@ -46,11 +49,11 @@ ...@@ -46,11 +49,11 @@
} }
}, },
"engines": { "engines": {
"node": ">= 6.1.0" "node": ">= 6.0.0"
}, },
"devDependencies": { "devDependencies": {
"co": "^4.6.0",
"eslint": "^2.9.0", "eslint": "^2.9.0",
"tape": "^4.5.1" "tape": "^4.5.1",
"tuling123-client": "0.0.1"
} }
} }
...@@ -45,15 +45,22 @@ class Group { ...@@ -45,15 +45,22 @@ class Group {
id: rawObj.UserName id: rawObj.UserName
, encryId: rawObj.EncryChatRoomId // ??? , encryId: rawObj.EncryChatRoomId // ???
, name: rawObj.NickName , name: rawObj.NickName
, members: rawObj.MemberList.map(m => { , members: this.parseMemberList(rawObj.MemberList)
return {
contact: Contact.load(m.UserName)
, name: m.DisplayName
}
})
} }
} }
parseMemberList(memberList) {
if (!memberList || !memberList.map) {
return []
}
return memberList.map(m => {
return {
contact: Contact.load(m.UserName)
, name: m.DisplayName
}
})
}
dumpRaw() { dumpRaw() {
console.error('======= dump raw group =======') console.error('======= dump raw group =======')
Object.keys(this.rawObj).forEach(k => console.error(`${k}: ${this.rawObj[k]}`)) Object.keys(this.rawObj).forEach(k => console.error(`${k}: ${this.rawObj[k]}`))
......
...@@ -52,8 +52,13 @@ class Browser { ...@@ -52,8 +52,13 @@ class Browser {
// const phantomjsExe = require('phantomjs2').path // const phantomjsExe = require('phantomjs2').path
const customPhantom = WebDriver.Capabilities.phantomjs() const customPhantom = WebDriver.Capabilities.phantomjs()
.set('phantomjs.binary.path', phantomjsExe) .set('phantomjs.binary.path', phantomjsExe)
.set('phantomjs.cli.args', [
'--ignore-ssl-errors=true' // this help socket.io connect with localhost
, '--load-images=false'
, '--remote-debugger-port=9000'
])
log.verbose('Browser', 'phantomjs path:' + phantomjsExe) log.silly('Browser', 'phantomjs path:' + phantomjsExe)
//build custom phantomJS driver //build custom phantomJS driver
return new WebDriver.Builder() return new WebDriver.Builder()
...@@ -69,19 +74,20 @@ class Browser { ...@@ -69,19 +74,20 @@ class Browser {
} }
inject() { inject() {
const injectio = Browser.getInjectio() const injectio = Browser.getInjectio()
log.verbose('Browser', 'injecting') log.verbose('Browser', 'inject()')
try { try {
var p = this.execute(injectio, this.port) return this.execute(injectio, this.port)
.then(r => {
log.verbose('Browser', 'init() after inject()')
return this.execute('return (typeof Wechaty)==="undefined" ? false : Wechaty.init()')
})
.then(r => {
log.verbose('Browser', 'Wechaty.init() return: ' + r)
return r
})
} catch (e) { } catch (e) {
return new Promise((rs, rj) => rj('execute exception: ' + e)) return Promise.reject('execute exception: ' + e)
} }
return p.then(() => {
log.verbose('Browser', 'injected / try Wechaty.init()')
return this.execute('return (typeof Wechaty)==="undefined" ? false : Wechaty.init()')
}).then((data) => {
log.verbose('Browser', 'Wechaty.init() return: ' + data)
return new Promise((resolve, reject) => resolve(data))
})
} }
quit() { quit() {
......
...@@ -46,11 +46,12 @@ return (function(port) { ...@@ -46,11 +46,12 @@ return (function(port) {
// glue funcs // glue funcs
, getLoginStatusCode: function() { return Wechaty.glue.loginScope.code } , getLoginStatusCode: function() { return Wechaty.glue.loginScope.code }
, getLoginQrImgUrl: function() { return Wechaty.glue.loginScope.qrcodeUrl } , getLoginQrImgUrl: function() { return Wechaty.glue.loginScope.qrcodeUrl }
, isLogined: function() { return 200 === Wechaty.glue.loginScope.code /* MMCgi.isLogin ??? */} , isLogin: function() { return !!(window.MMCgi && window.MMCgi.isLogin) }
, isReady: isReady , isReady: isReady
// variable // variable
, socket: null , socket: null
, eventsBuf: []
// funcs // funcs
, init: init , init: init
...@@ -59,6 +60,7 @@ return (function(port) { ...@@ -59,6 +60,7 @@ return (function(port) {
, slog: slog // log throw Socket IO , slog: slog // log throw Socket IO
, ding: ding , ding: ding
, quit: quit , quit: quit
, emit: emit
, getContact: getContact , getContact: getContact
} }
...@@ -85,21 +87,29 @@ return (function(port) { ...@@ -85,21 +87,29 @@ return (function(port) {
function glueAngular() { function glueAngular() {
var injector = angular.element(document).injector() var injector = angular.element(document).injector()
var rootScope = injector.get('$rootScope')
var http = injector.get('$http') var http = injector.get('$http')
var accountFactory = injector.get('accountFactory')
var chatFactory = injector.get('chatFactory') var chatFactory = injector.get('chatFactory')
var confFactory = injector.get('confFactory') var confFactory = injector.get('confFactory')
var contactFactory = injector.get('contactFactory') var contactFactory = injector.get('contactFactory')
var loginScope = angular.element('.login_box').scope()
var rootScope = injector.get('$rootScope')
var appScope = angular.element('[ng-controller="appController"]').scope()
var loginScope = angular.element('[ng-controller="loginController"]').scope()
// get all we need from wx in browser(angularjs) // get all we need from wx in browser(angularjs)
Wechaty.glue = { Wechaty.glue = {
injector: injector injector: injector
, rootScope: rootScope
, http: http , http: http
, accountFactory: accountFactory
, chatFactory: chatFactory , chatFactory: chatFactory
, confFactory: confFactory , confFactory: confFactory
, contactFactory: contactFactory , contactFactory: contactFactory
, rootScope: rootScope
, appScope: appScope
, loginScope: loginScope , loginScope: loginScope
} }
} }
...@@ -107,39 +117,66 @@ return (function(port) { ...@@ -107,39 +117,66 @@ return (function(port) {
function quit() { function quit() {
if (Wechaty.socket) { if (Wechaty.socket) {
Wechaty.socket.close() Wechaty.socket.close()
Wechaty.socket = undefined Wechaty.socket = null
} }
clog('quit()') clog('quit()')
} }
function slog(data) { return Wechaty.socket && Wechaty.socket.emit('log', data) } function slog(msg) { return Wechaty.socket && Wechaty.socket.emit('log', msg) }
function ding() { return 'dong' } function ding() { return 'dong' }
function send(ToUserName, Content) { function send(ToUserName, Content) {
var chat = Wechaty.glue.chatFactory var chat = Wechaty.glue.chatFactory
var conf = Wechaty.glue.confFactory
var m = chat.createMessage({ var m = chat.createMessage({
ToUserName: ToUserName ToUserName: ToUserName
, Content: Content , Content: Content
, MsgType: conf.MSGTYPE_TEXT , MsgType: Wechaty.glue.confFactory.MSGTYPE_TEXT
}) })
chat.appendMessage(m) chat.appendMessage(m)
return chat.sendMessage(m) return chat.sendMessage(m)
} }
function getContact(id) { return Wechaty.glue.contactFactory.getContact(id) } function getContact(id) { return Wechaty.glue.contactFactory.getContact(id) }
function hookMessage() { function hookMessage() {
var rootScope = Wechaty.glue.rootScope Wechaty.glue.rootScope.$on('message:add:success', function(event, data) {
rootScope.$on('message:add:success', function(event, data) { Wechaty.emit('message', data)
if (Wechaty.socket) { })
Wechaty.socket.emit('message', data) Wechaty.glue.appScope.$on("newLoginPage", function(event, data) {
} else { Wechaty.emit('login', data)
clog('Wechaty.socket not ready')
}
}) })
Wechaty.glue.rootScope.$on('root:pageInit:success'), function (event, data) {
Wechaty.emit('login', data)
}
} }
function hookUnload() { function hookUnload() {
window.addEventListener('unload', function(e) { window.addEventListener('unload', function(e) {
Wechaty.socket.emit('unload') // XXX only 1 event can be emitted here???
Wechaty.emit('unload', e)
// Wechaty.slog('emit unload')
// Wechaty.emit('logout', e)
// Wechaty.slog('emit logout')
// Wechaty.slog('emit logout&unload over')
}) })
} }
// Wechaty.emit, will save event & data when there's no socket io connection to prevent event lost
function emit(event, data) {
if (!Wechaty.socket) {
clog('Wechaty.socket not ready')
if (event) {
Wechaty.eventsBuf.push([event, data])
}
setTimeout(emit, 1000) // resent eventsBuf after 1000ms
return
}
if (Wechaty.eventsBuf.length) {
clog('Wechaty.eventsBuf has ' + Wechaty.eventsBuf.length + ' unsend events')
var eventData
while (eventData = Wechaty.eventsBuf.pop()) {
Wechaty.socket.emit(eventData[0], eventData[1])
}
clog('Wechaty.eventsBuf all sent')
}
if (event) {
Wechaty.socket.emit(event, data)
}
}
function connectSocket() { function connectSocket() {
clog('connectSocket()') clog('connectSocket()')
if (typeof io !== 'function') { if (typeof io !== 'function') {
...@@ -178,6 +215,9 @@ return (function(port) { ...@@ -178,6 +215,9 @@ return (function(port) {
window.Wechaty = Wechaty window.Wechaty = Wechaty
if (Wechaty.isLogin()) {
Wechaty.emit('login', 'page refresh')
}
var callback = arguments[arguments.length - 1] var callback = arguments[arguments.length - 1]
if (typeof callback === 'function') { if (typeof callback === 'function') {
return callback('Wechaty') return callback('Wechaty')
......
...@@ -27,22 +27,35 @@ class Server extends EventEmitter { ...@@ -27,22 +27,35 @@ class Server extends EventEmitter {
toString() { return `Class Wechaty.Puppet.Web.Server({port:${this.port}})` } toString() { return `Class Wechaty.Puppet.Web.Server({port:${this.port}})` }
init() { init() {
this.express = this.createExpress() log.verbose('Server', 'initing: ' + this)
this.httpsServer = this.createHttpsServer(this.express, this.port) return new Promise((resolve, reject) => {
this.socketio = this.createSocketIo(this.httpsServer) this.express = this.createExpress()
log.verbose('Server', 'inited: ' + this) this.httpsServer = this.createHttpsServer(this.express
return Promise.resolve(this) , r => resolve(r), e => reject(e)
)
this.socketio = this.createSocketIo(this.httpsServer)
})
} }
/** /**
* Https Server * Https Server
*/ */
createHttpsServer(express) { createHttpsServer(express, resolve, reject) {
return https.createServer({ return https.createServer({
key: require('./ssl-pem').key key: require('./ssl-pem').key
, cert: require('./ssl-pem').cert , cert: require('./ssl-pem').cert
}, express).listen(this.port, () => { }, express)
.listen(this.port, () => {
log.verbose('Server', `createHttpsServer port ${this.port}`) log.verbose('Server', `createHttpsServer port ${this.port}`)
if (typeof resolve === 'function') {
resolve(this)
}
})
.on('error', e => {
log.error('Server', 'createHttpsServer:' + e)
if (typeof reject === 'function') {
reject(e)
}
}) })
} }
...@@ -96,6 +109,7 @@ class Server extends EventEmitter { ...@@ -96,6 +109,7 @@ class Server extends EventEmitter {
'message' 'message'
, 'login' , 'login'
, 'logout' , 'logout'
, 'log'
, 'unload' , 'unload'
].map(e => { ].map(e => {
s.on(e, data => { s.on(e, data => {
......
...@@ -61,13 +61,16 @@ class PuppetWeb extends Puppet { ...@@ -61,13 +61,16 @@ class PuppetWeb extends Puppet {
* `unload` event is sent from js@browser to webserver via socketio * `unload` event is sent from js@browser to webserver via socketio
* after received `unload`, we re-inject the Wechaty js code into browser. * after received `unload`, we re-inject the Wechaty js code into browser.
*/ */
this.server.on('unload', () => { this.server.on('unload', data => {
log.verbose('PuppetWeb', 'server received unload event') log.verbose('PuppetWeb', 'server received unload event')
this.emit('logout', data)
this.browser.inject() this.browser.inject()
.then(() => log.verbose('PuppetWeb', 're-injected')) .then(() => log.verbose('PuppetWeb', 're-injected'))
.catch((e) => log.error('PuppetWeb', 'inject err: ' + e)) .catch((e) => log.error('PuppetWeb', 'inject err: ' + e))
}) })
this.server.on('log', s => log.verbose('PuppetWeb', 'log event:' + s))
return this.server.init() return this.server.init()
} }
......
...@@ -49,8 +49,12 @@ class Wechaty extends EventEmitter { ...@@ -49,8 +49,12 @@ class Wechaty extends EventEmitter {
init() { return this.puppet.init() } init() { return this.puppet.init() }
currentUser() { return this.puppet.currentUser() } currentUser() { return this.puppet.currentUser() }
send(message) { return this.puppet.send(message) } send(message) { return this.puppet.send(message) }
quit() { return this.puppet.quit() }
ding() { return 'dong' } ding() {
// TODO: test through the server & browser
return 'dong'
}
getLoginQrImgUrl() { return this.puppet.getLoginQrImgUrl() } getLoginQrImgUrl() { return this.puppet.getLoginQrImgUrl() }
} }
......
...@@ -5,7 +5,7 @@ const Browser = require('../src/puppet-web-browser') ...@@ -5,7 +5,7 @@ const Browser = require('../src/puppet-web-browser')
const PORT = 58788 const PORT = 58788
test('Browser class smoking tests', function(t) { test('Browser class smoking tests', function(t) {
const b = new Browser({head: true, port: PORT}) const b = new Browser({port: PORT})
t.ok(b, 'Browser instance created') t.ok(b, 'Browser instance created')
co(function* () { co(function* () {
...@@ -24,14 +24,14 @@ test('Browser class smoking tests', function(t) { ...@@ -24,14 +24,14 @@ test('Browser class smoking tests', function(t) {
const retReady = yield b.execute('return Wechaty && Wechaty.isReady()') const retReady = yield b.execute('return Wechaty && Wechaty.isReady()')
t.equal(typeof retReady, 'boolean', 'execute Wechaty.isReady()') t.equal(typeof retReady, 'boolean', 'execute Wechaty.isReady()')
}) })
.catch((e) => { // Catch .catch((e) => { // Rejected
t.fail('co promise rejected:' + e) t.fail('co promise rejected:' + e)
}) })
.then(r => { // Finally .then(r => { // Finally
b.quit() b.quit()
t.end() t.end()
}) })
.catch(e => { // Exception .catch(e => { // Exception
t.fail('Exception:' + e) t.fail('Exception:' + e)
}) })
}) })
const co = require('co') const co = require('co')
const log = require('npmlog')
const test = require('tape') const test = require('tape')
const log = require('npmlog')
log.level = 'silly'
const PuppetWeb = require('../src/puppet-web') const PuppetWeb = require('../src/puppet-web')
const PORT = 58788 const PORT = 58788
const HEAD = true
test('PuppetWeb smoke testing', function(t) { test('PuppetWeb smoke testing', function(t) {
const pw = new PuppetWeb({head: HEAD, port: PORT}) const pw = new PuppetWeb({port: PORT})
co(function* () { co(function* () {
yield pw.init() yield pw.init()
...@@ -24,15 +25,15 @@ test('PuppetWeb smoke testing', function(t) { ...@@ -24,15 +25,15 @@ test('PuppetWeb smoke testing', function(t) {
const retCode = yield pw.proxyWechaty('getLoginStatusCode') const retCode = yield pw.proxyWechaty('getLoginStatusCode')
t.equal(typeof retCode, 'number', 'getLoginStatusCode') t.equal(typeof retCode, 'number', 'getLoginStatusCode')
}) })
.catch(e => t.fail(e)) .catch(e => t.fail(e)) // Reject
.then(r => { .then(r => { // Finally
pw.quit() pw.quit()
t.end() t.end()
}) })
}) })
test('Puppet Web server/browser communication', function(t) { test('Puppet Web server/browser communication', function(t) {
const pw = new PuppetWeb({head: HEAD, port: PORT}) const pw = new PuppetWeb({port: PORT})
co(function* () { co(function* () {
yield pw.init() yield pw.init()
...@@ -41,16 +42,11 @@ test('Puppet Web server/browser communication', function(t) { ...@@ -41,16 +42,11 @@ test('Puppet Web server/browser communication', function(t) {
const retSocket = yield dingSocket(pw.server) const retSocket = yield dingSocket(pw.server)
t.equal(retSocket, 'dong', 'dingSocket got dong') t.equal(retSocket, 'dong', 'dingSocket got dong')
}) })
.catch(e => { // Reject .catch(e => t.fail(e)) // Reject
t.fail('co promise rejected:' + e) .then(r => { // Finally
})
.then(r => { // Finally
pw.quit() pw.quit()
t.end() t.end()
}) })
.catch(e => { // Exception
log.error('TestingPuppetWeb', 'Exception:' + e)
})
return // The following is help functions only return // The following is help functions only
......
...@@ -8,9 +8,10 @@ const Browser = WebDriver.Browser ...@@ -8,9 +8,10 @@ const Browser = WebDriver.Browser
const By = WebDriver.By const By = WebDriver.By
const PuppetWebBrowser = require('../src/puppet-web-browser') const PuppetWebBrowser = require('../src/puppet-web-browser')
const PORT = 58788
test('WebDriver smoke testing', function(t) { test('WebDriver smoke testing', function(t) {
const wb = new PuppetWebBrowser({head: true}) const wb = new PuppetWebBrowser({port: PORT})
const driver = wb.getDriver() const driver = wb.getDriver()
const injectio = PuppetWebBrowser.getInjectio() const injectio = PuppetWebBrowser.getInjectio()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册