From cea702b5a3cf3be436a0eefb831792ea40d1b941 Mon Sep 17 00:00:00 2001 From: Adhiraj Singh Date: Tue, 17 Nov 2020 16:58:57 +0530 Subject: [PATCH] better presence handling via chat-update --- Example/example.ts | 4 ++- README.md | 4 +-- src/WAConnection/4.Events.ts | 55 +++++++++++++++++++++++------------ src/WAConnection/Constants.ts | 11 +++---- 4 files changed, 46 insertions(+), 28 deletions(-) diff --git a/Example/example.ts b/Example/example.ts index 6f586d0..a58278f 100644 --- a/Example/example.ts +++ b/Example/example.ts @@ -47,12 +47,14 @@ async function example() { /* Note: one can take this auth_info.json file and login again from any computer without having to scan the QR code, and get full access to one's WhatsApp. Despite the convenience, be careful with this file */ - conn.on ('user-presence-update', json => console.log(json.id + ' presence is ' + json.type)) conn.on ('message-status-update', json => { const participant = json.participant ? ' (' + json.participant + ')' : '' // participant exists when the message is from a group console.log(`${json.to}${participant} acknlowledged message(s) ${json.ids} as ${json.type}`) }) conn.on('chat-update', async chat => { + if (chat.presences) { // receive presence updates -- composing, available, etc. + Object.keys(chat.presences).forEach(jid => console.log( `${jid}'s presence is ${chat.presences[jid].lastKnownPresence} in ${chat.jid}`)) + } // only do something when a new message is received; i.e. the unread count is updated if (!chat.count) return diff --git a/README.md b/README.md index 57d27cb..3130d5a 100644 --- a/README.md +++ b/README.md @@ -195,8 +195,6 @@ on (event: 'credentials-updated', listener: (auth: AuthenticationCredentials) => on (event: 'qr', listener: (qr: string) => void): this /** when the connection to the phone changes */ on (event: 'connection-phone-change', listener: (state: {connected: boolean}) => void): this -/** when a user's presence is updated */ -on (event: 'user-presence-update', listener: (update: PresenceUpdate) => void): this /** when a user's status is updated */ on (event: 'user-status-update', listener: (update: {jid: string, status?: string}) => void): this /** when a new chat is added */ @@ -207,7 +205,7 @@ on (event: 'contacts-received', listener: () => void): this on (event: 'chats-received', listener: (update: {hasNewChats: boolean}) => void): this /** when multiple chats are updated (new message, updated message, deleted, pinned, etc) */ on (event: 'chats-update', listener: (chats: (Partial & { jid: string })[]) => void): this -/** when a chat is updated (new message, updated message, deleted, pinned, etc) */ +/** when a chat is updated (new message, updated message, deleted, pinned, presence updated etc) */ on (event: 'chat-update', listener: (chat: Partial & { jid: string }) => void): this /** when a message's status is updated (deleted, delivered, read, sent etc.) */ on (event: 'message-status-update', listener: (message: WAMessageStatusUpdate) => void): this diff --git a/src/WAConnection/4.Events.ts b/src/WAConnection/4.Events.ts index eebefa9..2991199 100644 --- a/src/WAConnection/4.Events.ts +++ b/src/WAConnection/4.Events.ts @@ -1,6 +1,6 @@ import * as QR from 'qrcode-terminal' import { WAConnection as Base } from './3.Connect' -import { WAMessageStatusUpdate, WAMessage, WAContact, WAChat, WAMessageProto, WA_MESSAGE_STUB_TYPE, WA_MESSAGE_STATUS_TYPE, PresenceUpdate, BaileysEvent, DisconnectReason, WAOpenResult, Presence, AuthenticationCredentials, WAParticipantAction, WAGroupMetadata, WAUser, WANode } from './Constants' +import { WAMessageStatusUpdate, WAMessage, WAContact, WAChat, WAMessageProto, WA_MESSAGE_STUB_TYPE, WA_MESSAGE_STATUS_TYPE, PresenceUpdate, BaileysEvent, DisconnectReason, WAOpenResult, Presence, AuthenticationCredentials, WAParticipantAction, WAGroupMetadata, WAUser, WANode, WAPresenceData } from './Constants' import { whatsappID, unixTimestampSeconds, isGroupID, GET_MESSAGE_ID, WA_MESSAGE_ID, waMessageKey, newMessagesDB, shallowChanges, toNumber } from './Utils' import KeyedDB from '@adiwajshing/keyed-db' import { Mutex } from './Mutex' @@ -157,19 +157,8 @@ export class WAConnection extends Base { }) // presence updates this.on('CB:Presence', json => { - const update = json[1] as PresenceUpdate - const jid = whatsappID(update.participant || update.id) - - const contact = this.contacts[jid] - if (contact && jid.endsWith('@s.whatsapp.net')) { // if its a single chat - if (update.t) contact.lastSeen = +update.t - else if (update.type === Presence.unavailable && contact.lastKnownPresence !== Presence.unavailable) { - contact.lastSeen = unixTimestampSeconds() - } - contact.lastKnownPresence = update.type - } - - this.emit('user-presence-update', update) + const chatUpdate = this.applyingPresenceUpdate(json[1]) + chatUpdate && this.emit('chat-update', chatUpdate) }) // If a message has been updated (usually called when a video message gets its upload url, or live locations) this.on ('CB:action,add:update,message', json => { @@ -320,6 +309,30 @@ export class WAConnection extends Base { const response = await this.query({ json: ['query', 'ProfilePicThumb', jid || this.user.jid], expect200: true, requiresPhoneConnection: false }) return response.eurl as string } + protected applyingPresenceUpdate(update: PresenceUpdate) { + const chatId = update.id + const jid = whatsappID(update.participant || update.id) + // emit deprecated + this.emit('user-presence-update', update) + + const contact = this.contacts[jid] + if (contact && jid.endsWith('@s.whatsapp.net')) { // if its a single chat + if (update.t) contact.lastSeen = +update.t + else if (update.type === Presence.unavailable && contact.lastKnownPresence !== Presence.unavailable) { + contact.lastSeen = unixTimestampSeconds() + } + contact.lastKnownPresence = update.type + const presence: WAPresenceData = { lastKnownPresence: contact.lastKnownPresence, lastSeen: contact.lastSeen } + + const chat = this.chats.get(chatId) + if (chat) { + chat.presences = chat.presences || {} + chat.presences[jid] = presence + + return { jid: chatId, presences: { [jid]: presence } } as Partial + } + } + } protected forwardStatusUpdate (update: WAMessageStatusUpdate) { const chat = this.chats.get( whatsappID(update.to) ) if (!chat) return @@ -368,10 +381,11 @@ export class WAConnection extends Base { if (!message.key.fromMe && message.message) { chat.count += 1 chatUpdate.count = chat.count + const contact = this.contacts[message.participant || chat.jid] - if (contact && contact.lastKnownPresence === Presence.composing) { // update presence - contact.lastKnownPresence = Presence.available // emit change - this.emit ('user-presence-update', { id: chat.jid, presence: Presence.available, participant: message.participant }) + if (contact.lastKnownPresence === Presence.composing) { // update presence + const update = this.applyingPresenceUpdate({ id: chat.jid, participant: message.participant || chat.jid, type: Presence.available }) + update && Object.assign(chatUpdate, update) } } @@ -501,7 +515,10 @@ export class WAConnection extends Base { on (event: 'qr', listener: (qr: string) => void): this /** when the connection to the phone changes */ on (event: 'connection-phone-change', listener: (state: {connected: boolean}) => void): this - /** when a user's presence is updated */ + /** + * when a user's presence is updated + * @deprecated use `chat-update` + * */ on (event: 'user-presence-update', listener: (update: PresenceUpdate) => void): this /** when a user's status is updated */ on (event: 'user-status-update', listener: (update: {jid: string, status?: string}) => void): this @@ -513,7 +530,7 @@ export class WAConnection extends Base { on (event: 'chats-received', listener: (update: {hasNewChats: boolean}) => void): this /** when multiple chats are updated (new message, updated message, deleted, pinned, etc) */ on (event: 'chats-update', listener: (chats: (Partial & { jid: string })[]) => void): this - /** when a chat is updated (new message, updated message, deleted, pinned, etc) */ + /** when a chat is updated (new message, updated message, deleted, pinned, presence updated etc) */ on (event: 'chat-update', listener: (chat: Partial & { jid: string }) => void): this /** * when a new message is relayed diff --git a/src/WAConnection/Constants.ts b/src/WAConnection/Constants.ts index b2ccd41..e030ec6 100644 --- a/src/WAConnection/Constants.ts +++ b/src/WAConnection/Constants.ts @@ -177,8 +177,11 @@ export interface WAGroupModification { status: number participants?: { [key: string]: any } } - -export interface WAContact { +export interface WAPresenceData { + lastKnownPresence?: Presence + lastSeen?: number +} +export interface WAContact extends WAPresenceData { verify?: string /** name of the contact, the contact has set on their own on WA */ notify?: string @@ -192,8 +195,6 @@ export interface WAContact { short?: string // Baileys Added imgUrl?: string - lastKnownPresence?: Presence - lastSeen?: number } export interface WAUser extends WAContact { phone: any @@ -215,6 +216,7 @@ export interface WAChat { // Baileys added properties messages: KeyedDB imgUrl?: string + presences?: { [k: string]: WAPresenceData } } export enum WAMetric { debugLog = 1, @@ -426,7 +428,6 @@ export type BaileysEvent = 'ws-close' | 'qr' | 'connection-phone-change' | - 'user-presence-update' | 'user-status-update' | 'contacts-received' | 'chats-received' |