Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
.www.
wechaty
提交
34e03974
W
wechaty
项目概览
.www.
/
wechaty
与 Fork 源项目一致
Fork自
wechaty / wechaty
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
W
wechaty
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
34e03974
编写于
5月 24, 2016
作者:
Huan (李卓桓)
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
helper function: waitData to retry a promise until get right
上级
c300e011
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
204 addition
and
86 deletion
+204
-86
example/ding-dong-bot.js
example/ding-dong-bot.js
+10
-5
example/tuling123-bot.js
example/tuling123-bot.js
+19
-13
src/contact.js
src/contact.js
+23
-24
src/group.js
src/group.js
+8
-4
src/message.js
src/message.js
+7
-15
src/puppet-web-bridge.js
src/puppet-web-bridge.js
+46
-2
src/puppet-web-browser.js
src/puppet-web-browser.js
+15
-3
src/puppet-web-injectio.js
src/puppet-web-injectio.js
+5
-3
src/puppet-web-server.js
src/puppet-web-server.js
+3
-5
src/puppet-web.js
src/puppet-web.js
+11
-10
src/wechaty.js
src/wechaty.js
+2
-1
test/puppet-web-bridge-spec.js
test/puppet-web-bridge-spec.js
+55
-1
未找到文件。
example/ding-dong-bot.js
浏览文件 @
34e03974
...
...
@@ -30,18 +30,17 @@ Please wait... I'm trying to login in...
console
.
log
(
welcome
)
const
bot
=
new
Wechaty
({
head
:
true
})
bot
.
on
(
'
scan
'
,
({
url
,
code
})
=>
{
console
.
log
(
`Scan qrcode in url to login: \n
${
url
}
`
)
console
.
log
(
code
)
})
bot
.
on
(
'
login
'
,
()
=>
log
.
info
(
'
Bot
'
,
'
logined
'
))
.
on
(
'
logout
'
,
()
=>
log
.
info
(
'
Bot
'
,
'
logouted
'
))
.
on
(
'
scan
'
,
({
url
,
code
})
=>
{
console
.
log
(
`Scan qrcode in url to login:
${
code
}
\n
${
url
}
`
)
})
.
on
(
'
message
'
,
m
=>
{
m
.
ready
()
.
then
(
msg
=>
{
log
.
info
(
'
Bot
'
,
'
recv: %s
'
,
msg
)
logToFile
(
JSON
.
stringify
(
msg
.
rawObj
))
})
.
catch
(
e
=>
log
.
error
(
'
Bot
'
,
'
ready: %s
'
,
e
))
...
...
@@ -60,3 +59,9 @@ bot.init()
bot
.
quit
()
process
.
exit
(
-
1
)
})
function
logToFile
(
data
)
{
require
(
'
fs
'
).
appendFile
(
'
message.log
'
,
data
+
'
\n\n
#############################
\n\n
'
,
err
=>
{
if
(
err
)
{
log
.
error
(
'
LogToFile: %s
'
,
err
)
}
})
}
example/tuling123-bot.js
浏览文件 @
34e03974
...
...
@@ -39,21 +39,13 @@ bot
.
on
(
'
message
'
,
m
=>
{
co
(
function
*
()
{
const
msg
=
yield
m
.
ready
()
log
.
info
(
'
Bot
'
,
'
recv: %s
'
,
msg
)
if
(
m
.
group
())
{
return
if
(
m
.
group
()
&&
/Wechaty/i
.
test
(
m
.
group
().
name
()))
{
log
.
info
(
'
Bot
'
,
'
talk: %s
'
,
msg
)
talk
(
m
)
}
else
{
log
.
info
(
'
Bot
'
,
'
recv: %s
'
,
msg
)
}
const
reply
=
new
Wechaty
.
Message
()
.
set
(
'
to
'
,
m
.
get
(
'
from
'
))
const
content
=
m
.
get
(
'
content
'
)
const
{
code
,
text
}
=
yield
brain
.
ask
(
content
,
{
userid
:
msg
.
get
(
'
from
'
)})
reply
.
set
(
'
content
'
,
text
)
yield
bot
.
send
(
reply
)
log
.
info
(
'
Bot
'
,
`REPLY: {code:
${
code
}
, text:
${
text
}
}`
)
})
.
catch
(
e
=>
log
.
error
(
'
Bot
'
,
'
on message rejected: %s
'
,
e
))
})
...
...
@@ -65,3 +57,17 @@ bot.init()
process
.
exit
(
-
1
)
})
function
talk
(
m
)
{
co
(
function
*
()
{
const
fromId
=
m
.
from
().
id
const
content
=
m
.
content
()
const
{
code
,
text
}
=
yield
brain
.
ask
(
content
,
{
userid
:
fromId
})
const
minDelayTime
=
5000
const
maxDelayTime
=
15000
const
delayTime
=
Math
.
floor
(
Math
.
random
()
*
(
maxDelayTime
-
minDelayTime
))
+
minDelayTime
log
.
info
(
'
Bot
'
,
`REPLY(after
${
Math
.
floor
(
delayTime
/
1000
)}
s): {code:
${
code
}
, text:
${
text
}
}`
)
setTimeout
(
r
=>
{
bot
.
reply
(
m
,
text
)
},
delayTime
)
})
}
src/contact.js
浏览文件 @
34e03974
...
...
@@ -19,26 +19,9 @@ class Contact {
this
.
obj
=
{}
}
ready
(
contactGetter
)
{
log
.
silly
(
'
Contact
'
,
'
ready(
'
+
typeof
contactGetter
+
'
)
'
)
if
(
this
.
obj
.
id
)
{
return
Promise
.
resolve
(
this
)
}
if
(
!
contactGetter
)
{
log
.
silly
(
'
Contact
'
,
'
get contact via
'
+
Contact
.
puppet
.
constructor
.
name
)
contactGetter
=
Contact
.
puppet
.
getContact
.
bind
(
Contact
.
puppet
)
}
return
contactGetter
(
this
.
id
)
.
then
(
data
=>
{
log
.
silly
(
'
Contact
'
,
`contactGetter(
${
this
.
id
}
) resolved`
)
this
.
rawObj
=
data
this
.
obj
=
this
.
parse
(
data
)
return
this
}).
catch
(
e
=>
{
log
.
error
(
'
Contact
'
,
`contactGetter(
${
this
.
id
}
) rejected: `
,
e
)
throw
new
Error
(
'
contactGetter:
'
+
e
)
})
toString
()
{
var
name
=
this
.
obj
.
name
?
`
${
this
.
obj
.
name
}
@
${
this
.
id
}
`
:
this
.
id
return
`Contact(
${
name
}
)`
}
parse
(
rawObj
)
{
...
...
@@ -56,6 +39,26 @@ class Contact {
}
name
()
{
return
this
.
obj
.
name
}
ready
(
contactGetter
)
{
log
.
silly
(
'
Contact
'
,
'
ready(
'
+
typeof
contactGetter
+
'
)
'
)
if
(
this
.
obj
.
id
)
{
return
Promise
.
resolve
(
this
)
}
if
(
!
contactGetter
)
{
log
.
silly
(
'
Contact
'
,
'
get contact via
'
+
Contact
.
puppet
.
constructor
.
name
)
contactGetter
=
Contact
.
puppet
.
getContact
.
bind
(
Contact
.
puppet
)
}
return
contactGetter
(
this
.
id
)
.
then
(
data
=>
{
log
.
silly
(
'
Contact
'
,
`contactGetter(
${
this
.
id
}
) resolved`
)
this
.
rawObj
=
data
this
.
obj
=
this
.
parse
(
data
)
return
this
}).
catch
(
e
=>
{
log
.
error
(
'
Contact
'
,
`contactGetter(
${
this
.
id
}
) rejected: %s`
,
e
)
throw
e
})
}
dumpRaw
()
{
console
.
error
(
'
======= dump raw contact =======
'
)
Object
.
keys
(
this
.
rawObj
).
forEach
(
k
=>
console
.
error
(
`
${
k
}
:
${
this
.
rawObj
[
k
]}
`
))
...
...
@@ -65,10 +68,6 @@ class Contact {
Object
.
keys
(
this
.
obj
).
forEach
(
k
=>
console
.
error
(
`
${
k
}
:
${
this
.
obj
[
k
]}
`
))
}
toString
()
{
return
`Contact(
${
this
.
id
}
)`
}
get
(
prop
)
{
return
this
.
obj
[
prop
]
}
send
(
message
)
{
...
...
src/group.js
浏览文件 @
34e03974
...
...
@@ -19,13 +19,15 @@ class Group {
}
}
toString
()
{
return
this
.
obj
.
name
?
this
.
obj
.
name
:
this
.
id
}
toString
()
{
var
name
=
this
.
obj
.
name
?
`[
${
this
.
obj
.
name
}
]
${
this
.
id
}
`
:
this
.
id
return
`Group(
${
name
}
)`
}
ready
(
contactGetter
)
{
log
.
silly
(
'
Group
'
,
`ready(
${
contactGetter
}
)`
)
if
(
this
.
obj
.
id
)
{
return
Promise
.
resolve
(
this
)
}
if
(
this
.
obj
.
id
)
{
return
Promise
.
resolve
(
this
)
}
contactGetter
=
contactGetter
||
Group
.
puppet
.
getContact
.
bind
(
Group
.
puppet
)
return
contactGetter
(
this
.
id
)
.
then
(
data
=>
{
...
...
@@ -39,6 +41,8 @@ class Group {
})
}
name
()
{
return
this
.
obj
.
name
}
parse
(
rawObj
)
{
return
!
rawObj
?
{}
:
{
id
:
rawObj
.
UserName
...
...
src/message.js
浏览文件 @
34e03974
...
...
@@ -15,18 +15,11 @@ class Message {
constructor
(
rawObj
)
{
Message
.
counter
++
this
.
logToFile
(
JSON
.
stringify
(
rawObj
))
this
.
rawObj
=
rawObj
=
rawObj
||
{}
this
.
obj
=
this
.
parse
(
rawObj
)
this
.
id
=
this
.
obj
.
id
}
logToFile
(
data
)
{
require
(
'
fs
'
).
appendFile
(
'
message.log
'
,
data
+
'
\n\n
#############################
\n\n
'
,
err
=>
{
if
(
err
)
{
log
.
error
(
'
Message
'
,
'
logToFile:
'
+
err
)
}
})
}
// Transform rawObj to local m
parse
(
rawObj
)
{
return
{
...
...
@@ -52,9 +45,9 @@ class Message {
return
s
}
getSenderString
()
{
const
name
=
this
.
obj
.
from
.
get
(
'
name
'
)
const
name
=
this
.
obj
.
from
.
get
(
'
remark
'
)
||
this
.
obj
.
from
.
get
(
'
name
'
)
const
group
=
this
.
obj
.
group
return
'
<
'
+
name
+
(
group
?
`@
[
${
group
}
]
`
:
''
)
+
'
>
'
return
'
<
'
+
name
+
(
group
?
`@
${
group
}
`
:
''
)
+
'
>
'
}
getContentString
()
{
let
content
=
this
.
unescapeHtml
(
this
.
stripHtml
(
this
.
obj
.
content
))
...
...
@@ -74,20 +67,19 @@ class Message {
from
()
{
return
this
.
obj
.
from
}
to
()
{
return
this
.
obj
.
to
}
content
()
{
return
this
.
obj
.
content
}
group
()
{
return
this
.
obj
.
group
}
ready
()
{
return
this
.
obj
.
from
.
ready
()
// Contact from
return
this
.
obj
.
from
.
ready
()
// Contact from
.
then
(
r
=>
this
.
obj
.
to
.
ready
())
// Contact to
.
then
(
r
=>
this
.
obj
.
group
&&
this
.
obj
.
group
.
ready
())
// Group member list
.
then
(
r
=>
this
)
.
catch
(
e
=>
{
// REJECT
log
.
error
(
'
Message
'
,
'
ready() rejected:
'
+
e
)
.
then
(
r
=>
this
)
// ready return this for chain
.
catch
(
e
=>
{
// REJECTED
log
.
error
(
'
Message
'
,
'
ready() rejected:
%s
'
,
e
)
throw
new
Error
(
e
)
})
}
group
()
{
return
!!
(
this
.
obj
.
group
)
}
get
(
prop
)
{
if
(
!
prop
||
!
(
prop
in
this
.
obj
))
{
const
s
=
'
[
'
+
Object
.
keys
(
this
.
obj
).
join
(
'
,
'
)
+
'
]
'
...
...
src/puppet-web-bridge.js
浏览文件 @
34e03974
...
...
@@ -32,7 +32,50 @@ class Bridge {
getLoginQrImgUrl
()
{
return
this
.
proxyWechaty
(
'
getLoginQrImgUrl
'
)
}
getUserName
()
{
return
this
.
proxyWechaty
(
'
getUserName
'
)
}
getContact
(
id
)
{
return
this
.
proxyWechaty
(
'
getContact
'
,
id
)
}
getContact
(
id
)
{
return
this
.
waitData
(
r
=>
{
return
this
.
proxyWechaty
(
'
getContact
'
,
id
)
},
3000
)
}
/**
* Call a function repeatly untill it return a value
*
* @param <function> pfunc
* @param <number> timeout
*
*/
waitData
(
pfunc
,
timeout
)
{
log
.
silly
(
'
Bridge
'
,
'
waitData()
'
)
const
waitTime
=
50
let
totalTime
=
0
return
new
Promise
((
resolve
,
reject
)
=>
{
function
retry
()
{
log
.
silly
(
'
Bridge
'
,
'
retry()@waitData()
'
)
try
{
pfunc
().
then
(
data
=>
{
if
(
data
)
{
log
.
silly
(
'
Bridge
'
,
`waitData(
${
totalTime
}
/
${
timeout
}
) succ`
)
return
resolve
(
data
)
}
else
if
(
totalTime
>
timeout
)
{
log
.
silly
(
'
Bridge
'
,
`waitData(
${
totalTime
}
/
${
timeout
}
) timeout`
)
return
resolve
()
}
else
{
log
.
silly
(
'
Bridge
'
,
`waitData(
${
totalTime
}
/
${
timeout
}
) retry`
)
totalTime
+=
waitTime
return
setTimeout
(
retry
,
waitTime
)
}
throw
new
Error
(
'
should not run to here
'
)
})
}
catch
(
e
)
{
log
.
silly
(
'
Bridge
'
,
`waitData(
${
totalTime
}
/
${
timeout
}
) exception: %s`
,
e
)
return
reject
(
e
)
}
}
return
retry
()
})
}
send
(
toUserName
,
content
)
{
return
this
.
proxyWechaty
(
'
send
'
,
toUserName
,
content
)
}
getInjectio
()
{
...
...
@@ -54,10 +97,11 @@ class Bridge {
})
.
then
(
r
=>
{
if
(
true
===
r
)
{
log
.
verbose
(
'
Bridge
'
,
'
Wechaty.init() return:
'
+
r
)
}
else
{
throw
new
Error
(
'
Wechaty.init() return not true
'
)
}
else
{
throw
new
Error
(
'
Wechaty.init() return not true
:
'
+
r
)
}
return
r
})
}
catch
(
e
)
{
log
.
error
(
'
Bridge
'
,
'
inject() exception: %s
'
,
e
)
return
Promise
.
reject
(
'
inject exception:
'
+
e
)
}
throw
new
Error
(
'
should not run to here
'
)
...
...
src/puppet-web-browser.js
浏览文件 @
34e03974
...
...
@@ -46,7 +46,10 @@ class Browser {
initDriver
()
{
log
.
verbose
(
'
Browser
'
,
'
initDriver()
'
)
if
(
this
.
head
)
{
this
.
driver
=
new
WebDriver
.
Builder
().
forBrowser
(
'
chrome
'
).
build
()
this
.
driver
=
new
WebDriver
.
Builder
()
.
setAlertBehavior
(
'
ignore
'
)
.
forBrowser
(
'
chrome
'
)
.
build
()
}
else
{
this
.
driver
=
this
.
getPhantomJsDriver
()
}
...
...
@@ -59,6 +62,7 @@ class Browser {
const
phantomjsExe
=
require
(
'
phantomjs-prebuilt
'
).
path
// const phantomjsExe = require('phantomjs2').path
const
customPhantom
=
WebDriver
.
Capabilities
.
phantomjs
()
.
setAlertBehavior
(
'
ignore
'
)
.
set
(
'
phantomjs.binary.path
'
,
phantomjsExe
)
.
set
(
'
phantomjs.cli.args
'
,
[
'
--ignore-ssl-errors=true
'
// this help socket.io connect with localhost
...
...
@@ -95,10 +99,18 @@ class Browser {
execute
(
script
,
...
args
)
{
//log.verbose('Browser', `Browser.execute(${script})`)
if
(
!
this
.
driver
)
{
throw
new
Error
(
'
driver not found
'
)
// throw new Error('driver not found')
const
errMsg
=
'
execute() called without driver
'
log
.
verbose
(
'
Browser
'
,
errMsg
)
return
Promise
.
reject
(
errMsg
)
}
// return promise
return
this
.
driver
.
executeScript
.
apply
(
this
.
driver
,
arguments
)
try
{
return
this
.
driver
.
executeScript
.
apply
(
this
.
driver
,
arguments
)
}
catch
(
e
)
{
log
.
error
(
'
Browser
'
,
e
)
return
Promise
.
reject
(
e
)
}
}
}
...
...
src/puppet-web-injectio.js
浏览文件 @
34e03974
...
...
@@ -192,9 +192,11 @@ return (function(port) {
return
chat
.
sendMessage
(
m
)
}
function
getContact
(
id
)
{
return
Wechaty
.
glue
.
contactFactory
?
Wechaty
.
glue
.
contactFactory
.
getContact
(
id
)
:
null
if
(
Wechaty
.
glue
.
contactFactory
)
{
return
Wechaty
.
glue
.
contactFactory
.
getContact
(
id
)
}
log
(
'
contactFactory not inited
'
)
return
null
}
function
getUserName
()
{
return
Wechaty
.
glue
.
accountFactory
...
...
src/puppet-web-server.js
浏览文件 @
34e03974
...
...
@@ -100,12 +100,10 @@ class Server extends EventEmitter {
this
.
emit
(
'
connection
'
,
client
)
client
.
on
(
'
disconnect
'
,
e
=>
{
log
.
verbose
(
'
Server
'
,
'
socket.io disconnected:
'
+
e
)
/**
* 1. Browser reload / 2. Lost connection(Bad network)
*/
log
.
verbose
(
'
Server
'
,
'
socket.io disconnect: %s
'
,
e
)
// 1. Browser reload / 2. Lost connection(Bad network)
this
.
socketClient
=
null
this
.
emit
(
'
disconnect
'
,
'
server re-emit from socketio
'
)
this
.
emit
(
'
disconnect
'
,
e
)
})
client
.
on
(
'
error
'
,
e
=>
log
.
error
(
'
Server
'
,
'
socketio client error: %s
'
,
e
))
...
...
src/puppet-web.js
浏览文件 @
34e03974
...
...
@@ -137,12 +137,21 @@ class PuppetWeb extends Puppet {
}
send
(
message
)
{
const
userName
=
message
.
get
(
'
to
'
).
id
const
userName
=
message
.
to
(
).
id
const
content
=
message
.
content
()
log
.
silly
(
'
PuppetWeb
'
,
`s
end
(
${
userName
}
,
${
content
}
)`
)
log
.
silly
(
'
PuppetWeb
'
,
`s
ay
(
${
userName
}
,
${
content
}
)`
)
return
this
.
bridge
.
send
(
userName
,
content
)
}
reply
(
recvMsg
,
replyMsg
)
{
var
contact
=
recvMsg
.
group
()
if
(
!
contact
)
{
contact
=
recvMsg
.
from
()
}
const
contactId
=
contact
.
id
log
.
silly
(
'
PuppetWeb
'
,
`reply(
${
contact
}
,
${
replyMsg
}
)`
)
return
this
.
bridge
.
send
(
contactId
,
replyMsg
)
}
logout
()
{
return
this
.
bridge
.
logout
()
}
getContact
(
id
)
{
return
this
.
bridge
.
getContact
(
id
)
}
getLoginQrImgUrl
()
{
...
...
@@ -153,14 +162,6 @@ class PuppetWeb extends Puppet {
return
this
.
bridge
.
getLoginQrImgUrl
()
}
debugLoop
()
{
// XXX
this
.
bridge
.
getLoginStatusCode
().
then
((
c
)
=>
{
log
.
verbose
(
'
PuppetWeb
'
,
`login status code:
${
c
}
`
)
setTimeout
(
this
.
debugLoop
.
bind
(
this
),
3000
)
})
}
/**
* Interface Methods
*/
...
...
src/wechaty.js
浏览文件 @
34e03974
...
...
@@ -59,8 +59,9 @@ class Wechaty extends EventEmitter {
}
currentUser
()
{
return
this
.
puppet
.
currentUser
()
}
send
(
message
)
{
return
this
.
puppet
.
send
(
message
)
}
quit
()
{
return
this
.
puppet
.
quit
()
}
send
(
message
)
{
return
this
.
puppet
.
say
(
message
)
}
reply
(
message
,
reply
)
{
return
this
.
puppet
.
reply
(
message
,
reply
)
}
ding
()
{
// TODO: test through the server & browser
...
...
test/puppet-web-bridge-spec.js
浏览文件 @
34e03974
...
...
@@ -5,7 +5,61 @@ const Browser = require('../src/puppet-web-browser')
const
Bridge
=
require
(
'
../src/puppet-web-bridge
'
)
const
PORT
=
58788
test
(
'
Bridge class smoking tests
'
,
function
(
t
)
{
const
log
=
require
(
'
npmlog
'
)
// log.level = 'silly'
test
(
'
Bridge functional testing
'
,
function
(
t
)
{
const
browser
=
new
Browser
({
port
:
PORT
})
t
.
ok
(
browser
,
'
Browser instance created
'
)
const
b
=
new
Bridge
({
browser
:
browser
})
t
.
ok
(
b
,
'
Bridge instance creted
'
)
co
(
function
*
()
{
const
EXPECTED_RETURN
=
'
Okey
'
function
delayedFactory
(
timeout
)
{
const
startTime
=
Date
.
now
()
return
function
()
{
const
nowTime
=
Date
.
now
()
if
(
nowTime
-
startTime
>
timeout
)
{
return
Promise
.
resolve
(
EXPECTED_RETURN
)
}
return
Promise
.
resolve
()
}
}
yield
b
.
waitData
(
delayedFactory
(
100
),
10
)
.
then
(
r
=>
{
t
.
notOk
(
r
,
'
waitData got none when wait 10ms
'
)
})
.
catch
(
e
=>
{
t
.
fail
(
e
)
})
yield
b
.
waitData
(
delayedFactory
(
100
),
100
)
.
then
(
r
=>
{
t
.
equal
(
r
,
EXPECTED_RETURN
,
`waitData got "
${
EXPECTED_RETURN
}
" when wait 100ms`
)
})
.
catch
(
e
=>
{
t
.
fail
(
e
)
})
})
.
catch
(
e
=>
{
// REJECTED
t
.
fail
(
e
)
})
.
then
(
r
=>
{
// FINALLY
browser
.
quit
()
b
.
quit
()
t
.
end
()
})
.
catch
(
e
=>
{
// EXCEPTION
t
.
fail
(
e
)
})
})
test
(
'
Bridge smoke testing
'
,
function
(
t
)
{
const
browser
=
new
Browser
({
port
:
PORT
})
t
.
ok
(
browser
,
'
Browser instance created
'
)
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录