Skip to content

Commit

Permalink
add FriendRequest function (#1252 #1254)
Browse files Browse the repository at this point in the history
  • Loading branch information
huan committed Jun 9, 2018
1 parent 2da8794 commit b488cfb
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 42 deletions.
7 changes: 4 additions & 3 deletions src/puppet-padchat/padchat-rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,8 @@ export class PadchatRpc extends EventEmitter {
// JSON.stringify(payload).length,
// )

// console.log('server payload:', payload)
// XXX
console.log('server payload:', payload)

if (payload.type === PadchatPayloadType.Logout) {
// {"type":-1,"msg":"掉线了"}
Expand Down Expand Up @@ -750,8 +751,8 @@ export class PadchatRpc extends EventEmitter {
// 30 -通过二维码方式
public async WXAddUser(strangerV1: string, strangerV2: string, type: string, verify: string): Promise<any> {
// TODO:
type = '14'
verify = 'hello'
// type = '14'
// verify = 'hello'
const result = await this.rpcCall('WXAddUser', strangerV1, strangerV2, type, verify)
log.silly('PadchatRpc', 'WXAddUser result: %s', JSON.stringify(result))
return result
Expand Down
55 changes: 53 additions & 2 deletions src/puppet-padchat/padchat-schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ export interface PadchatContactPayload {
*/
msg_type? : PadchatContactMsgType,
continue? : PadchatContinue,
ticket? : string,
uin? : number,

big_head : string, // "http://wx.qlogo.cn/mmhead/ver_1/xfCMmibHH74xGLoyeDFJadrZXX3eOEznPefiaCa3iczxZGMwPtDuSbRQKx3Xdm18un303mf0NFia3USY2nO2VEYILw/0",
Expand All @@ -133,7 +132,8 @@ export interface PadchatContactPayload {
// "http://wx.qlogo.cn/mmhead/ver_1/xfCMmibHH74xGLoyeDFJadrZXX3eOEznPefiaCa3iczxZGMwPtDuSbRQKx3Xdm18un303mf0NFia3USY2nO2VEYILw/132",
small_head : string,
status : PadchatContactRoomStatus, // 1 when use WXSyncContact, 0 when use WXGetContact
stranger : string, // "v1_0468f2cd3f0efe7ca2589d57c3f9ba952a3789e41b6e78ee00ed53d1e6096b88@stranger",
stranger? : string, // 用户v1码,从未加过好友则为空 "v1_0468f2cd3f0efe7ca2589d57c3f9ba952a3789e41b6e78ee00ed53d1e6096b88@stranger"
ticket? : string, // 用户v2码,如果非空则为单向好友(非对方好友) 'v2_xxx@stranger'
user_name : string, // "mengjunjun001" | "qq512436430" Unique name

message? : string,
Expand Down Expand Up @@ -392,3 +392,54 @@ export interface PadchatRoomMemberListPayload {
status : PadchatRoomMemberStatus, // number, // 0,
user_name : string, // '6350854677@chatroom'
}

// xml2js.parseString(str.replace(/\+/g, ' '), (err, data) => console.log(data))
// { msg:
// { '$':
// { fromusername: 'lizhuohuan',
// encryptusername:
// 'v1_cf269def9b946093f9d131a5e733ba169351013c95e46a860cddecaf485c4b10@stranger',
// fromnickname: '李卓桓',
// content: 'xixixi',
// fullpy: 'lizhuohuan',
// shortpy: 'LZH',
// imagestatus: '3',
// scene: '6',
// country: 'CN',
// province: 'Beijing',
// city: 'Haidian',
// sign: 'PreAngel投资人。水木清华BBS站长。投资人中最会飞的AI程序员。',
// percard: '1',
// sex: '1',
// alias: '',
// weibo: '',
// weibonickname: '',
// albumflag: '0',
// albumstyle: '0',
// albumbgimgid: '913943270785024_913943270785024',
// snsflag: '177',
// snsbgimgid:
// 'http://shmmsns.qpic.cn/mmsns/NoFChqEQomEyhyNjzExH3v78BHSVmIzHBIdOECg9jgcTpRNwThgXJicCsGicI6Kib4xLETc2PuKwhM/0',
// snsbgobjectid: '12683064081608282338',
// mhash: 'd98b28f4cb1708bb584f3e66078e0a0d',
// mfullhash: 'd98b28f4cb1708bb584f3e66078e0a0d',
// bigheadimgurl:
// 'http://wx.qlogo.cn/mmhead/ver_1/ciaaFRTCqfHIKLY0wBjv3h0LSPkCEEcJ0fo6kQkMxQLBiahJWFk7rS9G4VLU5n9OfAnXWlMaIV01oeTITYS0OHlg/0',
// smallheadimgurl:
// 'http://wx.qlogo.cn/mmhead/ver_1/ciaaFRTCqfHIKLY0wBjv3h0LSPkCEEcJ0fo6kQkMxQLBiahJWFk7rS9G4VLU5n9OfAnXWlMaIV01oeTITYS0OHlg/96',
// ticket:
// 'v2_1a0d2cf325e64b6f74bed09e944529e7cc7a7580cb323475050664566dd0302d89b8e2ed95b596b459cf762d94a0ce606da39babbae0dc26b18a62e079bfc120@stranger',
// opcode: '2',
// googlecontact: '',
// qrticket: '',
// chatroomusername: '',
// sourceusername: '',
// sourcenickname: '' },
// brandlist: [ [Object] ] } }

export interface PadchatFriendRequestPayload {
fromusername : string, // 'lizhuohuan'
encryptusername : string // v1_xxx@stranger'
content : string, // 'hello'
ticket : string, // 'v2_1a0d2cf325e64b6f74bed09e944529e7cc7a7580cb323475050664566dd0302d89b8e2ed95b596b459cf762d94a0ce606da39babbae0dc26b18a62e079bfc120@stranger',
}
91 changes: 60 additions & 31 deletions src/puppet-padchat/puppet-padchat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ import {
PuppetOptions,
Receiver,
FriendRequestPayload,
} from '../puppet/'
FriendRequestPayloadReceive,
} from '../puppet/'

import {
PadchatPureFunctionHelper as pfHelper,
Expand Down Expand Up @@ -273,7 +274,7 @@ export class PuppetPadchat extends Puppet {
this.emit('stop')
}

public async logout(): Promise<void> {
public async logout(passive = false): Promise<void> {
log.verbose('PuppetPadchat', 'logout()')

if (!this.id) {
Expand All @@ -283,6 +284,10 @@ export class PuppetPadchat extends Puppet {
this.emit('logout', this.id) // becore we will throw above by logonoff() when this.user===undefined
this.id = undefined

// if (!passive) {
// await this.bridge.WXLogout()
// }

await this.bridge.logout()
}

Expand Down Expand Up @@ -565,6 +570,15 @@ export class PuppetPadchat extends Puppet {
await this.bridge.WXDeleteChatRoomMember(roomId, contactId)
}

public async roomQrCode(roomId: string): Promise<string> {
log.verbose('PuppetPadchat', 'roomQrCode(%s)', roomId)

// TODO

throw new Error('not support')

}

public async roomAvatar(roomId: string): Promise<FileBox> {
log.verbose('PuppetPadchat', 'roomAvatar(%s)', roomId)

Expand All @@ -583,7 +597,20 @@ export class PuppetPadchat extends Puppet {
contactId : string,
): Promise<void> {
log.verbose('PuppetPadchat', 'roomAdd(%s, %s)', roomId, contactId)
await this.bridge.WXAddChatRoomMember(roomId, contactId)

// XXX: did there need to calc the total number of the members in this room?
// if n <= 40 then add() else invite() ?

try {
log.verbose('PuppetPadchat', 'roomAdd(%s, %s) try to Add', roomId, contactId)
await this.bridge.WXAddChatRoomMember(roomId, contactId)
} catch (e) {
// FIXME
console.error(e)
log.warn('PuppetPadchat', 'roomAdd(%s, %s) Add exception: %s', e)
log.verbose('PuppetPadchat', 'roomAdd(%s, %s) try to Invite', roomId, contactId)
await this.bridge.WXInviteChatRoomMember(roomId, contactId)
}
}

public async roomTopic(roomId: string) : Promise<string>
Expand Down Expand Up @@ -611,9 +638,11 @@ export class PuppetPadchat extends Puppet {
): Promise<string> {
log.verbose('PuppetPadchat', 'roomCreate(%s, %s)', contactIdList, topic)

// TODO
// await this.bridge.crea
return 'mock_room_id'
// FIXME:
const roomId = this.bridge.WXCreateChatRoom(contactIdList)
console.log('roomCreate returl:', roomId)

return roomId
}

public async roomQuit(roomId: string): Promise<void> {
Expand Down Expand Up @@ -646,50 +675,50 @@ export class PuppetPadchat extends Puppet {

const rawPayload = await this.contactRawPayload(contactId)

let strangerV1
let strangerV2
if (pfHelper.isStrangerV1(rawPayload.stranger)) { // /^v1_/i.test(rawPayload.stranger)) {
strangerV1 = rawPayload.stranger
} else if (pfHelper.isStrangerV2(rawPayload.stranger)) { // /^v2_/i.test(rawPayload.stranger)) {
strangerV2 = rawPayload.stranger
} else {
throw new Error('stranger neither v1 nor v2!')
}
// XXX
console.log('rawPayload.stranger: ', rawPayload)

// let strangerV1
// let strangerV2
// if (pfHelper.isStrangerV1(rawPayload.stranger)) {
// strangerV1 = rawPayload.stranger
// } else if (pfHelper.isStrangerV2(rawPayload.stranger)) {
// strangerV2 = rawPayload.stranger
// } else {
// throw new Error('stranger neither v1 nor v2!')
// }

// Issue #1252 : what's wrong here?

await this.bridge.WXAddUser(
strangerV1 || '',
strangerV2 || '',
rawPayload.stranger || '',
rawPayload.ticket || '',
'14',
hello,
)
}

public async friendRequestAccept(
contactId : string,
ticket : string,
friendRequestId : string,
): Promise<void> {
log.verbose('PuppetPadchat', 'friendRequestAccept(%s, %s)', contactId, ticket)
log.verbose('PuppetPadchat', 'friendRequestAccept(%s)', friendRequestId)

// TODO

// const rawPayload = await this.contactRawPayload(contactId)
const payload = await this.friendRequestPayload(friendRequestId) as FriendRequestPayloadReceive

// if (!rawPayload.ticket) {
// throw new Error('no ticket')
// }
if (!payload.ticket) {
throw new Error('no ticket')
}

// await this.bridge.WXAcceptUser(
// rawPayload.stranger,
// rawPayload.ticket,
// )
await this.bridge.WXAcceptUser(
payload.contactId,
payload.ticket,
)
}

public async friendRequestRawPayloadParser(rawPayload: PadchatMessagePayload) : Promise<FriendRequestPayload> {
log.verbose('PuppetPadchat', 'friendRequestRawPayloadParser(%s)', rawPayload)

const payload: FriendRequestPayload = pfHelper.friendRequestRawPayloadParser(rawPayload)
const payload: FriendRequestPayload = await pfHelper.friendRequestRawPayloadParser(rawPayload)
return payload
}

Expand Down
24 changes: 23 additions & 1 deletion src/puppet-padchat/pure-function-helper.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@ import {
PadchatContinue,
PadchatContactPayload,
PadchatContactRoomStatus,
// PadchatMessagePayload,

PadchatMessagePayload,
} from './padchat-schemas'

import {
ContactGender,
ContactType,
ContactPayload,
FriendRequestPayload,
FriendRequestType,
// MessagePayload,
} from '../puppet/'

Expand Down Expand Up @@ -151,6 +154,25 @@ test('contactRawPayloadParser', async t => {
t.throws(() => pfHelper.contactRawPayloadParser(undefined as any), 'should throw exception for undifined')
})

test('friendRequestRawPayloadParser()', async t => {
const DATA = '%5B%7B%22content%22%3A%22%3Cmsg+fromusername%3D%5C%22lizhuohuan%5C%22+encryptusername%3D%5C%22v1_cf269def9b946093f9d131a5e733ba169351013c95e46a860cddecaf485c4b10%40stranger%5C%22+fromnickname%3D%5C%22%E6%9D%8E%E5%8D%93%E6%A1%93%5C%22+content%3D%5C%22xixixi%5C%22+fullpy%3D%5C%22lizhuohuan%5C%22+shortpy%3D%5C%22LZH%5C%22+imagestatus%3D%5C%223%5C%22+scene%3D%5C%226%5C%22+country%3D%5C%22CN%5C%22+province%3D%5C%22Beijing%5C%22+city%3D%5C%22Haidian%5C%22+sign%3D%5C%22PreAngel%E6%8A%95%E8%B5%84%E4%BA%BA%E3%80%82%E6%B0%B4%E6%9C%A8%E6%B8%85%E5%8D%8EBBS%E7%AB%99%E9%95%BF%E3%80%82%E6%8A%95%E8%B5%84%E4%BA%BA%E4%B8%AD%E6%9C%80%E4%BC%9A%E9%A3%9E%E7%9A%84AI%E7%A8%8B%E5%BA%8F%E5%91%98%E3%80%82%5C%22+percard%3D%5C%221%5C%22+sex%3D%5C%221%5C%22+alias%3D%5C%22%5C%22+weibo%3D%5C%22%5C%22+weibonickname%3D%5C%22%5C%22+albumflag%3D%5C%220%5C%22+albumstyle%3D%5C%220%5C%22+albumbgimgid%3D%5C%22913943270785024_913943270785024%5C%22+snsflag%3D%5C%22177%5C%22+snsbgimgid%3D%5C%22http%3A%2F%2Fshmmsns.qpic.cn%2Fmmsns%2FNoFChqEQomEyhyNjzExH3v78BHSVmIzHBIdOECg9jgcTpRNwThgXJicCsGicI6Kib4xLETc2PuKwhM%2F0%5C%22+snsbgobjectid%3D%5C%2212683064081608282338%5C%22+mhash%3D%5C%22d98b28f4cb1708bb584f3e66078e0a0d%5C%22+mfullhash%3D%5C%22d98b28f4cb1708bb584f3e66078e0a0d%5C%22+bigheadimgurl%3D%5C%22http%3A%2F%2Fwx.qlogo.cn%2Fmmhead%2Fver_1%2FciaaFRTCqfHIKLY0wBjv3h0LSPkCEEcJ0fo6kQkMxQLBiahJWFk7rS9G4VLU5n9OfAnXWlMaIV01oeTITYS0OHlg%2F0%5C%22+smallheadimgurl%3D%5C%22http%3A%2F%2Fwx.qlogo.cn%2Fmmhead%2Fver_1%2FciaaFRTCqfHIKLY0wBjv3h0LSPkCEEcJ0fo6kQkMxQLBiahJWFk7rS9G4VLU5n9OfAnXWlMaIV01oeTITYS0OHlg%2F96%5C%22+ticket%3D%5C%22v2_1a0d2cf325e64b6f74bed09e944529e7cc7a7580cb323475050664566dd0302d89b8e2ed95b596b459cf762d94a0ce606da39babbae0dc26b18a62e079bfc120%40stranger%5C%22+opcode%3D%5C%222%5C%22+googlecontact%3D%5C%22%5C%22+qrticket%3D%5C%22%5C%22+chatroomusername%3D%5C%22%5C%22+sourceusername%3D%5C%22%5C%22+sourcenickname%3D%5C%22%5C%22%3E%3Cbrandlist+count%3D%5C%220%5C%22+ver%3D%5C%22652101432%5C%22%3E%3C%2Fbrandlist%3E%3C%2Fmsg%3E%22%2C%22continue%22%3A1%2C%22description%22%3A%22%22%2C%22from_user%22%3A%22fmessage%22%2C%22msg_id%22%3A%222957327798149218888%22%2C%22msg_source%22%3A%22%22%2C%22msg_type%22%3A5%2C%22status%22%3A1%2C%22sub_type%22%3A37%2C%22timestamp%22%3A1528557626%2C%22to_user%22%3A%22wxid_5zj4i5htp9ih22%22%2C%22uin%22%3A1928023446%7D%5D%0A'
const TENCENT_PAYLOAD_LIST: PadchatMessagePayload[] = JSON.parse(decodeURIComponent(DATA))
const PADCHAT_MESSAGE_PAYLOAD = TENCENT_PAYLOAD_LIST[0]
const EXPECTED_FRIEND_REQUEST_PAYLOAD = {
id : '2957327798149218888',
contactId : 'lizhuohuan',
hello : 'xixixi',
ticket : 'v2_1a0d2cf325e64b6f74bed09e944529e7cc7a7580cb323475050664566dd0302d89b8e2ed95b596b459cf762d94a0ce606da39babbae0dc26b18a62e079bfc120@stranger',
type : FriendRequestType.Receive,
}

// console.log(PADCHAT_MESSAGE_PAYLOAD)

const friendRequestPayload: FriendRequestPayload = await pfHelper.friendRequestRawPayloadParser(PADCHAT_MESSAGE_PAYLOAD)
// console.log(friendRequestPayload)

t.deepEqual(friendRequestPayload, EXPECTED_FRIEND_REQUEST_PAYLOAD, 'should parse friendRequestPayload right')
})
// TODO
// test('roomRawPayloadParser', async t => {

Expand Down
52 changes: 47 additions & 5 deletions src/puppet-padchat/pure-function-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
* [Master the JavaScript Interview: What is a Pure Function?](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-pure-function-d1c076bec976)
*
*/
import jsQR from 'jsqr'
import Jimp from 'jimp'
import jsQR from 'jsqr'
import Jimp from 'jimp'
import { parseString } from 'xml2js'

import {
ContactPayload,
Expand All @@ -21,6 +22,7 @@ import {
RoomPayload,

FriendRequestPayload,
FriendRequestType,
} from '../puppet/'

import {
Expand All @@ -32,6 +34,7 @@ import {
PadchatMessageType,

PadchatRoomPayload,
PadchatFriendRequestPayload,
// PadchatRoomMemberPayload,
} from './padchat-schemas'

Expand Down Expand Up @@ -168,6 +171,7 @@ export class PadchatPureFunctionHelper {
case PadchatMessageType.Recalled:
case PadchatMessageType.StatusNotify:
case PadchatMessageType.Sys:
case PadchatMessageType.SysNotice:
type = MessageType.Unknown
break

Expand Down Expand Up @@ -247,10 +251,48 @@ export class PadchatPureFunctionHelper {
return payload
}

public static friendRequestRawPayloadParser(
public static async friendRequestRawPayloadParser(
rawPayload: PadchatMessagePayload,
) : FriendRequestPayload {
throw new Error('to do ' + rawPayload)
) : Promise<FriendRequestPayload> {

let tryXmlText = rawPayload.content
tryXmlText = tryXmlText.replace(/\+/g, ' ')

interface XmlSchema {
msg?: {
$?: PadchatFriendRequestPayload,
}
}

const padchatFriendRequestPayload = await new Promise<PadchatFriendRequestPayload>((resolve, reject) => {
parseString(tryXmlText, { explicitArray: false }, (err, obj: XmlSchema) => {
if (err) { // HTML can not be parsed to JSON
return reject(err)
}
if (!obj) {
// FIXME: when will this happen?
return reject(new Error('parseString() return empty obj'))
}
if (!obj.msg || !obj.msg.$) {
return reject(new Error('parseString() return unknown obj'))
}
return resolve(obj.msg.$)
})
})

console.log(padchatFriendRequestPayload)

const friendRequestPayload: FriendRequestPayload = {
id : rawPayload.msg_id,
// use v1 stranger id as contactid at here:
contactId : padchatFriendRequestPayload.encryptusername,
hello : padchatFriendRequestPayload.content,
ticket : padchatFriendRequestPayload.ticket,
type : FriendRequestType.Receive,
}

return friendRequestPayload

// switch (rawPayload.sub_type) {
// case PadchatMessageType.VerifyMsg:
// if (!rawPayload.RecommendInfo) {
Expand Down

0 comments on commit b488cfb

Please sign in to comment.