Server IP : 103.11.96.170 / Your IP : 18.219.43.26 Web Server : Microsoft-IIS/10.0 System : Windows NT WIN-F6SLGVICLOP 10.0 build 17763 (Windows Server 2016) AMD64 User : elibrary.unsap.ac.id ( 0) PHP Version : 7.4.19 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF Directory (0777) : D:/localhost/dev_admission/baileys-api-master/src/ |
[ Home ] | [ C0mmand ] | [ Upload File ] |
---|
import type { ConnectionState, proto, SocketConfig, WASocket } from '@adiwajshing/baileys'; import makeWASocket, { Browsers, DisconnectReason, isJidBroadcast, makeCacheableSignalKeyStore, } from '@adiwajshing/baileys'; import type { Boom } from '@hapi/boom'; import { initStore, Store, useSession } from '@ookamiiixd/baileys-store'; import type { Response } from 'express'; // import { writeFile } from 'fs/promises'; // import { join } from 'path'; import { toDataURL } from 'qrcode'; import { logger, prisma } from './shared'; type Session = WASocket & { destroy: () => Promise<void>; store: Store; }; const sessions = new Map<string, Session>(); const retries = new Map<string, number>(); const SSEQRGenerations = new Map<string, number>(); const RECONNECT_INTERVAL = Number(process.env.RECONNECT_INTERVAL || 0); const MAX_RECONNECT_RETRIES = Number(process.env.MAX_RECONNECT_RETRIES || 5); const SSE_MAX_QR_GENERATION = Number(process.env.SSE_MAX_QR_GENERATION || 5); const SESSION_CONFIG_ID = 'session-config'; export async function init() { initStore({ prisma, logger }); const sessions = await prisma.session.findMany({ select: { sessionId: true, data: true }, where: { id: { startsWith: SESSION_CONFIG_ID } }, }); for (const { sessionId, data } of sessions) { createSession({ sessionId, socketConfig: JSON.parse(data) }); } } function shouldReconnect(sessionId: string) { let attempts = retries.get(sessionId) ?? 0; if (attempts < MAX_RECONNECT_RETRIES) { attempts += 1; retries.set(sessionId, attempts); return true; } return false; } type createSessionOptions = { sessionId: string; res?: Response; SSE?: boolean; socketConfig?: SocketConfig; }; export async function createSession(options: createSessionOptions) { const { sessionId, res, SSE = false, socketConfig } = options; const configID = `${SESSION_CONFIG_ID}-${sessionId}`; let connectionState: Partial<ConnectionState> = { connection: 'close' }; const destroy = async (logout = true) => { try { await Promise.all([ logout && socket.logout(), prisma.chat.deleteMany({ where: { sessionId } }), prisma.contact.deleteMany({ where: { sessionId } }), prisma.message.deleteMany({ where: { sessionId } }), prisma.groupMetadata.deleteMany({ where: { sessionId } }), prisma.session.deleteMany({ where: { sessionId } }), ]); } catch (e) { logger.error(e, 'An error occured during session destroy'); } finally { sessions.delete(sessionId); } }; const handleConnectionClose = () => { const code = (connectionState.lastDisconnect?.error as Boom)?.output?.statusCode; const restartRequired = code === DisconnectReason.restartRequired; const doNotReconnect = !shouldReconnect(sessionId); if (code === DisconnectReason.loggedOut || doNotReconnect) { if (res) { !SSE && !res.headersSent && res.status(500).json({ error: 'Unable to create session' }); res.end(); } destroy(doNotReconnect); return; } if (!restartRequired) { logger.info({ attempts: retries.get(sessionId) ?? 1, sessionId }, 'Reconnecting...'); } setTimeout(() => createSession(options), restartRequired ? 0 : RECONNECT_INTERVAL); }; const handleNormalConnectionUpdate = async () => { if (connectionState.qr?.length) { if (res && !res.headersSent) { try { const qr = await toDataURL(connectionState.qr); res.status(200).json({ qr }); return; } catch (e) { logger.error(e, 'An error occured during QR generation'); res.status(500).json({ error: 'Unable to generate QR' }); } } destroy(); } }; const handleSSEConnectionUpdate = async () => { let qr: string | undefined = undefined; if (connectionState.qr?.length) { try { qr = await toDataURL(connectionState.qr); } catch (e) { logger.error(e, 'An error occured during QR generation'); } } const currentGenerations = SSEQRGenerations.get(sessionId) ?? 0; if (!res || res.writableEnded || (qr && currentGenerations >= SSE_MAX_QR_GENERATION)) { res && !res.writableEnded && res.end(); destroy(); return; } const data = { ...connectionState, qr }; if (qr) SSEQRGenerations.set(sessionId, currentGenerations + 1); res.write(`data: ${JSON.stringify(data)}\n\n`); }; const handleConnectionUpdate = SSE ? handleSSEConnectionUpdate : handleNormalConnectionUpdate; const { state, saveCreds } = await useSession(sessionId); const socket = makeWASocket({ printQRInTerminal: true, browser: Browsers.ubuntu('Chrome'), generateHighQualityLinkPreview: true, ...socketConfig, auth: { creds: state.creds, keys: makeCacheableSignalKeyStore(state.keys, logger), }, logger, shouldIgnoreJid: (jid) => isJidBroadcast(jid), getMessage: async (key) => { const data = await prisma.message.findFirst({ where: { remoteJid: key.remoteJid!, id: key.id!, sessionId }, }); return (data?.message || undefined) as proto.IMessage | undefined; }, }); const store = new Store(sessionId, socket.ev); sessions.set(sessionId, { ...socket, destroy, store }); socket.ev.on('creds.update', saveCreds); socket.ev.on('connection.update', (update) => { connectionState = update; const { connection } = update; if (connection === 'open') { retries.delete(sessionId); SSEQRGenerations.delete(sessionId); } if (connection === 'close') handleConnectionClose(); handleConnectionUpdate(); }); // Debug events // socket.ev.on('messaging-history.set', (data) => dump('messaging-history.set', data)); // socket.ev.on('chats.upsert', (data) => dump('chats.upsert', data)); // socket.ev.on('contacts.update', (data) => dump('contacts.update', data)); // socket.ev.on('groups.upsert', (data) => dump('groups.upsert', data)); await prisma.session.upsert({ create: { id: configID, sessionId, data: JSON.stringify(socketConfig || {}) }, update: {}, where: { sessionId_id: { id: configID, sessionId } }, }); } export function getSession(sessionId: string) { return sessions.get(sessionId); } export async function deleteSession(sessionId: string) { sessions.get(sessionId)?.destroy(); } export function sessionExists(sessionId: string) { return sessions.has(sessionId); } export async function jidExists( session: Session, jid: string, type: 'group' | 'number' = 'number' ) { try { if (type === 'number') { const [result] = await session.onWhatsApp(jid); return !!result?.exists; } const groupMeta = await session.groupMetadata(jid); return !!groupMeta.id; } catch (e) { return Promise.reject(e); } } // eslint-disable-next-line @typescript-eslint/no-explicit-any // export async function dump(fileName: string, data: any) { // const path = join(__dirname, '..', 'debug', `${fileName}.json`); // await writeFile(path, JSON.stringify(data, null, 2)); // }