Presence fixes

This commit is contained in:
Adhiraj Singh
2020-11-24 18:56:07 +05:30
parent cd90d66c5e
commit 242328abdc
7 changed files with 74 additions and 38 deletions

View File

@@ -11,6 +11,17 @@ WAConnectionTest('Messages', conn => {
const message = await sendAndRetreiveMessage(conn, 'hello fren', MessageType.text) const message = await sendAndRetreiveMessage(conn, 'hello fren', MessageType.text)
assert.strictEqual(message.message.conversation || message.message.extendedTextMessage?.text, 'hello fren') assert.strictEqual(message.message.conversation || message.message.extendedTextMessage?.text, 'hello fren')
}) })
it('should send a pending message', async () => {
const message = await sendAndRetreiveMessage(conn, 'hello fren', MessageType.text, { waitForAck: false })
await new Promise(resolve => conn.once('message-status-update', update => {
if (update.ids.includes(message.key.id)) {
assert.strictEqual(update.type, WA_MESSAGE_STATUS_TYPE.SERVER_ACK)
resolve()
}
}))
})
it('should forward a message', async () => { it('should forward a message', async () => {
let {messages} = await conn.loadMessages (testJid, 1) let {messages} = await conn.loadMessages (testJid, 1)
await conn.forwardMessage (testJid, messages[0], true) await conn.forwardMessage (testJid, messages[0], true)

View File

@@ -136,14 +136,17 @@ WAConnectionTest('Misc', (conn) => {
await delay (500) await delay (500)
} }
}) })
// open the other phone and look at the updates to really verify stuff
it('should send presence updates', async () => {
conn.shouldLogMessages = true
conn.requestPresenceUpdate(testJid)
it('should update presence', async () => { const sequence = [ Presence.available, Presence.composing, Presence.paused, Presence.recording, Presence.paused, Presence.unavailable ]
const presences = Object.values(Presence) for (const presence of sequence) {
for (const i in presences) { await delay(5000)
const response = await conn.updatePresence(testJid, presences[i]) await conn.updatePresence(presence !== Presence.unavailable ? testJid : null, presence)
assert.strictEqual(response.status, 200) //console.log(conn.messageLog.slice(-1))
console.log('sent update ', presence)
await delay(1500)
} }
}) })
it('should generate link previews correctly', async () => { it('should generate link previews correctly', async () => {

View File

@@ -210,7 +210,7 @@ export class WAConnection extends EventEmitter {
* @param timeoutMs timeout after which the query will be failed (set to null to disable a timeout) * @param timeoutMs timeout after which the query will be failed (set to null to disable a timeout)
* @param tag the tag to attach to the message * @param tag the tag to attach to the message
*/ */
async query(q: WAQuery) { async query(q: WAQuery): Promise<any> {
let {json, binaryTags, tag, timeoutMs, expect200, waitForOpen, longTag, requiresPhoneConnection, startDebouncedTimeout} = q let {json, binaryTags, tag, timeoutMs, expect200, waitForOpen, longTag, requiresPhoneConnection, startDebouncedTimeout} = q
requiresPhoneConnection = requiresPhoneConnection !== false requiresPhoneConnection = requiresPhoneConnection !== false
waitForOpen = waitForOpen !== false waitForOpen = waitForOpen !== false

View File

@@ -51,18 +51,15 @@ export class WAConnection extends Base {
* @param jid the ID of the person/group who you are updating * @param jid the ID of the person/group who you are updating
* @param type your presence * @param type your presence
*/ */
updatePresence = (jid: string | null, type: Presence) => updatePresence = (jid: string | null, type: Presence) => this.sendBinary(
this.query( [ 'action',
{ {epoch: this.msgCount.toString(), type: 'set'},
json: [ [ ['presence', { type: type, to: jid }, null] ]
'action', ],
{ epoch: this.msgCount.toString(), type: 'set' }, [WAMetric.presence, WAFlag[type] ], // weird stuff WA does
[['presence', { type: type, to: jid }, null]], undefined,
], true
binaryTags: [WAMetric.group, WAFlag.acknowledge], )
expect200: true
}
) as Promise<{status: number}>
/** Request an update on the presence of a user */ /** Request an update on the presence of a user */
requestPresenceUpdate = async (jid: string) => this.query({ json: ['action', 'presence', 'subscribe', jid] }) requestPresenceUpdate = async (jid: string) => this.query({ json: ['action', 'presence', 'subscribe', jid] })
/** Query the status of the person (see groupMetadata() for groups) */ /** Query the status of the person (see groupMetadata() for groups) */

View File

@@ -29,7 +29,7 @@ export class WAConnection extends Base {
options: MessageOptions = {}, options: MessageOptions = {},
) { ) {
const waMessage = await this.prepareMessage (id, message, type, options) const waMessage = await this.prepareMessage (id, message, type, options)
await this.relayWAMessage (waMessage) await this.relayWAMessage (waMessage, { waitForAck: options.waitForAck !== false })
return waMessage return waMessage
} }
/** Prepares a message for sending via sendWAMessage () */ /** Prepares a message for sending via sendWAMessage () */
@@ -217,12 +217,26 @@ export class WAConnection extends Base {
return WAMessageProto.WebMessageInfo.create (messageJSON) return WAMessageProto.WebMessageInfo.create (messageJSON)
} }
/** Relay (send) a WAMessage; more advanced functionality to send a built WA Message, you may want to stick with sendMessage() */ /** Relay (send) a WAMessage; more advanced functionality to send a built WA Message, you may want to stick with sendMessage() */
async relayWAMessage(message: WAMessage) { async relayWAMessage(message: WAMessage, { waitForAck } = { waitForAck: true }) {
const json = ['action', {epoch: this.msgCount.toString(), type: 'relay'}, [['message', null, message]]] const json = ['action', {epoch: this.msgCount.toString(), type: 'relay'}, [['message', null, message]]]
const flag = message.key.remoteJid === this.user?.jid ? WAFlag.acknowledge : WAFlag.ignore // acknowledge when sending message to oneself const flag = message.key.remoteJid === this.user?.jid ? WAFlag.acknowledge : WAFlag.ignore // acknowledge when sending message to oneself
await this.query({json, binaryTags: [WAMetric.message, flag], tag: message.key.id, expect200: true}) const mID = message.key.id
message.status = WA_MESSAGE_STATUS_TYPE.PENDING
message.status = WA_MESSAGE_STATUS_TYPE.SERVER_ACK const promise = this.query({
json,
binaryTags: [WAMetric.message, flag],
tag: mID,
expect200: true
})
.then(() => message.status = WA_MESSAGE_STATUS_TYPE.SERVER_ACK)
if (waitForAck) {
await promise
} else {
promise
.then(() => this.emit('message-status-update', { ids: [ mID ], to: message.key.remoteJid, type: WA_MESSAGE_STATUS_TYPE.SERVER_ACK }))
.catch(() => this.emit('message-status-update', { ids: [ mID ], to: message.key.remoteJid, type: WA_MESSAGE_STATUS_TYPE.ERROR }))
}
await this.chatAddMessageAppropriate (message) await this.chatAddMessageAppropriate (message)
} }
/** /**

View File

@@ -299,14 +299,14 @@ export class WAConnection extends Base {
return waMessage return waMessage
} }
/** /**
* Forward a message like WA does * Generate forwarded message content like WA does
* @param id the id to forward the message to
* @param message the message to forward * @param message the message to forward
* @param forceForward will show the message as forwarded even if it is from you * @param forceForward will show the message as forwarded even if it is from you
*/ */
async forwardMessage(id: string, message: WAMessage, forceForward: boolean=false) { generateForwardMessageContent (message: WAMessage, forceForward: boolean=false) {
const content = message.message let content = message.message
if (!content) throw new Error ('no content in message') if (!content) throw new BaileysError ('no content in message', { status: 400 })
content = JSON.parse(JSON.stringify(content)) // hacky copy
let key = Object.keys(content)[0] let key = Object.keys(content)[0]
@@ -320,13 +320,20 @@ export class WAConnection extends Base {
} }
if (score > 0) content[key].contextInfo = { forwardingScore: score, isForwarded: true } if (score > 0) content[key].contextInfo = { forwardingScore: score, isForwarded: true }
else content[key].contextInfo = {} else content[key].contextInfo = {}
return content
const waMessage = this.prepareMessageFromContent (id, content, {}) }
/**
* Forward a message like WA
* @param jid the chat ID to forward to
* @param message the message to forward
* @param forceForward will show the message as forwarded even if it is from you
*/
async forwardMessage(jid: string, message: WAMessage, forceForward: boolean=false) {
const content = this.generateForwardMessageContent(message, forceForward)
const waMessage = this.prepareMessageFromContent (jid, content, {})
await this.relayWAMessage (waMessage) await this.relayWAMessage (waMessage)
return waMessage return waMessage
} }
/** /**
* Modify a given chat (archive, pin etc.) * Modify a given chat (archive, pin etc.)
* @param jid the ID of the person/group you are modifiying * @param jid the ID of the person/group you are modifiying

View File

@@ -253,22 +253,24 @@ export enum WAMetric {
export const STORIES_JID = 'status@broadcast' export const STORIES_JID = 'status@broadcast'
export enum WAFlag { export enum WAFlag {
available = 160,
ignore = 1 << 7, ignore = 1 << 7,
acknowledge = 1 << 6, acknowledge = 1 << 6,
available = 1 << 5,
unavailable = 1 << 4, unavailable = 1 << 4,
expires = 1 << 3, expires = 1 << 3,
skipOffline = 1 << 2, composing = 1 << 2,
recording = 1 << 2,
paused = 1 << 2
} }
/** Tag used with binary queries */ /** Tag used with binary queries */
export type WATag = [WAMetric, WAFlag] export type WATag = [WAMetric, WAFlag]
/** set of statuses visible to other people; see updatePresence() in WhatsAppWeb.Send */ /** set of statuses visible to other people; see updatePresence() in WhatsAppWeb.Send */
export enum Presence { export enum Presence {
available = 'available', // "online"
unavailable = 'unavailable', // "offline" unavailable = 'unavailable', // "offline"
available = 'available', // "online"
composing = 'composing', // "typing..." composing = 'composing', // "typing..."
recording = 'recording', // "recording..." recording = 'recording', // "recording..."
paused = 'paused', // I have no clue paused = 'paused', // stop typing
} }
/** Set of message types that are supported by the library */ /** Set of message types that are supported by the library */
export enum MessageType { export enum MessageType {
@@ -348,6 +350,8 @@ export interface MessageOptions {
duration?: number duration?: number
/** Fetches new media options for every media file */ /** Fetches new media options for every media file */
forceNewMediaOptions?: boolean forceNewMediaOptions?: boolean
/** Wait for the message to be sent to the server (default true) */
waitForAck?: boolean
} }
export interface WABroadcastListInfo { export interface WABroadcastListInfo {
status: number status: number