feat: eventMessage sending / call link creation (#1677)
This commit is contained in:
@@ -10,6 +10,8 @@ const { version } = defaultVersion
|
||||
export const UNAUTHORIZED_CODES = [401, 403, 419]
|
||||
|
||||
export const DEFAULT_ORIGIN = 'https://web.whatsapp.com'
|
||||
export const CALL_VIDEO_PREFIX = 'https://call.whatsapp.com/video/'
|
||||
export const CALL_AUDIO_PREFIX = 'https://call.whatsapp.com/voice/'
|
||||
export const DEF_CALLBACK_PREFIX = 'CB:'
|
||||
export const DEF_TAG_PREFIX = 'TAG:'
|
||||
export const PHONE_CONNECTION_CB = 'CB:Pong'
|
||||
|
||||
@@ -633,6 +633,28 @@ export const makeChatsSocket = (config: SocketConfig) => {
|
||||
return child?.attrs?.url
|
||||
}
|
||||
|
||||
const createCallLink = async (type: 'audio' | 'video', event?: { startTime: number }, timeoutMs?: number) => {
|
||||
const result = await query(
|
||||
{
|
||||
tag: 'call',
|
||||
attrs: {
|
||||
id: generateMessageTag(),
|
||||
to: '@call'
|
||||
},
|
||||
content: [
|
||||
{
|
||||
tag: 'link_create',
|
||||
attrs: { media: type },
|
||||
content: event ? [{ tag: 'event', attrs: { start_time: String(event.startTime) } }] : undefined
|
||||
}
|
||||
]
|
||||
},
|
||||
timeoutMs
|
||||
)
|
||||
const child = getBinaryNodeChild(result, 'link_create')
|
||||
return child?.attrs?.token
|
||||
}
|
||||
|
||||
const sendPresenceUpdate = async (type: WAPresence, toJid?: string) => {
|
||||
const me = authState.creds.me!
|
||||
if (type === 'available' || type === 'unavailable') {
|
||||
@@ -1139,6 +1161,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
|
||||
|
||||
return {
|
||||
...sock,
|
||||
createCallLink,
|
||||
getBotListV2,
|
||||
processingMutex,
|
||||
fetchPrivacySettings,
|
||||
|
||||
@@ -655,6 +655,10 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
||||
return 'poll'
|
||||
}
|
||||
|
||||
if (message.eventMessage) {
|
||||
return 'event'
|
||||
}
|
||||
|
||||
return 'text'
|
||||
}
|
||||
|
||||
@@ -817,12 +821,14 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
||||
}),
|
||||
//TODO: CACHE
|
||||
getProfilePicUrl: sock.profilePictureUrl,
|
||||
getCallLink: sock.createCallLink,
|
||||
upload: waUploadToServer,
|
||||
mediaCache: config.mediaCache,
|
||||
options: config.options,
|
||||
messageId: generateMessageIDV2(sock.user?.id),
|
||||
...options
|
||||
})
|
||||
const isEventMsg = 'event' in content && !!content.event
|
||||
const isDeleteMsg = 'delete' in content && !!content.delete
|
||||
const isEditMsg = 'edit' in content && !!content.edit
|
||||
const isPinMsg = 'pin' in content && !!content.pin
|
||||
@@ -848,6 +854,13 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
||||
polltype: 'creation'
|
||||
}
|
||||
} as BinaryNode)
|
||||
} else if (isEventMsg) {
|
||||
additionalNodes.push({
|
||||
tag: 'meta',
|
||||
attrs: {
|
||||
event_type: 'creation'
|
||||
}
|
||||
} as BinaryNode)
|
||||
}
|
||||
|
||||
if ('cachedGroupMetadata' in options) {
|
||||
|
||||
@@ -131,6 +131,19 @@ export type PollMessageOptions = {
|
||||
toAnnouncementGroup?: boolean
|
||||
}
|
||||
|
||||
export type EventMessageOptions = {
|
||||
name: string
|
||||
description?: string
|
||||
startDate: Date
|
||||
endDate?: Date
|
||||
location?: WALocationMessage
|
||||
call?: 'audio' | 'video'
|
||||
isCancelled?: boolean
|
||||
isScheduleCall?: boolean
|
||||
extraGuestsAllowed?: boolean
|
||||
messageSecret?: Uint8Array<ArrayBufferLike>
|
||||
}
|
||||
|
||||
type SharePhoneNumber = {
|
||||
sharePhoneNumber: boolean
|
||||
}
|
||||
@@ -203,6 +216,7 @@ export type AnyRegularMessageContent = (
|
||||
Contextable &
|
||||
Editable)
|
||||
| AnyMediaMessageContent
|
||||
| { event: EventMessageOptions }
|
||||
| ({
|
||||
poll: PollMessageOptions
|
||||
} & Mentionable &
|
||||
@@ -327,6 +341,7 @@ export type MediaGenerationOptions = {
|
||||
export type MessageContentGenerationOptions = MediaGenerationOptions & {
|
||||
getUrlInfo?: (text: string) => Promise<WAUrlInfo | undefined>
|
||||
getProfilePicUrl?: (jid: string, type: 'image' | 'preview') => Promise<string | undefined>
|
||||
getCallLink?: (type: 'audio' | 'video', event?: { startTime: number }) => Promise<string | undefined>
|
||||
jid?: string
|
||||
}
|
||||
export type MessageGenerationOptions = MessageContentGenerationOptions & MessageGenerationOptionsFromContent
|
||||
|
||||
+23
-1
@@ -4,7 +4,7 @@ import { randomBytes } from 'crypto'
|
||||
import { promises as fs } from 'fs'
|
||||
import { type Transform } from 'stream'
|
||||
import { proto } from '../../WAProto/index.js'
|
||||
import { MEDIA_KEYS, URL_REGEX, WA_DEFAULT_EPHEMERAL } from '../Defaults'
|
||||
import { CALL_AUDIO_PREFIX, CALL_VIDEO_PREFIX, MEDIA_KEYS, URL_REGEX, WA_DEFAULT_EPHEMERAL } from '../Defaults'
|
||||
import type {
|
||||
AnyMediaMessageContent,
|
||||
AnyMessageContent,
|
||||
@@ -490,6 +490,28 @@ export const generateWAMessageContent = async (
|
||||
})
|
||||
} else if ('listReply' in message) {
|
||||
m.listResponseMessage = { ...message.listReply }
|
||||
} else if ('event' in message) {
|
||||
m.eventMessage = {}
|
||||
const startTime = Math.floor(message.event.startDate.getTime() / 1000)
|
||||
|
||||
if (message.event.call && options.getCallLink) {
|
||||
const token = await options.getCallLink(message.event.call, { startTime })
|
||||
m.eventMessage.joinLink = (message.event.call === 'audio' ? CALL_AUDIO_PREFIX : CALL_VIDEO_PREFIX) + token
|
||||
}
|
||||
|
||||
m.messageContextInfo = {
|
||||
// encKey
|
||||
messageSecret: message.event.messageSecret || randomBytes(32)
|
||||
}
|
||||
|
||||
m.eventMessage.name = message.event.name
|
||||
m.eventMessage.description = message.event.description
|
||||
m.eventMessage.startTime = startTime
|
||||
m.eventMessage.endTime = message.event.endDate ? message.event.endDate.getTime() / 1000 : undefined
|
||||
m.eventMessage.isCanceled = message.event.isCancelled ?? false
|
||||
m.eventMessage.extraGuestsAllowed = message.event.extraGuestsAllowed
|
||||
m.eventMessage.isScheduleCall = message.event.isScheduleCall ?? false
|
||||
m.eventMessage.location = message.event.location
|
||||
} else if ('poll' in message) {
|
||||
message.poll.selectableCount ||= 0
|
||||
message.poll.toAnnouncementGroup ||= false
|
||||
|
||||
Reference in New Issue
Block a user