Deploy: 2026-05-23 23:18:56

This commit is contained in:
Hamza-Ayed
2026-05-23 23:18:56 +03:00
parent bae23e8da7
commit b627a52c6e
3 changed files with 565 additions and 91 deletions

View File

@@ -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 {