mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
231 lines
9.6 KiB
TypeScript
231 lines
9.6 KiB
TypeScript
import WAConnection from '../WAConnection/WAConnection'
|
|
import { MessageStatus, MessageStatusUpdate, PresenceUpdate } from './Constants'
|
|
import {
|
|
WAMessage,
|
|
WANode,
|
|
WAMetric,
|
|
WAFlag,
|
|
WAGroupCreateResponse,
|
|
WAGroupMetadata,
|
|
WAGroupModification,
|
|
MessageLogLevel,
|
|
} from '../WAConnection/Constants'
|
|
import { generateMessageTag } from '../WAConnection/Utils'
|
|
|
|
export default class WhatsAppWebBase extends WAConnection {
|
|
/** Set the callback for unexpected disconnects */
|
|
setOnUnexpectedDisconnect(callback: (error: Error) => void) {
|
|
this.unexpectedDisconnect = (err) => {
|
|
this.close()
|
|
callback(err)
|
|
}
|
|
}
|
|
/** Set the callback for message status updates (when a message is delivered, read etc.) */
|
|
setOnMessageStatusChange(callback: (update: MessageStatusUpdate) => void) {
|
|
const func = (json) => {
|
|
json = json[1]
|
|
let ids = json.id
|
|
if (json.cmd === 'ack') {
|
|
ids = [json.id]
|
|
}
|
|
const ackTypes = [MessageStatus.sent, MessageStatus.received, MessageStatus.read]
|
|
const data: MessageStatusUpdate = {
|
|
from: json.from,
|
|
to: json.to,
|
|
participant: json.participant,
|
|
timestamp: new Date(json.t * 1000),
|
|
ids: ids,
|
|
type: ackTypes[json.ack - 1] || 'unknown (' + json.ack + ')',
|
|
}
|
|
callback(data)
|
|
}
|
|
this.registerCallback('Msg', func)
|
|
this.registerCallback('MsgInfo', func)
|
|
}
|
|
/**
|
|
* Set the callback for new/unread messages; if someone sends you a message, this callback will be fired
|
|
* @param callbackOnMyMessages - should the callback be fired on a message you sent from the phone
|
|
*/
|
|
setOnUnreadMessage(callbackOnMyMessages = false, callback: (m: WAMessage) => void) {
|
|
this.registerCallback(['action', 'add:relay', 'message'], (json) => {
|
|
const message = json[2][0][2]
|
|
if (!message.key.fromMe || callbackOnMyMessages) {
|
|
// if this message was sent to us, notify
|
|
callback(message as WAMessage)
|
|
} else if (this.logLevel >= MessageLogLevel.unhandled) {
|
|
this.log(`[Unhandled] message - ${JSON.stringify(message)}`)
|
|
}
|
|
})
|
|
}
|
|
/** Set the callback for presence updates; if someone goes offline/online, this callback will be fired */
|
|
setOnPresenceUpdate(callback: (p: PresenceUpdate) => void) {
|
|
this.registerCallback('Presence', (json) => callback(json[1]))
|
|
}
|
|
/** Query whether a given number is registered on WhatsApp */
|
|
isOnWhatsApp = (jid: string) => this.query(['query', 'exist', jid]).then((m) => m.status === 200)
|
|
/** Request an update on the presence of a user */
|
|
requestPresenceUpdate = (jid: string) => this.queryExpecting200(['action', 'presence', 'subscribe', jid])
|
|
/** Query the status of the person (see groupMetadata() for groups) */
|
|
getStatus = (jid: string | null) =>
|
|
this.query(['query', 'Status', jid || this.userMetaData.id]) as Promise<{ status: string }>
|
|
/** Get the URL to download the profile picture of a person/group */
|
|
async getProfilePicture(jid: string | null) {
|
|
const response = await this.queryExpecting200(['query', 'ProfilePicThumb', jid || this.userMetaData.id])
|
|
return response.eurl as string
|
|
}
|
|
/** Get your contacts */
|
|
async getContacts() {
|
|
const json = ['query', { epoch: this.msgCount.toString(), type: 'contacts' }, null]
|
|
const response = await this.query(json, [WAMetric.group, WAFlag.ignore]) // this has to be an encrypted query
|
|
console.log(response)
|
|
return response
|
|
}
|
|
/** Fetch your chats */
|
|
getChats() {
|
|
const json = ['query', { epoch: this.msgCount.toString(), type: 'chat' }, null]
|
|
return this.query(json, [WAMetric.group, WAFlag.ignore]) // this has to be an encrypted query
|
|
}
|
|
/**
|
|
* Check if your phone is connected
|
|
* @param timeoutMs max time for the phone to respond
|
|
*/
|
|
async isPhoneConnected(timeoutMs = 5000) {
|
|
try {
|
|
const response = await this.query(['admin', 'test'], null, timeoutMs)
|
|
return response[1] as boolean
|
|
} catch (error) {
|
|
return false
|
|
}
|
|
}
|
|
/**
|
|
* Load the conversation with a group or person
|
|
* @param count the number of messages to load
|
|
* @param [indexMessage] the data for which message to offset the query by
|
|
* @param [mostRecentFirst] retreive the most recent message first or retreive from the converation start
|
|
*/
|
|
async loadConversation(
|
|
jid: string,
|
|
count: number,
|
|
indexMessage: { id: string; fromMe: boolean } = null,
|
|
mostRecentFirst = true,
|
|
) {
|
|
const json = [
|
|
'query',
|
|
{
|
|
epoch: this.msgCount.toString(),
|
|
type: 'message',
|
|
jid: jid,
|
|
kind: mostRecentFirst ? 'before' : 'after',
|
|
count: count.toString(),
|
|
index: indexMessage?.id,
|
|
owner: indexMessage?.fromMe === false ? 'false' : 'true',
|
|
},
|
|
null,
|
|
]
|
|
const response = await this.query(json, [WAMetric.group, WAFlag.ignore])
|
|
|
|
if (response.status) throw new Error(`error in query, got status: ${response.status}`)
|
|
|
|
return response[2] ? (response[2] as WANode[]).map((item) => item[2] as WAMessage) : []
|
|
}
|
|
/**
|
|
* Load the entire friggin conversation with a group or person
|
|
* @param onMessage callback for every message retreived
|
|
* @param [chunkSize] the number of messages to load in a single request
|
|
* @param [mostRecentFirst] retreive the most recent message first or retreive from the converation start
|
|
*/
|
|
loadEntireConversation(jid: string, onMessage: (m: WAMessage) => void, chunkSize = 25, mostRecentFirst = true) {
|
|
let offsetID = null
|
|
|
|
const loadMessage = async () => {
|
|
const json = await this.loadConversation(jid, chunkSize, offsetID, mostRecentFirst)
|
|
// callback with most recent message first (descending order of date)
|
|
let lastMessage
|
|
if (mostRecentFirst) {
|
|
for (let i = json.length - 1; i >= 0; i--) {
|
|
onMessage(json[i])
|
|
lastMessage = json[i]
|
|
}
|
|
} else {
|
|
for (let i = 0; i < json.length; i++) {
|
|
onMessage(json[i])
|
|
lastMessage = json[i]
|
|
}
|
|
}
|
|
// if there are still more messages
|
|
if (json.length >= chunkSize) {
|
|
offsetID = lastMessage.key // get the last message
|
|
return new Promise((resolve, reject) => {
|
|
// send query after 200 ms
|
|
setTimeout(() => loadMessage().then(resolve).catch(reject), 200)
|
|
})
|
|
}
|
|
}
|
|
return loadMessage() as Promise<void>
|
|
}
|
|
/** Generic function for group queries */
|
|
groupQuery(type: string, jid?: string, subject?: string, participants?: string[]) {
|
|
const json: WANode = [
|
|
'group',
|
|
{
|
|
author: this.userMetaData.id,
|
|
id: generateMessageTag(),
|
|
type: type,
|
|
jid: jid,
|
|
subject: subject,
|
|
},
|
|
participants ? participants.map((str) => ['participant', { jid: str }, null]) : [],
|
|
]
|
|
const q = ['action', { type: 'set', epoch: this.msgCount.toString() }, [json]]
|
|
return this.queryExpecting200(q, [WAMetric.group, WAFlag.ignore])
|
|
}
|
|
/** Get the metadata of the group */
|
|
groupMetadata = (jid: string) => this.queryExpecting200(['query', 'GroupMetadata', jid]) as Promise<WAGroupMetadata>
|
|
/**
|
|
* Create a group
|
|
* @param title like, the title of the group
|
|
* @param participants people to include in the group
|
|
*/
|
|
groupCreate = (title: string, participants: string[]) =>
|
|
this.groupQuery('create', null, title, participants) as Promise<WAGroupCreateResponse>
|
|
/**
|
|
* Leave a group
|
|
* @param jid the ID of the group
|
|
*/
|
|
groupLeave = (jid: string) => this.groupQuery('leave', jid) as Promise<{ status: number }>
|
|
/**
|
|
* Update the subject of the group
|
|
* @param {string} jid the ID of the group
|
|
* @param {string} title the new title of the group
|
|
*/
|
|
groupUpdateSubject = (jid: string, title: string) =>
|
|
this.groupQuery('subject', jid, title) as Promise<{ status: number }>
|
|
/**
|
|
* Add somebody to the group
|
|
* @param jid the ID of the group
|
|
* @param participants the people to add
|
|
*/
|
|
groupAdd = (jid: string, participants: string[]) =>
|
|
this.groupQuery('add', jid, null, participants) as Promise<WAGroupModification>
|
|
/**
|
|
* Remove somebody from the group
|
|
* @param jid the ID of the group
|
|
* @param participants the people to remove
|
|
*/
|
|
groupRemove = (jid: string, participants: string[]) =>
|
|
this.groupQuery('remove', jid, null, participants) as Promise<WAGroupModification>
|
|
/**
|
|
* Make someone admin on the group
|
|
* @param jid the ID of the group
|
|
* @param participants the people to make admin
|
|
*/
|
|
groupMakeAdmin = (jid: string, participants: string[]) =>
|
|
this.groupQuery('promote', jid, null, participants) as Promise<WAGroupModification>
|
|
/** Get the invite link of the given group */
|
|
async groupInviteCode(jid: string) {
|
|
const json = ['query', 'inviteCode', jid]
|
|
const response = await this.queryExpecting200(json)
|
|
return response.code as string
|
|
}
|
|
}
|