Deploy: 2026-05-23 23:18:56
This commit is contained in:
@@ -1,12 +1,178 @@
|
||||
const baileys = require('@whiskeysockets/baileys');
|
||||
const makeWASocket = baileys.default || baileys.makeWASocket || baileys;
|
||||
const { useMultiFileAuthState, DisconnectReason, fetchLatestBaileysVersion, downloadMediaMessage, makeCacheableSignalKeyStore, makeInMemoryStore } = baileys;
|
||||
const { useMultiFileAuthState, DisconnectReason, fetchLatestBaileysVersion, downloadMediaMessage, makeCacheableSignalKeyStore } = baileys;
|
||||
const pino = require('pino');
|
||||
const NodeCache = require('node-cache');
|
||||
const axios = require('axios');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
class InMemoryStore {
|
||||
constructor() {
|
||||
this.chats = {
|
||||
dict: {},
|
||||
all() { return Object.values(this.dict); },
|
||||
get(id) { return this.dict[id]; },
|
||||
set(id, chat) { this.dict[id] = chat; },
|
||||
delete(id) { delete this.dict[id]; }
|
||||
};
|
||||
this.messages = new Proxy({}, {
|
||||
get: (target, jid) => {
|
||||
if (typeof jid === 'symbol') return target[jid];
|
||||
return this.getMessages(jid);
|
||||
}
|
||||
});
|
||||
this.messagesData = {};
|
||||
this.contacts = {};
|
||||
}
|
||||
|
||||
getMessages(jid) {
|
||||
if (!this.messagesData[jid]) {
|
||||
this.messagesData[jid] = {
|
||||
dict: {},
|
||||
all() {
|
||||
return Object.values(this.dict).sort((a, b) => {
|
||||
const tA = Number(a.messageTimestamp || 0);
|
||||
const tB = Number(b.messageTimestamp || 0);
|
||||
return tA - tB;
|
||||
});
|
||||
},
|
||||
get(id) { return this.dict[id]; },
|
||||
set(id, msg) { this.dict[id] = msg; },
|
||||
delete(id) { delete this.dict[id]; }
|
||||
};
|
||||
}
|
||||
return this.messagesData[jid];
|
||||
}
|
||||
|
||||
bind(ev) {
|
||||
ev.on('messaging-history.set', ({ chats, messages, contacts }) => {
|
||||
console.log(`[Store] Synced history: chats=${chats?.length || 0}, messages=${messages?.length || 0}, contacts=${contacts?.length || 0}`);
|
||||
if (chats) {
|
||||
for (const chat of chats) {
|
||||
this.chats.set(chat.id, { ...(this.chats.get(chat.id) || {}), ...chat });
|
||||
}
|
||||
}
|
||||
if (contacts) {
|
||||
for (const contact of contacts) {
|
||||
this.contacts[contact.id] = { ...(this.contacts[contact.id] || {}), ...contact };
|
||||
const chat = this.chats.get(contact.id);
|
||||
if (chat) {
|
||||
chat.name = contact.name || contact.verifiedName || contact.notify;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (messages) {
|
||||
for (const msg of messages) {
|
||||
const jid = msg.key.remoteJid;
|
||||
if (jid) {
|
||||
this.getMessages(jid).set(msg.key.id, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ev.on('chats.upsert', (newChats) => {
|
||||
for (const chat of newChats) {
|
||||
this.chats.set(chat.id, { ...(this.chats.get(chat.id) || {}), ...chat });
|
||||
}
|
||||
});
|
||||
|
||||
ev.on('chats.update', (updates) => {
|
||||
for (const update of updates) {
|
||||
const current = this.chats.get(update.id);
|
||||
if (current) {
|
||||
this.chats.set(update.id, { ...current, ...update });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ev.on('chats.delete', (deletions) => {
|
||||
for (const id of deletions) {
|
||||
this.chats.delete(id);
|
||||
}
|
||||
});
|
||||
|
||||
ev.on('messages.upsert', ({ messages, type }) => {
|
||||
if (type === 'notify' || type === 'append') {
|
||||
for (const msg of messages) {
|
||||
const jid = msg.key.remoteJid;
|
||||
if (jid) {
|
||||
this.getMessages(jid).set(msg.key.id, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ev.on('messages.update', (updates) => {
|
||||
for (const update of updates) {
|
||||
const jid = update.key.remoteJid;
|
||||
if (jid) {
|
||||
const storeMsgs = this.getMessages(jid);
|
||||
const current = storeMsgs.get(update.key.id);
|
||||
if (current) {
|
||||
storeMsgs.set(update.key.id, { ...current, ...update });
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ev.on('contacts.upsert', (newContacts) => {
|
||||
for (const contact of newContacts) {
|
||||
this.contacts[contact.id] = { ...(this.contacts[contact.id] || {}), ...contact };
|
||||
}
|
||||
});
|
||||
|
||||
ev.on('contacts.update', (updates) => {
|
||||
for (const update of updates) {
|
||||
const id = update.id;
|
||||
if (id && this.contacts[id]) {
|
||||
this.contacts[id] = { ...this.contacts[id], ...update };
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
readFromFile(filePath) {
|
||||
if (fs.existsSync(filePath)) {
|
||||
try {
|
||||
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
||||
this.chats.dict = data.chats || {};
|
||||
this.contacts = data.contacts || {};
|
||||
if (data.messages) {
|
||||
for (const jid in data.messages) {
|
||||
const msgs = data.messages[jid];
|
||||
const storeMsgs = this.getMessages(jid);
|
||||
storeMsgs.dict = msgs || {};
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`[Store] Failed to read store file:`, e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writeToFile(filePath) {
|
||||
try {
|
||||
const data = {
|
||||
chats: this.chats.dict,
|
||||
contacts: this.contacts,
|
||||
messages: {}
|
||||
};
|
||||
for (const jid in this.messagesData) {
|
||||
data.messages[jid] = this.messagesData[jid].dict;
|
||||
}
|
||||
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8');
|
||||
} catch (e) {
|
||||
console.error(`[Store] Failed to write store file:`, e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function makeInMemoryStore() {
|
||||
return new InMemoryStore();
|
||||
}
|
||||
|
||||
const sessions = new Map(); // Store active sockets in memory
|
||||
const retryCounters = new Map(); // Track reconnection attempts per session
|
||||
const recentMessages = new Map(); // Cache of recent messages in memory to serve getMessage callback
|
||||
@@ -59,6 +225,28 @@ async function startSession(session_key, webhook_url) {
|
||||
const sessionFolder = path.join(SESSIONS_DIR, session_key);
|
||||
const { state, saveCreds } = await useMultiFileAuthState(sessionFolder);
|
||||
|
||||
// Initialize InMemoryStore for chat history
|
||||
const store = makeInMemoryStore({ logger: pino({ level: 'silent' }) });
|
||||
const storeFile = path.join(SESSIONS_DIR, `${session_key}_store.json`);
|
||||
if (fs.existsSync(storeFile)) {
|
||||
try {
|
||||
store.readFromFile(storeFile);
|
||||
console.log(`[Store] Loaded store from file for ${session_key}`);
|
||||
} catch (e) {
|
||||
console.error(`[Store] Failed to load store file for ${session_key}:`, e.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Periodically save store to file every 10 seconds
|
||||
const storeInterval = setInterval(() => {
|
||||
try {
|
||||
store.writeToFile(storeFile);
|
||||
} catch (e) {
|
||||
console.error(`[Store] Failed to write store file for ${session_key}:`, e.message);
|
||||
}
|
||||
}, 10000);
|
||||
storeIntervals.set(session_key, storeInterval);
|
||||
|
||||
// Fetch the latest WhatsApp Web version to avoid 405 rejection
|
||||
let version;
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user