diff --git a/Example/example.ts b/Example/example.ts index 09545f1..266f6d6 100644 --- a/Example/example.ts +++ b/Example/example.ts @@ -63,6 +63,8 @@ import makeWASocket, { WASocket, AuthenticationState, DisconnectReason, AnyMessa await delay(2000) await sock.sendPresenceUpdate('paused', jid) + + await sock.sendMessage(jid, msg) } sock = startSock() diff --git a/src/Store/in-memory-store.ts b/src/Store/in-memory-store.ts deleted file mode 100644 index 371d745..0000000 --- a/src/Store/in-memory-store.ts +++ /dev/null @@ -1,293 +0,0 @@ -import type KeyedDB from "@adiwajshing/keyed-db" -import type { Comparable } from "@adiwajshing/keyed-db/lib/Types" -import type { Logger } from "pino" -import type { Connection } from "../Socket" -import type { BaileysEventEmitter, Chat, ConnectionState, Contact, GroupMetadata, MessageInfo, PresenceData, WAMessage, WAMessageCursor, WAMessageKey } from "../Types" -import { toNumber } from "../Utils" -import makeOrderedDictionary from "./ordered-dictionary" - -export const waChatKey = (pin: boolean) => ({ - key: (c: Chat) => (pin ? (c.pin ? '1' : '0') : '') + (c.archive ? '0' : '1') + toNumber(c.conversationTimestamp).toString(16).padStart(8, '0') + c.id, - compare: (k1: string, k2: string) => k2.localeCompare (k1) -}) - -export const waMessageID = (m: WAMessage) => m.key.id - -export type BaileysInMemoryStoreConfig = { - chatKey: Comparable - logger: Logger -} - -const makeMessagesDictionary = () => makeOrderedDictionary(waMessageID) - -export default( - { logger, chatKey }: BaileysInMemoryStoreConfig -) => { - const KeyedDBConstructor = require('@adiwajshing/keyed-db').default as new (...args: any[]) => KeyedDB - const chats = new KeyedDBConstructor(chatKey, c => c.jid) - const messages: { [_: string]: ReturnType } = { } - const contacts: { [_: string]: Contact } = { } - const groupMetadata: { [_: string]: GroupMetadata } = { } - const messageInfos: { [id: string]: MessageInfo } = { } - const presences: { [id: string]: { [participant: string]: PresenceData } } = { } - const state: ConnectionState = { connection: 'close' } - - const assertMessageList = (jid: string) => { - if(!messages[jid]) messages[jid] = makeMessagesDictionary() - return messages[jid] - } - - const listen = (ev: BaileysEventEmitter) => { - - const contactsUpsert = (newContacts: Contact[]) => { - const oldContacts = new Set(Object.keys(contacts)) - for(const contact of newContacts) { - oldContacts.delete(contact.jid) - contacts[contact.jid] = Object.assign( - contacts[contact.jid] || {}, - contact - ) - } - return oldContacts - } - - ev.on('connection.update', update => { - Object.assign(state, update) - }) - ev.on('contacts.set', ({ contacts: newContacts }) => { - const oldContacts = contactsUpsert(newContacts) - for(const jid of oldContacts) { - delete contacts[jid] - } - logger.debug({ deletedContacts: oldContacts.size }, 'synced contacts') - }) - ev.on('contacts.update', updates => { - for(const update of updates) { - if(contacts[update.jid!]) { - Object.assign(contacts[update.jid!], update) - } else { - logger.debug({ update }, `got update for non-existant contact`) - } - } - }) - ev.on('chats.upsert', newChats => { - chats.upsert(...newChats) - }) - ev.on('chats.set', ({ chats: newChats }) => { - chats.upsert(...newChats) - }) - ev.on('chats.update', updates => { - for(const update of updates) { - const result = chats.update(update.jid!, chat => { - Object.assign(chat, update) - }) - if(!result) { - logger.debug({ update }, `got update for non-existant chat`) - } - } - }) - ev.on('presence.update', ({ jid, presences: update }) => { - presences[jid] = presences[jid] || {} - Object.assign(presences[jid], update) - }) - ev.on('chats.delete', deletions => { - for(const item of deletions) { - chats.deleteById(item) - } - }) - ev.on('messages.upsert', ({ messages: newMessages, type }) => { - switch(type) { - case 'append': - case 'notify': - for(const msg of newMessages) { - const jid = msg.key.remoteJid! - const list = assertMessageList(jid) - list.upsert(msg, 'append') - - if(type === 'notify') { - if(!chats.get(jid)) { - ev.emit('chats.upsert', [ - { jid, t: toNumber(msg.messageTimestamp), count: 1 } - ]) - } - // add message infos if required - messageInfos[msg.key.id!] = messageInfos[msg.key.id!] || { reads: {}, deliveries: {} } - } - } - break - case 'last': - logger.info('recv last message on all chats') - for(const msg of newMessages) { - const jid = msg.key.remoteJid! - const list = assertMessageList(jid) - const [lastItem] = list.array.slice(-1) - // reset message list - if(lastItem?.key.id !== msg.key.id) { - list.clear() - list.upsert(msg, 'append') - } - } - break - case 'prepend': - for(const msg of newMessages) { - const jid = msg.key.remoteJid! - const list = assertMessageList(jid) - list.upsert(msg, 'prepend') - } - break - } - }) - ev.on('messages.update', updates => { - for(const { update, key } of updates) { - const list = assertMessageList(key.remoteJid) - const result = list.updateAssign(key.id, update) - if(!result) { - logger.debug({ update }, `got update for non-existent message`) - } - } - }) - ev.on('messages.delete', item => { - const list = assertMessageList(item.jid) - if('all' in item) { - list.clear() - } else { - const idSet = new Set(item.ids) - list.filter(m => !idSet.has(m.key.id)) - } - }) - - ev.on('groups.update', updates => { - for(const update of updates) { - if(groupMetadata[update.id]) { - Object.assign(groupMetadata[update.id!], update) - } else { - logger.debug({ update }, `got update for non-existant group metadata`) - } - } - }) - - ev.on('group-participants.update', ({ jid, participants, action }) => { - const metadata = groupMetadata[jid] - if(metadata) { - switch(action) { - case 'add': - metadata.participants.push(...participants.map(jid => ({ jid, isAdmin: false, isSuperAdmin: false }))) - break - case 'demote': - case 'promote': - for(const participant of metadata.participants) { - if(participants.includes(participant.jid)) { - participant.isAdmin = action === 'promote' - } - } - break - case 'remove': - metadata.participants = metadata.participants.filter(p => !participants.includes(p.jid)) - break - } - } - }) - - ev.on('message-info.update', updates => { - for(const { key, update } of updates) { - const obj = messageInfos[key.id!] - if(obj) { - // add reads/deliveries - for(const key in update) { - Object.assign(obj[key], update[key]) - } - } - } - }) - } - - - return { - chats, - contacts, - messages, - groupMetadata, - messageInfos, - state, - presences, - listen, - /*loadMessages: async(jid: string, count: number, cursor: WAMessageCursor, sock: Connection | undefined) => { - const list = assertMessageList(jid) - const retrieve = async(count: number, cursor: WAMessageCursor) => { - const result = await sock?.fetchMessagesFromWA(jid, count, cursor) - return result || [] - } - const mode = !cursor || 'before' in cursor ? 'before' : 'after' - const cursorKey = !!cursor ? ('before' in cursor ? cursor.before : cursor.after) : undefined - const cursorValue = cursorKey ? list.get(cursorKey.id) : undefined - - let messages: WAMessage[] - if(list && mode === 'before' && (!cursorKey || cursorValue)) { - if(cursorValue) { - const msgIdx = list.array.findIndex(m => m.key.id === cursorKey.id) - messages = list.array.slice(0, msgIdx) - } else { - messages = list.array - } - const diff = count - messages.length - if (diff < 0) { - messages = messages.slice(-count) // get the last X messages - } else if (diff > 0) { - const [fMessage] = messages - const cursor = { before: fMessage?.key || cursorKey } - const extra = await retrieve (diff, cursor) - // add to DB - for(let i = extra.length-1; i >= 0;i--) { - list.upsert(extra[i], 'prepend') - } - messages.splice(0, 0, ...extra) - } - } else messages = await retrieve(count, cursor) - - return messages - }, - loadMessage: async(jid: string, id: string, sock: Connection | undefined) => { - let message = messages[jid]?.get(id) - if(!message) { - message = await sock?.loadMessageFromWA(jid, id) - } - return message - }, - mostRecentMessage: async(jid: string, sock: Connection | undefined) => { - let message = messages[jid]?.array.slice(-1)[0] - if(!message) { - const [result] = await sock?.fetchMessagesFromWA(jid, 1, undefined) - message = result - } - return message - }, - fetchImageUrl: async(jid: string, sock: Connection | undefined) => { - const contact = contacts[jid] - if(!contact) { - return sock?.fetchImageUrl(jid) - } - if(typeof contact.imgUrl === 'undefined') { - contact.imgUrl = await sock?.fetchImageUrl(jid) - } - return contact.imgUrl - }, - fetchGroupMetadata: async(jid: string, sock: Connection | undefined) => { - if(!groupMetadata[jid]) { - groupMetadata[jid] = await sock?.groupMetadata(jid, chats.get(jid)?.read_only === 'true') - } - return groupMetadata[jid] - }, - fetchBroadcastListInfo: async(jid: string, sock: Connection | undefined) => { - if(!groupMetadata[jid]) { - groupMetadata[jid] = await sock?.getBroadcastListInfo(jid) - } - return groupMetadata[jid] - }, - fetchMessageInfo: async({remoteJid, id}: WAMessageKey, sock: Connection | undefined) => { - if(!messageInfos[id!]) { - messageInfos[id!] = await sock?.messageInfo(remoteJid, id) - } - return messageInfos[id!] - }*/ - } -} \ No newline at end of file diff --git a/src/Store/index.ts b/src/Store/index.ts deleted file mode 100644 index 1bfc30c..0000000 --- a/src/Store/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import makeInMemoryStore from './in-memory-store' -export { makeInMemoryStore } \ No newline at end of file diff --git a/src/Store/ordered-dictionary.ts b/src/Store/ordered-dictionary.ts deleted file mode 100644 index a1a7af1..0000000 --- a/src/Store/ordered-dictionary.ts +++ /dev/null @@ -1,77 +0,0 @@ - -const makeOrderedDictionary = function(idGetter: (item: T) => string) { - const array: T[] = [] - const dict: { [_: string]: T } = { } - - const get = (id: string) => dict[id] - - const update = (item: T) => { - const id = idGetter(item) - const idx = array.findIndex(i => idGetter(i) === id) - if(idx >= 0) { - array[idx] = item - dict[id] = item - } - return false - } - - const upsert = (item: T, mode: 'append' | 'prepend') => { - const id = idGetter(item) - if(get(id)) { - update(item) - } else { - if(mode === 'append') { - array.push(item) - } else { - array.splice(0, 0, item) - } - dict[id] = item - } - } - - const remove = (item: T) => { - const id = idGetter(item) - const idx = array.findIndex(i => idGetter(i) === id) - if(idx >= 0) { - array.splice(idx, 1) - delete dict[id] - return true - } - return false - } - - return { - array, - get, - upsert, - update, - remove, - updateAssign: (id: string, update: Partial) => { - const item = get(id) - if(item) { - Object.assign(item, update) - delete dict[id] - dict[idGetter(item)] = item - return true - } - return false - }, - clear: () => { - array.splice(0, array.length) - Object.keys(dict).forEach(key => { delete dict[key] }) - }, - filter: (contain: (item: T) => boolean) => { - let i = 0 - while(i < array.length) { - if(!contain(array[i])) { - delete dict[idGetter(array[i])] - array.splice(i, 1) - } else { - i += 1 - } - } - } - } -} -export default makeOrderedDictionary -//export type OrderedDictionary = ReturnType \ No newline at end of file