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

Merge branch 'master' of github.com:zixia/wechaty

......@@ -25,13 +25,13 @@ The following 9 lines of code implement a bot who reply "roger" for every messag
```javascript
const Wechaty = require('wechaty')
const wechaty = new Wechaty()
wechaty.init().on('scan', ({url, code}) => {
wechaty.on('scan', ({url, code}) => {
console.log(`Use Wechat to scan qrcode in url to login: ${code}\n${url}`)
}).on('message', m => {
!m.self() && wechaty.reply(m, 'roger') // 1. reply
.then(() => console.log(`RECV: ${m}, REPLY: "roger"`)) // 2. log message
.catch(e => console.error(e)) // 3. catch exception
})
}).init()
```
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.
......
......@@ -26,7 +26,7 @@ Please wait... I'm trying to login in...
`
console.log(welcome)
const bot = new Wechaty({ session: 'ding-dong-bot.wechaty.json' })
const bot = new Wechaty({ session: 'example.wechaty.json' })
bot
.on('login' , user => log.info('Bot', `${user.name()} logined`))
......
const Wechaty = require('..')
const bot = new Wechaty({ session: 'example.wechaty.json' })
bot
.on('scan', ({url, code}) => {
console.log(`Use Wechat to Scan QR Code in url to login: ${code}\n${url}`)
})
.on('message', m => {
console.log(`RECV: ${m}`)
if (m.type() === Wechaty.Message.Type.IMAGE) {
console.log('IMAGE url: ' + m.get('url'))
const filename = m.id + '.jpg'
console.log('IMAGE local filename: ' + filename)
var fileStream = require('fs').createWriteStream(filename)
m.readyStream()
.then(stream => stream.pipe(fileStream))
.catch(e => log.error('stream error', e))
}
})
.init()
.catch(e => console.error('bot.init() error: ' + e))
const Wechaty = require('..')
const bot = new Wechaty()
bot.init()
bot
.on('scan', ({url, code}) => {
console.log(`Use Wechat to Scan QR Code in url to login: ${code}\n${url}`)
})
......@@ -10,4 +10,5 @@ bot.init()
.then(() => console.log(`RECV: ${m}, REPLY: "roger"`)) // 2. log message
.catch(e => console.error(e)) // 3. catch exception
})
.init()
.catch(e => console.error(e))
......@@ -7,7 +7,7 @@
*
*/
const log = require('./npmlog-env')
const htmlUtil = require('./html-util')
const webUtil = require('./web-util')
class Contact {
constructor(id) {
......@@ -41,7 +41,7 @@ class Contact {
}
}
name() { return htmlUtil.plainText(this.obj.name) }
name() { return webUtil.plainText(this.obj.name) }
remark() { return this.obj.remark }
stranger() { return this.obj.stranger }
star() { return this.obj.star }
......
......@@ -6,13 +6,53 @@
* https://github.com/zixia/wechaty
*
*/
const log = require('./npmlog-env')
const co = require('co')
const log = require('./npmlog-env')
const webUtil = require('./web-util')
const Message = require('./message')
class ImageMessage extends Message {
constructor(rawObj) {
super(rawObj)
this.bridge = Message.puppet.bridge
}
ready() {
log.silly('ImageMessage', 'ready()')
const parentReady = super.ready.bind(this)
return co.call(this, function* () {
yield parentReady()
const url = yield this.getMsgImg(this.id)
this.obj.url = url
return this // IMPORTANT!
})
.catch(e => {
log.warn('ImageMessage', 'ready() exception: %s', e.message)
throw e
})
}
getMsgImg(id) {
return this.bridge.getMsgImg(id)
.catch(e => {
log.warn('ImageMessage', 'getMsgImg(%d) exception: %s', id, e.message)
throw e
})
}
readyStream() {
return this.ready()
.then(() => {
return Message.puppet.browser.checkSession()
})
.then(cookies => {
return webUtil.downloadStream(this.obj.url, cookies)
})
.catch(e => {
log.warn('ImageMessage', 'stream() exception: %s', e.message)
throw e
})
}
}
......
......@@ -11,7 +11,7 @@ const co = require('co')
const Contact = require('./contact')
const Room = require('./room')
const htmlUtil = require('./html-util')
const webUtil = require('./web-util')
const log = require('./npmlog-env')
class Message {
......@@ -54,10 +54,10 @@ class Message {
return obj
}
toString() {
return htmlUtil.plainText(this.obj.content)
return webUtil.plainText(this.obj.content)
}
toStringDigest() {
const text = htmlUtil.digestEmoji(this.obj.digest)
const text = webUtil.digestEmoji(this.obj.digest)
return '{' + this.type() + '}' + text
}
......@@ -73,7 +73,7 @@ class Message {
return '<' + name + (room ? `@${room}` : '') + '>'
}
getContentString() {
let content = htmlUtil.plainText(this.obj.content)
let content = webUtil.plainText(this.obj.content)
if (content.length > 20) { content = content.substring(0,17) + '...' }
return '{' + this.type() + '}' + content
}
......@@ -83,8 +83,9 @@ class Message {
content() { return this.obj.content }
room() { return this.obj.room }
type() { return Message.Type[this.obj.type] }
count() { return Message.counter }
type() { return this.obj.type }
typeEx() { return Message.Type[this.obj.type] }
count() { return Message.counter }
self() {
if (!this.obj.self) {
......@@ -173,4 +174,6 @@ Object.keys(Message.Type).forEach(k => {
Message.Type[v] = k // Message.Type[1] = 'TEXT'
})
Message.attach = function(puppet) { Message.puppet = puppet }
module.exports = Message
......@@ -78,8 +78,20 @@ class Bridge {
throw e
})
}
getContact(id) {
getMsgImg(id) {
return this.proxyWechaty('getMsgImg', id)
.catch(e => {
log.silly('PuppetWebBridge', 'proxyWechaty(getMsgImg, %d) exception: %s', id, e.message)
throw e
})
}
getContact(id) {
if (id!==id) { // NaN
const err = new Error('NaN! where does it come from?')
log.error('PuppetWebBridge', 'getContact(NaN): %s', err)
return Promise.reject(err)
}
const max = 35
const backoff = 500
......@@ -184,6 +196,26 @@ Object.keys(ac).filter(function(k) { return /李/.test(ac[k].NickName) }).map(fu
Object.keys(window._chatContent).filter(function (k) { return window._chatContent[k].length > 0 }).map(function (k) { return window._chatContent[k].map(function (v) {return v.MMDigestTime}) })
.web_wechat_tab_add
.web_wechat_tab_launch-chat
*
.web_wechat_tab_launch-chat
contentChatController
e.getMsgImg = function(e, t, o) {
return o && "undefined" != typeof o.MMStatus && o.MMStatus != u.MSG_SEND_STATUS_SUCC ? void 0 : u.API_webwxgetmsgimg + "?&MsgID=" + e + "&skey=" + encodeURIComponent(c.getSkey()) + (t ? "&type=" + t : "")
}
,
e.getMsgVideo = function(e) {
return u.API_webwxgetvideo + "?msgid=" + e + "&skey=" + encodeURIComponent(c.getSkey())
}
<div class="picture"
ng-init="imageInit(message,message.MMPreviewSrc || message.MMThumbSrc || getMsgImg(message.MsgId,'slave'))">
<img class="msg-img" ng-style="message.MMImgStyle" ng-click="previewImg(message)"
ng-src="/cgi-bin/mmwebwx-bin/webwxgetmsgimg?&amp;MsgID=6944236226252183282&amp;skey=%40crypt_c117402d_2b2a8c58340c8f4b0a4570cb8f11a1e8&amp;type=slave"
src="/cgi-bin/mmwebwx-bin/webwxgetmsgimg?&amp;MsgID=6944236226252183282&amp;skey=%40crypt_c117402d_2b2a8c58340c8f4b0a4570cb8f11a1e8&amp;type=slave"
style="height: 100px; width: 75px;">
*
*/
......@@ -54,6 +54,7 @@ return (function(port) {
, getContact: getContact
, getUserName: getUserName
, getMsgImg: getMsgImg
}
window.Wechaty = Wechaty
......@@ -141,6 +142,17 @@ return (function(port) {
var appScope = angular.element('[ng-controller="appController"]').scope()
var loginScope = angular.element('[ng-controller="loginController"]').scope()
/**
* generate $scope with a contoller (as it is not assigned in html staticly)
* https://github.com/angular/angular.js/blob/a4e60cb6970d8b6fa9e0af4b9f881ee3ba7fdc99/test/ng/controllerSpec.js#L24
*/
var contentChatScope = rootScope.$new()
injector.get('$controller')('contentChatController', {$scope: contentChatScope })
/*
s =
*/
// get all we need from wx in browser(angularjs)
Wechaty.glue = {
injector: injector
......@@ -154,6 +166,8 @@ return (function(port) {
, rootScope: rootScope
, appScope: appScope
, loginScope: loginScope
, contentChatScope: contentChatScope
}
}
......@@ -277,17 +291,19 @@ return (function(port) {
clog('Wechaty.vars.socket not ready')
return setTimeout(emit, 1000) // resent eventsBuf after 1000ms
}
if (Wechaty.vars.eventsBuf.length) {
clog('Wechaty.vars.eventsBuf has ' + Wechaty.vars.eventsBuf.length + ' unsend events')
var bufLen = Wechaty.vars.eventsBuf.length
if (bufLen) {
if (bufLen > 1) { clog('Wechaty.vars.eventsBuf has ' + bufLen + ' unsend events') }
while (Wechaty.vars.eventsBuf.length) {
var eventData = Wechaty.vars.eventsBuf.pop()
if (eventData && eventData.map && eventData.length===2) {
clog('emiting ' + eventData[0])
Wechaty.vars.socket.emit(eventData[0], eventData[1])
} else {
log('Wechaty.emit() got invalid eventData: ' + eventData[0] + ', ' + eventData[1] + ', length: ' + eventData.length)
}
} else { clog('Wechaty.emit() got invalid eventData: ' + eventData[0] + ', ' + eventData[1] + ', length: ' + eventData.length) }
}
clog('Wechaty.vars.eventsBuf all sent')
if (bufLen > 1) { clog('Wechaty.vars.eventsBuf all sent') }
}
}
......@@ -340,4 +356,9 @@ return (function(port) {
i.parentNode.removeChild(i)
}
function getMsgImg(id) {
var location = window.location.href.replace(/\/$/, '')
var path = Wechaty.glue.contentChatScope.getMsgImg(id)
return location + path
}
}.apply(window, arguments))
......@@ -23,10 +23,12 @@ const co = require('co')
const log = require('./npmlog-env')
const Puppet = require('./puppet')
const Message = require('./message')
const Contact = require('./contact')
const Room = require('./room')
const Message = require('./message')
const ImageMessage = require('./message-image')
const Server = require('./puppet-web-server')
const Browser = require('./puppet-web-browser')
const Bridge = require('./puppet-web-bridge')
......@@ -110,6 +112,7 @@ class PuppetWeb extends Puppet {
log.verbose('PuppetWeb', 'initAttach()')
Contact.attach(puppet)
Room.attach(puppet)
Message.attach(puppet)
return Promise.resolve(!!puppet)
}
initBrowser() {
......@@ -389,7 +392,20 @@ class PuppetWeb extends Puppet {
}
}
onServerMessage(data) {
const m = new Message(data)
let m
// log.warn('PuppetWeb', 'MsgType: %s', data.MsgType)
switch (data.MsgType) {
case Message.Type.IMAGE:
// log.verbose('PuppetWeb', 'onServerMessage() IMAGE message')
m = new ImageMessage(data)
break;
case 'TEXT':
default:
m = new Message(data)
break;
}
if (this.user) {
m.set('self', this.user.id)
} else {
......@@ -399,6 +415,10 @@ class PuppetWeb extends Puppet {
.then(() => this.emit('message', m))
.catch(e => {
log.error('PuppetWeb', 'onServerMessage() message ready exception: %s', e)
/**
* FIXME: add retry here...
* setTimeout(onServerMessage.bind(this, data, ++attempt), 1000)
*/
})
}
......
......@@ -7,7 +7,7 @@
*
*/
const log = require('./npmlog-env')
const htmlUtil = require('./html-util')
const webUtil = require('./web-util')
class Room {
constructor(id) {
......@@ -46,7 +46,7 @@ class Room {
})
}
name() { return htmlUtil.plainText(this.obj.name) }
name() { return webUtil.plainText(this.obj.name) }
get(prop) { return this.obj[prop] }
parse(rawObj) {
......
const http = require('http')
const log = require('./npmlog-env')
const HtmlUtil = {
stripHtml: stripHtml
, unescapeHtml: unescapeHtml
, digestEmoji: digestEmoji
, plainText: plainText
, downloadStream: downloadStream
}
function stripHtml(html) {
......@@ -39,4 +42,38 @@ function plainText(html) {
)
)
}
module.exports = HtmlUtil
\ No newline at end of file
function downloadStream(url, cookies) {
// const myurl = 'http://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetmsgimg?&MsgID=3080011908135131569&skey=%40crypt_c117402d_53a58f8fbb21978167a3fc7d3be7f8c9'
url = url.replace(/^https/i, 'http') // https not supported by nodejs http module?
const options = require('url').parse(url)
options.headers = {
Accept: 'image/webp,image/*,*/*;q=0.8'
, 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'
, Referer: 'https://wx.qq.com/'
, 'Accept-Encoding': 'gzip, deflate, sdch'
, 'Accept-Language': 'zh-CN,zh;q=0.8'
}
options.agent = http.globalAgent
// 'pgv_pvi=6639183872; pgv_si=s8359147520; webwxuvid=747895d9dac5a25dd3a78175a5e931d879e026cacaf3ac06de0bd5f071470e7182fa36f7f1f0477ae5ee9266f741999a; mm_lang=zh_CN; MM_WX_NOTIFY_STATE=1; MM_WX_SOUND_STATE=1; wxloadtime=1465928826_expired; wxpluginkey=1465901102; wxuin=1211516682; wxsid=zMT7Gb24aTQzB1rA; webwx_data_ticket=gSeBbuhX+0kFdkXbgeQwr6Ck'
options.headers.Cookie = cookies.map(c => `${c.name}=${c.value}`).join('; ')
// log.verbose('WebUtil', 'Cookie: %s', options.headers.Cookie)
return new Promise((resolve, reject) => {
req = http.request(options, (res) => {
// console.log(`STATUS: ${res.statusCode}`);
// console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
// res.setEncoding('utf8');
resolve(res)
})
req.on('error', (e) => {
log.warn('WebUtil', `downloadStream() problem with request: ${e.message}`)
})
req.end()
})
}
module.exports = HtmlUtil
......@@ -62,7 +62,6 @@ class Wechaty extends EventEmitter {
this.inited = true
return this // for chaining
})
.catch(e => {
log.error('Wechaty', 'init() exception: %s', e.message)
......
......@@ -3,7 +3,7 @@
const test = require('tap').test
const log = require('../src/npmlog-env')
const htmlUtil = require('../src/html-util')
const webUtil = require('../src/web-util')
test('HtmlUtil smoking test', function(t) {
const HTML_BEFORE_STRIP = 'Outer<html>Inner</html>'
......@@ -24,17 +24,17 @@ test('HtmlUtil smoking test', function(t) {
const PLAIN_BEFORE = '&amp;<html>&amp;</html>&amp;<img class="emoji emoji1f4a4" text="[流汗]_web" src="/zh_CN/htmledition/v2/images/spacer.gif" />'
const PLAIN_AFTER = '&&&[流汗]'
const strippedHtml = htmlUtil.stripHtml(HTML_BEFORE_STRIP)
const strippedHtml = webUtil.stripHtml(HTML_BEFORE_STRIP)
t.equal(strippedHtml, HTML_AFTER_STRIP, 'should strip html as expected')
const unescapedHtml = htmlUtil.unescapeHtml(HTML_BEFORE_UNESCAPE)
const unescapedHtml = webUtil.unescapeHtml(HTML_BEFORE_UNESCAPE)
t.equal(unescapedHtml, HTML_AFTER_UNESCAPE, 'should unescape html as expected')
for (let i=0; i<EMOJI_BEFORE_DIGEST.length; i++) {
const emojiDigest = htmlUtil.digestEmoji(EMOJI_BEFORE_DIGEST[i])
const emojiDigest = webUtil.digestEmoji(EMOJI_BEFORE_DIGEST[i])
t.equal(emojiDigest, EMOJI_AFTER_DIGEST[i], 'should digest emoji string ' + i + ' as expected')
}
const plainText = htmlUtil.plainText(PLAIN_BEFORE)
const plainText = webUtil.plainText(PLAIN_BEFORE)
t.equal(plainText, PLAIN_AFTER, 'should convert plain text as expected')
t.end()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册