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)
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 () => {
let {messages} = await conn.loadMessages (testJid, 1)
await conn.forwardMessage (testJid, messages[0], true)

View File

@@ -136,14 +136,17 @@ WAConnectionTest('Misc', (conn) => {
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 presences = Object.values(Presence)
for (const i in presences) {
const response = await conn.updatePresence(testJid, presences[i])
assert.strictEqual(response.status, 200)
await delay(1500)
const sequence = [ Presence.available, Presence.composing, Presence.paused, Presence.recording, Presence.paused, Presence.unavailable ]
for (const presence of sequence) {
await delay(5000)
await conn.updatePresence(presence !== Presence.unavailable ? testJid : null, presence)
//console.log(conn.messageLog.slice(-1))
console.log('sent update ', presence)
}
})
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 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
requiresPhoneConnection = requiresPhoneConnection !== 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 type your presence
*/
updatePresence = (jid: string | null, type: Presence) =>
this.query(
{
json: [
'action',
{ epoch: this.msgCount.toString(), type: 'set' },
[['presence', { type: type, to: jid }, null]],
],
binaryTags: [WAMetric.group, WAFlag.acknowledge],
expect200: true
}
) as Promise<{status: number}>
updatePresence = (jid: string | null, type: Presence) => this.sendBinary(
[ 'action',
{epoch: this.msgCount.toString(), type: 'set'},
[ ['presence', { type: type, to: jid }, null] ]
],
[WAMetric.presence, WAFlag[type] ], // weird stuff WA does
undefined,
true
)
/** Request an update on the presence of a user */
requestPresenceUpdate = async (jid: string) => this.query({ json: ['action', 'presence', 'subscribe', jid] })
/** Query the status of the person (see groupMetadata() for groups) */

View File

@@ -29,7 +29,7 @@ export class WAConnection extends Base {
options: MessageOptions = {},
) {
const waMessage = await this.prepareMessage (id, message, type, options)
await this.relayWAMessage (waMessage)
await this.relayWAMessage (waMessage, { waitForAck: options.waitForAck !== false })
return waMessage
}
/** Prepares a message for sending via sendWAMessage () */
@@ -217,12 +217,26 @@ export class WAConnection extends Base {
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() */
async relayWAMessage(message: WAMessage) {
async relayWAMessage(message: WAMessage, { waitForAck } = { waitForAck: true }) {
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
await this.query({json, binaryTags: [WAMetric.message, flag], tag: message.key.id, expect200: true})
message.status = WA_MESSAGE_STATUS_TYPE.SERVER_ACK
const mID = message.key.id
message.status = WA_MESSAGE_STATUS_TYPE.PENDING
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)
}
/**

View File

@@ -299,14 +299,14 @@ export class WAConnection extends Base {
return waMessage
}
/**
* Forward a message like WA does
* @param id the id to forward the message to
* Generate forwarded message content like WA does
* @param message the message to forward
* @param forceForward will show the message as forwarded even if it is from you
*/
async forwardMessage(id: string, message: WAMessage, forceForward: boolean=false) {
const content = message.message
if (!content) throw new Error ('no content in message')
generateForwardMessageContent (message: WAMessage, forceForward: boolean=false) {
let content = message.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]
@@ -320,13 +320,20 @@ export class WAConnection extends Base {
}
if (score > 0) content[key].contextInfo = { forwardingScore: score, isForwarded: true }
else content[key].contextInfo = {}
const waMessage = this.prepareMessageFromContent (id, content, {})
return 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)
return waMessage
}
/**
* Modify a given chat (archive, pin etc.)
* @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 enum WAFlag {
available = 160,
ignore = 1 << 7,
acknowledge = 1 << 6,
available = 1 << 5,
unavailable = 1 << 4,
expires = 1 << 3,
skipOffline = 1 << 2,
composing = 1 << 2,
recording = 1 << 2,
paused = 1 << 2
}
/** Tag used with binary queries */
export type WATag = [WAMetric, WAFlag]
/** set of statuses visible to other people; see updatePresence() in WhatsAppWeb.Send */
export enum Presence {
available = 'available', // "online"
unavailable = 'unavailable', // "offline"
available = 'available', // "online"
composing = 'composing', // "typing..."
recording = 'recording', // "recording..."
paused = 'paused', // I have no clue
paused = 'paused', // stop typing
}
/** Set of message types that are supported by the library */
export enum MessageType {
@@ -348,6 +350,8 @@ export interface MessageOptions {
duration?: number
/** Fetches new media options for every media file */
forceNewMediaOptions?: boolean
/** Wait for the message to be sent to the server (default true) */
waitForAck?: boolean
}
export interface WABroadcastListInfo {
status: number