Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
.www.
wechaty
提交
ddd1288a
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,发现更多精彩内容 >>
提交
ddd1288a
编写于
6月 02, 2018
作者:
Huan (李卓桓)
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
New Puppet: PuppetWechat4u worked with ding-dong-bot! (#69)
上级
07008dff
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
189 addition
and
82 deletion
+189
-82
src/message.ts
src/message.ts
+1
-0
src/puppet-puppeteer/web-schemas.ts
src/puppet-puppeteer/web-schemas.ts
+1
-0
src/puppet-wechat4u/puppet-wechat4u.ts
src/puppet-wechat4u/puppet-wechat4u.ts
+165
-80
src/puppet-wechat4u/typings.d.ts
src/puppet-wechat4u/typings.d.ts
+20
-0
src/puppet/puppet.ts
src/puppet/puppet.ts
+1
-1
src/wechaty.ts
src/wechaty.ts
+1
-1
未找到文件。
src/message.ts
浏览文件 @
ddd1288a
...
...
@@ -191,6 +191,7 @@ export class Message extends Accessory implements Sayable {
const
fromId
=
this
.
payload
.
fromId
if
(
!
fromId
)
{
console
.
log
(
this
.
payload
)
throw
new
Error
(
'
no from
'
)
}
...
...
src/puppet-puppeteer/web-schemas.ts
浏览文件 @
ddd1288a
...
...
@@ -57,6 +57,7 @@ export interface WebMessageRawPayload {
MMDigest
:
string
,
MMDisplayTime
:
number
,
// Javascript timestamp of milliseconds
CreateTime
:
number
,
/**
* MsgType == MSGTYPE_APP && message.AppMsgType == CONF.APPMSGTYPE_URL
...
...
src/puppet-wechat4u/puppet-wechat4u.ts
浏览文件 @
ddd1288a
...
...
@@ -16,8 +16,6 @@
* limitations under the License.
*
*/
// import * as path from 'path'
import
*
as
LRU
from
'
lru-cache
'
import
{
...
...
@@ -25,7 +23,9 @@ import {
}
from
'
file-box
'
// tslint:disable-next-line
const
Wechat4u
=
require
(
'
wechat4u
'
)
import
*
as
Wechat4u
from
'
wechat4u
'
import
{
Misc
}
from
'
../misc
'
import
{
MessagePayload
,
...
...
@@ -37,6 +37,7 @@ import {
FriendRequestPayload
,
FriendRequestPayloadReceive
,
FriendRequestPayloadConfirm
,
FriendRequestType
,
RoomPayload
,
...
...
@@ -101,8 +102,7 @@ export class PuppetWechat4u extends Puppet {
private
scanQrCode
?:
string
public
readonly
cacheWechat4uMessageRawPayload
:
LRU
.
Cache
<
string
,
WebMessageRawPayload
>
public
readonly
cacheWechat4uFriendRequestRawPayload
:
LRU
.
Cache
<
string
,
WebMessageRawPayload
>
public
readonly
cacheMessageRawPayload
:
LRU
.
Cache
<
string
,
WebMessageRawPayload
>
constructor
(
public
options
:
PuppetOptions
,
...
...
@@ -110,7 +110,7 @@ export class PuppetWechat4u extends Puppet {
super
(
options
)
const
lruOptions
:
LRU
.
Options
=
{
max
:
1000
,
max
:
1000
0
,
// length: function (n) { return n * 2},
dispose
:
function
(
key
:
string
,
val
:
Object
)
{
log
.
silly
(
'
Puppet
'
,
'
constructor() lruOptions.dispose(%s, %s)
'
,
key
,
JSON
.
stringify
(
val
))
...
...
@@ -118,9 +118,7 @@ export class PuppetWechat4u extends Puppet {
maxAge
:
1000
*
60
*
60
,
}
this
.
cacheWechat4uMessageRawPayload
=
new
LRU
<
string
,
WebMessageRawPayload
>
(
lruOptions
)
this
.
cacheWechat4uFriendRequestRawPayload
=
new
LRU
<
string
,
WebMessageRawPayload
>
(
lruOptions
)
this
.
cacheMessageRawPayload
=
new
LRU
<
string
,
WebMessageRawPayload
>
(
lruOptions
)
}
public
async
start
():
Promise
<
void
>
{
...
...
@@ -135,15 +133,15 @@ export class PuppetWechat4u extends Puppet {
this
.
wechat4u
=
new
Wechat4u
()
}
this
.
initHookEvents
(
this
.
wechat4u
)
if
(
this
.
wechat4u
.
PROP
.
uin
)
{
// 存在登录数据时,可以随时调用restart进行重启
this
.
wechat4u
.
restart
()
await
this
.
wechat4u
.
restart
()
}
else
{
this
.
wechat4u
.
start
()
await
this
.
wechat4u
.
start
()
}
this
.
initHookEvents
(
this
.
wechat4u
)
// await some tasks...
this
.
state
.
on
(
true
)
...
...
@@ -156,13 +154,13 @@ export class PuppetWechat4u extends Puppet {
*/
this
.
wechat4u
.
on
(
'
uuid
'
,
(
uuid
:
string
)
=>
{
this
.
scanQrCode
=
'
https://login.weixin.qq.com/l/
'
+
uuid
this
.
emit
(
'
scan
'
,
this
.
scanQrCode
,
20
0
)
this
.
emit
(
'
scan
'
,
this
.
scanQrCode
,
0
)
})
/**
* 登录用户头像事件,手机扫描后可以得到登录用户头像的Data URL
*/
wechat4u
.
on
(
'
user-avatar
'
,
(
avatarDataUrl
:
string
)
=>
{
this
.
emit
(
'
scan
'
,
this
.
scanQrCode
||
''
,
408
,
avatarDataUrl
)
this
.
emit
(
'
scan
'
,
this
.
scanQrCode
||
''
,
200
,
avatarDataUrl
)
})
/**
* 登录成功事件
...
...
@@ -177,22 +175,27 @@ export class PuppetWechat4u extends Puppet {
this
.
login
(
userId
)
// 保存数据,将数据序列化之后保存到任意位置
await
this
.
options
.
memory
.
set
(
SYNC_DATA_SLOT
,
wechat4u
.
botData
)
await
this
.
options
.
memory
.
save
()
})
/**
* 登出成功事件
*/
wechat4u
.
on
(
'
logout
'
,
async
()
=>
{
this
.
logout
()
if
(
this
.
logonoff
())
{
this
.
logout
()
}
// 清除数据
await
this
.
options
.
memory
.
delete
(
SYNC_DATA_SLOT
)
await
this
.
options
.
memory
.
save
()
})
/**
* 联系人更新事件,参数为被更新的联系人列表
*/
wechat4u
.
on
(
'
contacts-updated
'
,
(
contacts
:
any
[])
=>
{
// TODO: save them for the future usage
console
.
log
(
contacts
)
console
.
log
(
'
联系人数量:
'
,
Object
.
keys
(
wechat4u
.
contacts
).
length
)
wechat4u
.
on
(
'
contacts-updated
'
,
(
contacts
:
WebContactRawPayload
[])
=>
{
// Just for memory
return
contacts
// console.log('contacts.length: ', contacts[0])
// console.log('联系人数量:', Object.keys(wechat4u.contacts).length)
})
/**
* 错误事件,参数一般为Error对象
...
...
@@ -206,15 +209,33 @@ export class PuppetWechat4u extends Puppet {
*/
wechat4u
.
on
(
'
message
'
,
(
msg
:
WebMessageRawPayload
)
=>
{
this
.
cacheWechat4uMessageRawPayload
.
set
(
msg
.
MsgId
,
msg
)
if
(
!
msg
.
MsgId
)
{
console
.
log
(
msg
)
throw
new
Error
(
'
no id
'
)
}
this
.
cacheMessageRawPayload
.
set
(
msg
.
MsgId
,
msg
)
this
.
emit
(
'
message
'
,
msg
.
MsgId
)
switch
(
msg
.
MsgType
)
{
if
(
msg
.
MsgType
===
wechat4u
.
CONF
.
MSGTYPE_VERIFYMSG
)
{
this
.
cacheWechat4uFriendRequestRawPayload
.
set
(
msg
.
MsgId
,
msg
)
this
.
emit
(
'
friend
'
,
msg
.
MsgId
)
}
case
WebMessageType
.
STATUSNOTIFY
:
// Skip this internal type
break
case
WebMessageType
.
VERIFYMSG
:
this
.
emit
(
'
friend
'
,
msg
.
MsgId
)
break
case
WebMessageType
.
SYS
:
if
(
this
.
isFriendConfirm
(
msg
.
Content
))
{
this
.
emit
(
'
friend
'
,
msg
.
MsgId
)
}
this
.
emit
(
'
message
'
,
msg
.
MsgId
)
break
default
:
this
.
emit
(
'
message
'
,
msg
.
MsgId
)
break
}
/**
* 获取消息时间
*/
...
...
@@ -224,10 +245,6 @@ export class PuppetWechat4u extends Puppet {
*/
// console.log(wechat4u.contacts[msg.FromUserName].getDisplayName())
})
wechat4u
.
on
(
'
logout
'
,
()
=>
{
this
.
logout
()
})
}
public
async
stop
():
Promise
<
void
>
{
...
...
@@ -305,15 +322,22 @@ export class PuppetWechat4u extends Puppet {
}
public
async
contactRawPayload
(
id
:
string
):
Promise
<
WebContactRawPayload
>
{
log
.
verbose
(
'
PuppetWechat4u
'
,
'
contactRawPayload(%s)
'
,
id
)
log
.
verbose
(
'
PuppetWechat4u
'
,
'
contactRawPayload(%s) with contacts.length=%d
'
,
id
,
Object
.
keys
(
this
.
wechat4u
.
contacts
).
length
,
)
const
rawPayload
:
WebContactRawPayload
=
this
.
wechat4u
.
contacts
[
id
]
const
rawPayload
:
WebContactRawPayload
=
await
Misc
.
retry
<
WebContactRawPayload
>
((
retry
,
attempt
)
=>
{
log
.
verbose
(
'
PuppetWechat4u
'
,
'
contactRawPayload(%s) retry() attempt=%d
'
,
id
,
attempt
)
if
(
!
rawPayload
)
{
throw
new
Error
(
'
no rawPayload
'
)
}
if
(
id
in
this
.
wechat4u
.
contacts
)
{
return
this
.
wechat4u
.
contacts
[
id
]
}
retry
(
new
Error
(
'
no this.wechat4u.contacts[
'
+
id
+
'
]
'
))
})
return
rawPayload
}
public
async
contactRawPayloadParser
(
...
...
@@ -448,7 +472,7 @@ export class PuppetWechat4u extends Puppet {
public
async
messageRawPayload
(
id
:
string
):
Promise
<
WebMessageRawPayload
>
{
log
.
verbose
(
'
PuppetWechat4u
'
,
'
messageRawPayload(%s)
'
,
id
)
const
rawPayload
=
this
.
cache
Wechat4u
MessageRawPayload
.
get
(
id
)
const
rawPayload
=
this
.
cacheMessageRawPayload
.
get
(
id
)
if
(
!
rawPayload
)
{
throw
new
Error
(
'
id not found
'
)
...
...
@@ -461,33 +485,59 @@ export class PuppetWechat4u extends Puppet {
):
Promise
<
MessagePayload
>
{
log
.
verbose
(
'
PuppetPuppeteer
'
,
'
messageRawPayloadParser(%s) @ %s
'
,
rawPayload
,
this
)
console
.
log
(
rawPayload
)
const
id
=
rawPayload
.
MsgId
const
fromId
=
rawPayload
.
MMActualSender
// MMPeerUserName
const
text
:
string
=
rawPayload
.
MMActualContent
// Content has @id prefix added by wx
const
timestamp
:
number
=
rawPayload
.
MMDisplayTime
// Javascript timestamp of milliseconds
const
text
:
string
=
rawPayload
.
Content
.
replace
(
/^
\n
/
,
''
)
const
timestamp
:
number
=
rawPayload
.
CreateTime
const
filename
:
undefined
|
string
=
this
.
filename
(
rawPayload
)
||
undefined
const
toId
=
rawPayload
.
ToUserName
let
roomId
:
undefined
|
string
let
toId
:
undefined
|
string
let
roomId
:
undefined
|
string
=
undefined
let
fromId
=
rawPayload
.
FromUserName
// FIXME: has there any better method to know the room ID?
if
(
rawPayload
.
MMIsChatRoom
)
{
if
(
/^@@/
.
test
(
rawPayload
.
FromUserName
))
{
roomId
=
rawPayload
.
FromUserName
// MMPeerUserName always eq FromUserName ?
}
else
if
(
/^@@/
.
test
(
rawPayload
.
ToUserName
))
{
roomId
=
rawPayload
.
ToUserName
}
else
{
throw
new
Error
(
'
parse found a room message, but neither FromUserName nor ToUserName is a room(/^@@/)
'
)
}
/**
* Check for the ChatRoom
*
* { MsgId: '7445285040940022284',
* FromUserName:
* '@@2820dea1c91c9f65b25cead37cd81d4fcd15c1fef052e29668b2dc6897a8093f',
* ToUserName:
* '@06ddf0d988fcfe903207835cfb636356525231459b0361649813bebb2836d225',
* MsgType: 1,
* Content: '@c9af79da3582391bff5f291108d987e7:\n说的就是我',
* Status: 3,
* ...
* }
*
* { MsgId: '2311479263190931912',
* FromUserName:
* '@@b2829390b8a0f4613cee9763322274db18ad76498b5fe07dd1b3699e423e869a',
* ToUserName:
* '@06ddf0d988fcfe903207835cfb636356525231459b0361649813bebb2836d225',
* MsgType: 1,
* Content: '高阳:\n我是说错误上报的库',,
*/
if
(
/^@@/
.
test
(
fromId
))
{
roomId
=
rawPayload
.
FromUserName
// console.log('rawPayload.FromUserName: ', rawPayload.FromUserName)
// console.log('rawPayload.ToUserName: ', rawPayload.ToUserName)
// console.log('rawPayload.MMPeerUserName: ', rawPayload.MMPeerUserName)
}
const
header
=
rawPayload
.
Content
.
split
(
'
\n
'
)[
0
]
const
matches
=
header
.
match
(
/^
(
.+
)
:$/
)
if
(
!
matches
)
{
throw
new
Error
(
'
no matches
'
)
}
if
(
rawPayload
.
ToUserName
)
{
if
(
!
/^@@/
.
test
(
rawPayload
.
ToUserName
))
{
// if a message in room without any specific receiver, then it will set to be `undefined`
toId
=
rawPayload
.
ToUserName
const
idOrName
=
matches
[
1
]
if
(
this
.
wechat4u
.
contacts
[
idOrName
])
{
fromId
=
matches
[
1
]
}
else
{
const
memberContactList
=
await
this
.
roomMemberSearch
(
roomId
,
idOrName
)
if
(
memberContactList
.
length
<=
0
)
{
throw
new
Error
(
'
from not found
'
)
}
if
(
memberContactList
.
length
>
1
)
{
log
.
warn
(
'
PuppetWechat4u
'
,
'
messageRawPayloadParser() found more than one possible fromId, use the first one.
'
)
}
fromId
=
memberContactList
[
0
]
}
}
...
...
@@ -539,6 +589,11 @@ export class PuppetWechat4u extends Puppet {
* 发送文本消息,可以包含emoji(😒)和QQ表情([坏笑])
*/
await
this
.
wechat4u
.
sendMsg
(
text
,
id
)
/**
* { BaseResponse: { Ret: 0, ErrMsg: '' },
* MsgID: '830582407297708303',
* LocalID: '15279119663740094' }
*/
}
public
async
messageSendFile
(
...
...
@@ -573,7 +628,6 @@ export class PuppetWechat4u extends Puppet {
file
:
await
file
.
toStream
(),
filename
:
file
.
name
,
},
id
)
}
public
async
messageForward
(
...
...
@@ -612,11 +666,15 @@ export class PuppetWechat4u extends Puppet {
):
Promise
<
WebRoomRawPayload
>
{
log
.
verbose
(
'
PuppetWechat4u
'
,
'
roomRawPayload(%s)
'
,
id
)
const
rawPayload
:
WebRoomRawPayload
=
this
.
wechat4u
.
contacts
[
id
]
const
rawPayload
:
WebRoomRawPayload
=
await
Misc
.
retry
<
WebRoomRawPayload
>
((
retry
,
attempt
)
=>
{
log
.
verbose
(
'
PuppetWechat4u
'
,
'
contactRawPayload(%s) retry() attempt=%d
'
,
id
,
attempt
)
if
(
!
rawPayload
)
{
throw
new
Error
(
'
no rawPayload
'
)
}
if
(
!
this
.
wechat4u
.
contacts
[
id
])
{
retry
(
new
Error
(
'
no this.wechat4u.contacts[
'
+
id
+
'
]
'
))
}
return
this
.
wechat4u
.
contacts
[
id
]
})
return
rawPayload
}
...
...
@@ -732,8 +790,7 @@ export class PuppetWechat4u extends Puppet {
public
async
friendRequestRawPayload
(
id
:
string
)
:
Promise
<
any
>
{
log
.
verbose
(
'
PuppetWechat4u
'
,
'
friendRequestRawPayload(%s)
'
,
id
)
const
rawPayload
=
this
.
cacheWechat4uFriendRequestRawPayload
.
get
(
id
)
const
rawPayload
=
this
.
cacheMessageRawPayload
.
get
(
id
)
if
(
!
rawPayload
)
{
throw
new
Error
(
'
no rawPayload
'
)
}
...
...
@@ -744,26 +801,37 @@ export class PuppetWechat4u extends Puppet {
public
async
friendRequestRawPayloadParser
(
rawPayload
:
any
)
:
Promise
<
FriendRequestPayload
>
{
log
.
verbose
(
'
PuppetWechat4u
'
,
'
friendRequestRawPayloadParser(%s)
'
,
rawPayload
)
const
recommendInfo
:
WebRecomendInfo
=
rawPayload
.
RecommendInfo
switch
(
rawPayload
.
MsgType
)
{
case
WebMessageType
.
VERIFYMSG
:
if
(
!
rawPayload
.
RecommendInfo
)
{
throw
new
Error
(
'
no RecommendInfo
'
)
}
const
recommendInfo
:
WebRecomendInfo
=
rawPayload
.
RecommendInfo
if
(
!
recommendInfo
)
{
throw
new
Error
(
'
no recommendInfo
'
)
}
if
(
!
recommendInfo
)
{
throw
new
Error
(
'
no recommendInfo
'
)
}
const
payloadReceive
:
FriendRequestPayloadReceive
=
{
id
:
rawPayload
.
MsgId
,
contactId
:
recommendInfo
.
UserName
,
hello
:
recommendInfo
.
Content
,
ticket
:
recommendInfo
.
Ticket
,
type
:
FriendRequestType
.
Receive
,
}
return
payloadReceive
const
contactId
=
recommendInfo
.
UserName
const
hello
=
recommendInfo
.
Content
const
ticket
=
recommendInfo
.
Ticket
const
type
=
FriendRequestType
.
Receive
const
id
=
rawPayload
.
MsgId
case
WebMessageType
.
SYS
:
const
payloadConfirm
:
FriendRequestPayloadConfirm
=
{
id
:
rawPayload
.
MsgId
,
contactId
:
rawPayload
.
FromUserName
,
type
:
FriendRequestType
.
Confirm
,
}
return
payloadConfirm
const
payloadReceive
:
FriendRequestPayloadReceive
=
{
id
,
contactId
,
hello
,
ticket
,
type
,
default
:
throw
new
Error
(
'
not supported friend request message raw payload
'
)
}
return
payloadReceive
}
public
ding
(
data
?:
any
):
Promise
<
string
>
{
...
...
@@ -888,6 +956,23 @@ export class PuppetWechat4u extends Puppet {
}
}
private
isFriendConfirm
(
text
:
string
,
):
boolean
{
const
friendConfirmRegexpList
=
[
/^You have added
(
.+
)
as your WeChat contact. Start chatting!$/
,
/^你已添加了
(
.+
)
,现在可以开始聊天了。$/
,
/^
(
.+
)
just added you to his
\/
her contacts list. Send a message to him
\/
her now!$/
,
/^
(
.+
)
刚刚把你添加到通讯录,现在可以开始聊天了。$/
,
]
let
found
=
false
friendConfirmRegexpList
.
some
(
re
=>
!!
(
found
=
re
.
test
(
text
)))
return
found
}
}
export
default
PuppetWechat4u
src/puppet-wechat4u/typings.d.ts
0 → 100644
浏览文件 @
ddd1288a
/**
* June 2018, Huan: Learned from https://github.com/krisk/Fuse/pull/129
*/
declare
module
"
wechat4u
"
{
export
=
Wechat4u
export
as
namespace
Wechat4u
declare
class
Wechat4u
{
constructor
(
options
?:
Wechat4u
.
FuseOptions
)
contacts
:
WebContactRawPayload
search
<
T
>
(
pattern
:
string
):
T
[]
search
(
pattern
:
string
):
any
[]
}
declare
namespace
Wechat4u
{
export
interface
Wechat4uOptions
{
id
?:
string
}
}
}
src/puppet/puppet.ts
浏览文件 @
ddd1288a
...
...
@@ -597,7 +597,7 @@ export abstract class Puppet extends EventEmitter implements Sayable {
roomId
:
string
,
query
:
string
|
RoomMemberQueryFilter
,
):
Promise
<
string
[]
>
{
log
.
verbose
(
'
Puppet
'
,
'
roomMember(%s, %s)
'
,
roomId
,
JSON
.
stringify
(
query
))
log
.
verbose
(
'
Puppet
'
,
'
roomMember
Search
(%s, %s)
'
,
roomId
,
JSON
.
stringify
(
query
))
/**
* 1. for Text Query
...
...
src/wechaty.ts
浏览文件 @
ddd1288a
...
...
@@ -465,7 +465,7 @@ export class Wechaty extends Accessory implements Sayable {
log
.
verbose
(
'
Wechaty
'
,
'
initPuppetResolver(%s)
'
,
puppet
)
if
(
!
puppet
)
{
log
.
info
(
'
Wechaty
'
,
'
initPuppet() using
default
puppet: %s
'
,
config
.
puppet
)
log
.
info
(
'
Wechaty
'
,
'
initPuppet() using puppet: %s
'
,
config
.
puppet
)
puppet
=
config
.
puppet
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录