fix(WEBJS): fix presence.update
This commit is contained in:
1 parent
b5702f1a48
commit
8e36c7a14c
4 files changed
+124
-87
No files matched your search
@@ -1,4 +1,7 @@
|
||||
import { WebJSPresence } from '@waha/core/engines/webjs/types';
|
||||
import {
|
||||
WebJSPresence,
|
||||
WebJSPresenceUpdate,
|
||||
} from '@waha/core/engines/webjs/types';
|
||||
import { GetSerialized } from '@waha/core/utils/serialized';
|
||||
import { GetChatMessagesFilter } from '@waha/structures/chats.dto';
|
||||
import { Label } from '@waha/structures/labels.dto';
|
||||
@@ -198,11 +201,111 @@ export class WebjsClientCore extends Client {
|
||||
return;
|
||||
},
|
||||
);
|
||||
await exposeFunctionIfAbsent(
|
||||
this.pupPage,
|
||||
'onPresenceUpdate',
|
||||
(data: WebJSPresenceUpdate) => {
|
||||
this.events.emit('presence.update', data);
|
||||
return;
|
||||
},
|
||||
);
|
||||
await this.attachPresenceEvents();
|
||||
if (this.tags) {
|
||||
await this.attachTagsEvents();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Presence lands in PresenceCollection on the main thread even when WhatsApp runs comms in a worker,
|
||||
* so listen to the models instead of raw stanzas
|
||||
*/
|
||||
async attachPresenceEvents() {
|
||||
await this.pupPage.evaluate(() => {
|
||||
// @ts-ignore
|
||||
if (window.presenceEventsOn) {
|
||||
return;
|
||||
}
|
||||
// @ts-ignore
|
||||
window.presenceEventsOn = true;
|
||||
|
||||
const d = require;
|
||||
const PresenceCollection = d(
|
||||
'WAWebPresenceCollection',
|
||||
).PresenceCollection;
|
||||
const WAWebApiContact = d('WAWebApiContact');
|
||||
|
||||
// Prefer the phone number id when the LID mapping is known
|
||||
const toId = (wid) => {
|
||||
let id = wid;
|
||||
if (wid.isLid()) {
|
||||
id = WAWebApiContact.getPhoneNumber(wid) ?? wid;
|
||||
}
|
||||
// @ts-ignore
|
||||
return window.WWebJS.GetSerialized(id);
|
||||
};
|
||||
|
||||
const toPresences = (presence) => {
|
||||
if (!presence.isGroup) {
|
||||
return [
|
||||
{
|
||||
participant: toId(presence.id),
|
||||
lastSeen: presence.chatstate.t,
|
||||
state: presence.chatstate.type,
|
||||
},
|
||||
];
|
||||
}
|
||||
return presence.chatstates
|
||||
.getModelsArray()
|
||||
.filter((chatstate) => !!chatstate.type)
|
||||
.map((chatstate) => {
|
||||
return {
|
||||
participant: toId(chatstate.id),
|
||||
lastSeen: chatstate.t,
|
||||
state: chatstate.type,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
// type and t change in one set() - coalesce into a single event per presence
|
||||
const pending = new Set<any>();
|
||||
const flush = () => {
|
||||
for (const presence of pending) {
|
||||
// @ts-ignore
|
||||
window.onPresenceUpdate({
|
||||
id: toId(presence.id),
|
||||
presences: toPresences(presence),
|
||||
});
|
||||
}
|
||||
pending.clear();
|
||||
};
|
||||
|
||||
const findPresence = (chatstate) => {
|
||||
const presence = PresenceCollection.get(chatstate.id);
|
||||
if (presence && presence.chatstate === chatstate) {
|
||||
return presence;
|
||||
}
|
||||
// Group chatstate id is the participant, not the group
|
||||
return PresenceCollection.getModelsArray().find(
|
||||
(model) => model.chatstate === chatstate,
|
||||
);
|
||||
};
|
||||
|
||||
PresenceCollection.on(
|
||||
'change:chatstate.type change:chatstate.t',
|
||||
(chatstate) => {
|
||||
const presence = findPresence(chatstate);
|
||||
if (!presence || !presence.hasData) {
|
||||
return;
|
||||
}
|
||||
if (pending.size === 0) {
|
||||
queueMicrotask(flush);
|
||||
}
|
||||
pending.add(presence);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async attachTagsEvents() {
|
||||
await this.pupPage.evaluate(() => {
|
||||
// @ts-ignore
|
||||
@@ -210,7 +313,7 @@ export class WebjsClientCore extends Client {
|
||||
return;
|
||||
}
|
||||
|
||||
const tags = ['receipt', 'presence', 'chatstate'];
|
||||
const tags = ['receipt'];
|
||||
const WAWap = window.require('WAWap');
|
||||
// @ts-ignore
|
||||
window.decodeStanzaBack = WAWap.decodeStanza;
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
import type { BinaryNode, WAPresence } from '@adiwajshing/baileys';
|
||||
import { WAHAPresenceStatus } from '@waha/structures/enums.dto';
|
||||
import { WAHAChatPresences } from '@waha/structures/presence.dto';
|
||||
|
||||
import { jid } from './ack.webjs';
|
||||
import { toCusFormat } from '@waha/core/utils/jids';
|
||||
|
||||
export function TagPresenceToPresence(node: BinaryNode): WAHAChatPresences {
|
||||
const { attrs } = node;
|
||||
const id = jid(attrs.from);
|
||||
const state =
|
||||
attrs.type === 'unavailable'
|
||||
? WAHAPresenceStatus.OFFLINE
|
||||
: WAHAPresenceStatus.ONLINE;
|
||||
const lastSeen = attrs.last && attrs.last !== 'deny' ? +attrs.last : null;
|
||||
return {
|
||||
id: toCusFormat(id),
|
||||
presences: [
|
||||
{
|
||||
participant: toCusFormat(id),
|
||||
lastKnownPresence: state,
|
||||
lastSeen: lastSeen,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
export function TagChatstateToPresence(node: BinaryNode): WAHAChatPresences {
|
||||
const { attrs, content } = node;
|
||||
const id = jid(attrs.from);
|
||||
const participant = jid(attrs.participant) || jid(attrs.from);
|
||||
|
||||
const firstChild = content[0] as BinaryNode;
|
||||
|
||||
const type = firstChild.tag as WAPresence;
|
||||
let status = WAHAPresenceStatus.OFFLINE;
|
||||
|
||||
switch (type) {
|
||||
case 'unavailable':
|
||||
status = WAHAPresenceStatus.OFFLINE;
|
||||
break;
|
||||
case 'available':
|
||||
status = WAHAPresenceStatus.ONLINE;
|
||||
break;
|
||||
case 'paused':
|
||||
status = WAHAPresenceStatus.PAUSED;
|
||||
break;
|
||||
case 'composing':
|
||||
status = WAHAPresenceStatus.TYPING;
|
||||
break;
|
||||
}
|
||||
|
||||
if (firstChild.attrs?.media === 'audio') {
|
||||
status = WAHAPresenceStatus.RECORDING;
|
||||
}
|
||||
|
||||
return {
|
||||
id: toCusFormat(id),
|
||||
presences: [
|
||||
{
|
||||
participant: toCusFormat(participant),
|
||||
lastKnownPresence: status,
|
||||
lastSeen: null,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -24,10 +24,6 @@ import {
|
||||
ToGroupV2ParticipantsEvent,
|
||||
ToGroupV2UpdateEvent,
|
||||
} from '@waha/core/engines/webjs/groups.webjs';
|
||||
import {
|
||||
TagChatstateToPresence,
|
||||
TagPresenceToPresence,
|
||||
} from '@waha/core/engines/webjs/presence';
|
||||
import {
|
||||
WebjsChannelMessage,
|
||||
WebjsClientCore,
|
||||
@@ -208,7 +204,11 @@ import {
|
||||
} from 'whatsapp-web.js/src/structures';
|
||||
import { GetSerialized } from '@waha/core/utils/serialized';
|
||||
|
||||
import { WAJSPresenceChatStateType, WebJSPresence } from './types';
|
||||
import {
|
||||
WAJSPresenceChatStateType,
|
||||
WebJSPresence,
|
||||
WebJSPresenceUpdate,
|
||||
} from './types';
|
||||
import { WebJSAuthFactory } from './WebJSAuthFactory';
|
||||
import {
|
||||
isJidCus,
|
||||
@@ -351,7 +351,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
|
||||
protected getWebjsTagsFlag() {
|
||||
// Emit 'tag:*' events only when explicitly enabled in session config.
|
||||
// This flag is required for presence.update and message.ack events.
|
||||
// This flag is required for message.ack events.
|
||||
// Disabled by default for performance and stability reasons.
|
||||
return !!this.sessionConfig?.webjs?.tagsEventsOn;
|
||||
}
|
||||
@@ -2504,19 +2504,15 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
//
|
||||
// Presence
|
||||
//
|
||||
const tagPresenceNode$ = fromEvent(this.whatsapp, Events.TAG_PRESENCE);
|
||||
const presences$ = tagPresenceNode$.pipe(
|
||||
map(TagPresenceToPresence),
|
||||
filter(Boolean),
|
||||
filter((presence: any) => this.jids.include(presence.id)),
|
||||
const presenceUpdate$ = fromEvent(
|
||||
this.whatsapp.events,
|
||||
'presence.update',
|
||||
).pipe(
|
||||
map((data: WebJSPresenceUpdate) =>
|
||||
this.toWahaPresences(data.id, data.presences),
|
||||
),
|
||||
filter((presence) => this.jids.include(presence.id)),
|
||||
);
|
||||
const tagChatstateNode$ = fromEvent(this.whatsapp, 'tag:chatstate');
|
||||
const chatstatePresences$ = tagChatstateNode$.pipe(
|
||||
map(TagChatstateToPresence),
|
||||
filter(Boolean),
|
||||
filter((presence: any) => this.jids.include(presence.id)),
|
||||
);
|
||||
const presenceUpdate$ = merge(presences$, chatstatePresences$);
|
||||
this.events2.get(WAHAEvents.PRESENCE_UPDATE).switch(presenceUpdate$);
|
||||
|
||||
//
|
||||
|
||||
@@ -10,3 +10,8 @@ export interface WebJSPresence {
|
||||
lastSeen?: number;
|
||||
state: WAJSPresenceChatStateType;
|
||||
}
|
||||
|
||||
export interface WebJSPresenceUpdate {
|
||||
id: string;
|
||||
presences: WebJSPresence[];
|
||||
}
|
||||
Reference in new issue
Block a user