diff --git a/package-lock.json b/package-lock.json index 17553e8..7decf41 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "dotenv": "^16.4.5", "express": "^4.21.1", "express-rate-limit": "^7.4.1", + "pino": "^9.5.0", "qr-image": "^3.2.0", "qrcode-terminal": "^0.12.0", "swagger-ui-express": "^5.0.1", @@ -1697,6 +1698,15 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -3605,6 +3615,15 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-redact": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/fast-safe-stringify": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", @@ -6122,6 +6141,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -6328,6 +6356,43 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pino": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.5.0.tgz", + "integrity": "sha512-xSEmD4pLnV54t0NOUN16yCl7RIB1c5UUOse5HSyEXtBp+FgFQyPeDutc+Q2ZO7/22vImV7VfEjH/1zV2QuqvYw==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^4.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", + "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz", + "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==", + "license": "MIT" + }, "node_modules/pirates": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", @@ -6462,6 +6527,12 @@ "license": "MIT", "optional": true }, + "node_modules/process-warning": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-4.0.0.tgz", + "integrity": "sha512-/MyYDxttz7DfGMMHiysAsFE4qF+pQYAA8ziO/3NcRVrQ5fSk+Mns4QZA/oRPFzvcqNoVJXQNWNAsdwBXLUkQKw==", + "license": "MIT" + }, "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -6652,6 +6723,12 @@ ], "license": "MIT" }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -6730,6 +6807,15 @@ "node": ">=10" } }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.7.tgz", @@ -6963,6 +7049,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -7153,6 +7248,15 @@ "node": ">=8" } }, + "node_modules/sonic-boom": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz", + "integrity": "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -7174,6 +7278,15 @@ "source-map": "^0.6.0" } }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -7538,6 +7651,15 @@ "dev": true, "license": "MIT" }, + "node_modules/thread-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", + "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + } + }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", diff --git a/package.json b/package.json index 87b9d60..d7c95de 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "dotenv": "^16.4.5", "express": "^4.21.1", "express-rate-limit": "^7.4.1", + "pino": "^9.5.0", "qr-image": "^3.2.0", "qrcode-terminal": "^0.12.0", "swagger-ui-express": "^5.0.1", diff --git a/server.js b/server.js index 7a727c5..2b171af 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,6 @@ const app = require('./src/app') const { baseWebhookURL } = require('./src/config') +const { logger } = require('./src/logger') require('dotenv').config() // Start the server @@ -7,12 +8,12 @@ const port = process.env.PORT || 3000 // Check if BASE_WEBHOOK_URL environment variable is available if (!baseWebhookURL) { - console.error('BASE_WEBHOOK_URL environment variable is not set. Exiting...') + logger.error('BASE_WEBHOOK_URL environment variable is not set. Exiting...') process.exit(1) // Terminate the application with an error code } app.listen(port, () => { - console.log(`Server running on port ${port}`) + logger.info(`Server running on port ${port}`) }) // puppeteer uses subscriptions to SIGINT, SIGTERM, and SIGHUP to know when to close browser instances diff --git a/src/config.js b/src/config.js index 1e03954..0443f66 100644 --- a/src/config.js +++ b/src/config.js @@ -18,6 +18,7 @@ const recoverSessions = (process.env.RECOVER_SESSIONS || '').toLowerCase() === ' const chromeBin = process.env.CHROME_BIN || null const headless = process.env.HEADLESS ? (process.env.HEADLESS).toLowerCase() === 'true' : true const releaseBrowserLock = process.env.RELEASE_BROWSER_LOCK ? (process.env.RELEASE_BROWSER_LOCK).toLowerCase() === 'true' : true +const logLevel = process.env.LOGLEVEL || 'info' module.exports = { sessionFolderPath, @@ -35,5 +36,6 @@ module.exports = { recoverSessions, chromeBin, headless, - releaseBrowserLock + releaseBrowserLock, + logLevel } diff --git a/src/controllers/clientController.js b/src/controllers/clientController.js index 7856b81..680cf8f 100644 --- a/src/controllers/clientController.js +++ b/src/controllers/clientController.js @@ -105,11 +105,10 @@ const sendMessage = async (req, res) => { break } default: - return sendErrorResponse(res, 400, 'contentType invalid, must be string, MessageMedia, MessageMediaFromURL, Location, Buttons, List, Contact or Poll') + return sendErrorResponse(res, 400, 'invalid contentType') } res.json({ success: true, message: messageOut }) } catch (error) { - console.log(error) sendErrorResponse(res, 500, error.message) } } diff --git a/src/controllers/healthController.js b/src/controllers/healthController.js index 0e1c347..ee00a39 100644 --- a/src/controllers/healthController.js +++ b/src/controllers/healthController.js @@ -2,6 +2,7 @@ const fsp = require('fs').promises const qrcode = require('qrcode-terminal') const { sessionFolderPath } = require('../config') const { sendErrorResponse } = require('../utils') +const { logger } = require('../logger') /** * Responds to request with 'pong' @@ -77,7 +78,7 @@ const localCallbackExample = async (req, res) => { } } */ - console.log(error) + logger.error(error, 'Failed to handle local callback') sendErrorResponse(res, 500, error.message) } } diff --git a/src/controllers/sessionController.js b/src/controllers/sessionController.js index 4d4f447..85276a4 100644 --- a/src/controllers/sessionController.js +++ b/src/controllers/sessionController.js @@ -1,6 +1,7 @@ const qr = require('qr-image') const { setupSession, deleteSession, reloadSession, validateSession, flushSessions, sessions } = require('../sessions') const { sendErrorResponse, waitForNestedObject } = require('../utils') +const { logger } = require('../logger') /** * Starts a session for the given session ID. @@ -16,8 +17,8 @@ const { sendErrorResponse, waitForNestedObject } = require('../utils') const startSession = async (req, res) => { // #swagger.summary = 'Start new session' // #swagger.description = 'Starts a session for the given session ID.' + const sessionId = req.params.sessionId try { - const sessionId = req.params.sessionId const setupSessionReturn = await setupSession(sessionId) if (!setupSessionReturn.success) { /* #swagger.responses[422] = { @@ -45,7 +46,7 @@ const startSession = async (req, res) => { await waitForNestedObject(setupSessionReturn.client, 'pupPage') res.json({ success: true, message: setupSessionReturn.message }) } catch (error) { - console.log('startSession ERROR', error) + logger.error({ sessionId, err: error }, 'Failed to start session') sendErrorResponse(res, 500, error.message) } } @@ -64,8 +65,8 @@ const startSession = async (req, res) => { const statusSession = async (req, res) => { // #swagger.summary = 'Get session status' // #swagger.description = 'Status of the session with the given session ID.' + const sessionId = req.params.sessionId try { - const sessionId = req.params.sessionId const sessionData = await validateSession(sessionId) /* #swagger.responses[200] = { description: "Status of the session.", @@ -78,7 +79,7 @@ const statusSession = async (req, res) => { */ res.json(sessionData) } catch (error) { - console.log('statusSession ERROR', error) + logger.error({ sessionId, err: error }, 'Failed to get session status') sendErrorResponse(res, 500, error.message) } } @@ -97,8 +98,8 @@ const statusSession = async (req, res) => { const sessionQrCode = async (req, res) => { // #swagger.summary = 'Get session QR code' // #swagger.description = 'QR code of the session with the given session ID.' + const sessionId = req.params.sessionId try { - const sessionId = req.params.sessionId const session = sessions.get(sessionId) if (!session) { return res.json({ success: false, message: 'session_not_found' }) @@ -108,7 +109,7 @@ const sessionQrCode = async (req, res) => { } return res.json({ success: false, message: 'qr code not ready or already scanned' }) } catch (error) { - console.log('sessionQrCode ERROR', error) + logger.error({ sessionId, err: error }, 'Failed to get session qr code') sendErrorResponse(res, 500, error.message) } } @@ -127,8 +128,8 @@ const sessionQrCode = async (req, res) => { const sessionQrCodeImage = async (req, res) => { // #swagger.summary = 'Get session QR code as image' // #swagger.description = 'QR code as image of the session with the given session ID.' + const sessionId = req.params.sessionId try { - const sessionId = req.params.sessionId const session = sessions.get(sessionId) if (!session) { return res.json({ success: false, message: 'session_not_found' }) @@ -149,7 +150,7 @@ const sessionQrCodeImage = async (req, res) => { } return res.json({ success: false, message: 'qr code not ready or already scanned' }) } catch (error) { - console.log('sessionQrCodeImage ERROR', error) + logger.error({ sessionId, err: error }, 'Failed to get session qr code image') sendErrorResponse(res, 500, error.message) } } @@ -168,8 +169,8 @@ const sessionQrCodeImage = async (req, res) => { const restartSession = async (req, res) => { // #swagger.summary = 'Restart session' // #swagger.description = 'Restarts the session with the given session ID.' + const sessionId = req.params.sessionId try { - const sessionId = req.params.sessionId const validation = await validateSession(sessionId) if (validation.message === 'session_not_found') { return res.json(validation) @@ -186,7 +187,7 @@ const restartSession = async (req, res) => { */ res.json({ success: true, message: 'Restarted successfully' }) } catch (error) { - console.log('restartSession ERROR', error) + logger.error({ sessionId, err: error }, 'Failed to restart session') sendErrorResponse(res, 500, error.message) } } @@ -205,8 +206,8 @@ const restartSession = async (req, res) => { const terminateSession = async (req, res) => { // #swagger.summary = 'Terminate session' // #swagger.description = 'Terminates the session with the given session ID.' + const sessionId = req.params.sessionId try { - const sessionId = req.params.sessionId const validation = await validateSession(sessionId) if (validation.message === 'session_not_found') { return res.json(validation) @@ -223,7 +224,7 @@ const terminateSession = async (req, res) => { */ res.json({ success: true, message: 'Logged out successfully' }) } catch (error) { - console.log('terminateSession ERROR', error) + logger.error({ sessionId, err: error }, 'Failed to terminate session') sendErrorResponse(res, 500, error.message) } } @@ -254,7 +255,7 @@ const terminateInactiveSessions = async (req, res) => { */ res.json({ success: true, message: 'Flush completed successfully' }) } catch (error) { - console.log('terminateInactiveSessions ERROR', error) + logger.error(error, 'Failed to terminate inactive sessions') sendErrorResponse(res, 500, error.message) } } @@ -285,7 +286,7 @@ const terminateAllSessions = async (req, res) => { */ res.json({ success: true, message: 'Flush completed successfully' }) } catch (error) { - console.log('terminateAllSessions ERROR', error) + logger.error(error, 'Failed to terminate all sessions') sendErrorResponse(res, 500, error.message) } } diff --git a/src/logger.js b/src/logger.js new file mode 100644 index 0000000..f2cc3e7 --- /dev/null +++ b/src/logger.js @@ -0,0 +1,12 @@ +const { logLevel } = require('./config') +const pino = require('pino') + +const logger = pino({ + level: logLevel +}, pino.destination(1, { sync: false })) + +logger.on('level-change', (lvl, val, prevLvl, prevVal) => { + logger.info('%s (%d) was changed to %s (%d)', prevLvl, prevVal, lvl, val) +}) + +module.exports = { logger } diff --git a/src/sessions.js b/src/sessions.js index 44c6236..6d27ced 100644 --- a/src/sessions.js +++ b/src/sessions.js @@ -3,7 +3,8 @@ const fs = require('fs') const path = require('path') const sessions = new Map() const { baseWebhookURL, sessionFolderPath, maxAttachmentSize, setMessagesAsSeen, webVersion, webVersionCacheType, recoverSessions, chromeBin, headless, releaseBrowserLock } = require('./config') -const { triggerWebhook, waitForNestedObject, checkIfEventisEnabled } = require('./utils') +const { triggerWebhook, waitForNestedObject, checkIfEventisEnabled, sendMessageSeenStatus } = require('./utils') +const { logger } = require('./logger') // Function to validate if the session is ready const validateSession = async (sessionId) => { @@ -53,7 +54,7 @@ const validateSession = async (sessionId) => { returnData.message = 'session_connected' return returnData } catch (error) { - console.log(error) + logger.error({ sessionId, err: error }, 'Failed to validate session') return { success: false, state: null, message: error.message } } } @@ -72,14 +73,13 @@ const restoreSessions = () => { const match = file.match(/^session-(.+)$/) if (match) { const sessionId = match[1] - console.log('existing session detected', sessionId) + logger.warn({ sessionId }, 'existing session detected') await setupSession(sessionId) } } }) } catch (error) { - console.log(error) - console.error('Failed to restore sessions:', error) + logger.error(error, 'Failed to restore sessions') } } @@ -131,7 +131,7 @@ const setupSession = async (sessionId) => { const singletonLockPath = path.resolve(path.join(sessionFolderPath, `session-${sessionId}`, 'SingletonLock')) const singletonLockExists = await fs.promises.lstat(singletonLockPath).then(() => true).catch(() => false) if (singletonLockExists) { - console.log('Browser lock file exists, removing ', sessionId) + logger.warn({ sessionId }, 'Browser lock file exists, removing') await fs.promises.unlink(singletonLockPath) } } @@ -139,7 +139,7 @@ const setupSession = async (sessionId) => { try { await client.initialize() } catch (error) { - console.log('Initialize error:', error.message) + logger.error({ sessionId, err: error }, 'Initialize error') throw error } @@ -166,12 +166,12 @@ const initializeEvents = (client, sessionId) => { } client.pupPage.once('close', function () { // emitted when the page closes - console.log(`Browser page closed for ${sessionId}. Restoring`) + logger.warn({ sessionId }, 'Browser page closed. Restoring') restartSession(sessionId) }) client.pupPage.once('error', function () { // emitted when the page crashes - console.log(`Error occurred on browser page for ${sessionId}. Restoring`) + logger.warn({ sessionId }, 'Error occurred on browser page. Restoring') restartSession(sessionId) }) }).catch(e => { }) @@ -270,14 +270,13 @@ const initializeEvents = (client, sessionId) => { checkIfEventisEnabled('media').then(_ => { message.downloadMedia().then(messageMedia => { triggerWebhook(sessionWebhook, sessionId, 'media', { messageMedia, message }) - }).catch(e => { - console.log('Download media error:', e.message) + }).catch(error => { + logger.error({ sessionId, err: error }, 'Failed to download media') }) }) } if (setMessagesAsSeen) { - const chat = await message.getChat() - chat.sendSeen() + sendMessageSeenStatus(message) } }) }) @@ -287,8 +286,7 @@ const initializeEvents = (client, sessionId) => { client.on('message_ack', async (message, ack) => { triggerWebhook(sessionWebhook, sessionId, 'message_ack', { message, ack }) if (setMessagesAsSeen) { - const chat = await message.getChat() - chat.sendSeen() + sendMessageSeenStatus(message) } }) }) @@ -298,8 +296,7 @@ const initializeEvents = (client, sessionId) => { client.on('message_create', async (message) => { triggerWebhook(sessionWebhook, sessionId, 'message_create', { message }) if (setMessagesAsSeen) { - const chat = await message.getChat() - chat.sendSeen() + sendMessageSeenStatus(message) } }) }) @@ -407,7 +404,7 @@ const deleteSessionFolder = async (sessionId) => { } await fs.promises.rm(resolvedTargetDirPath, { recursive: true, force: true }) } catch (error) { - console.log('Folder deletion error', error) + logger.error({ sessionId, err: error }, 'Folder deletion error') throw error } } @@ -437,7 +434,7 @@ const reloadSession = async (sessionId) => { sessions.delete(sessionId) await setupSession(sessionId) } catch (error) { - console.log(error) + logger.error({ sessionId, err: error }, 'Failed to reload session') throw error } } @@ -452,11 +449,11 @@ const deleteSession = async (sessionId, validation) => { client.pupPage?.removeAllListeners('error') if (validation.success) { // Client Connected, request logout - console.log(`Logging out session ${sessionId}`) + logger.info({ sessionId }, 'Logging out session') await client.logout() } else if (validation.message === 'session_not_connected') { // Client not Connected, request destroy - console.log(`Destroying session ${sessionId}`) + logger.info({ sessionId }, 'Destroying session') await client.destroy() } // Wait 10 secs for client.pupBrowser to be disconnected before deleting the folder @@ -468,7 +465,7 @@ const deleteSession = async (sessionId, validation) => { await deleteSessionFolder(sessionId) sessions.delete(sessionId) } catch (error) { - console.log(error) + logger.error({ sessionId, err: error }, 'Failed to delete session') throw error } } @@ -491,7 +488,7 @@ const flushSessions = async (deleteOnlyInactive) => { } } } catch (error) { - console.log(error) + logger.error(error, 'Failed to flush sessions') throw error } } diff --git a/src/utils.js b/src/utils.js index 8943a42..5cbb9f3 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,10 +1,12 @@ const axios = require('axios') const { globalApiKey, disabledCallbacks } = require('./config') +const { logger } = require('./logger') // Trigger webhook endpoint const triggerWebhook = (webhookURL, sessionId, dataType, data) => { axios.post(webhookURL, { dataType, data, sessionId }, { headers: { 'x-api-key': globalApiKey } }) - .catch(error => console.error('Failed to send new message webhook:', sessionId, dataType, error.message, data || '')) + .then(() => logger.debug({ sessionId, dataType, data: data || '' }, `New webhook message sent to ${webhookURL}`)) + .catch(error => logger.error({ sessionId, dataType, err: error, data: data || '' }, `Failed to send new webhook message to ${webhookURL}`)) } // Function to send a response with error status and message @@ -23,7 +25,7 @@ const waitForNestedObject = (rootObj, nestedPath, maxWaitTime = 10000, interval resolve() } else if (Date.now() - start > maxWaitTime) { // Maximum wait time exceeded, reject the promise - console.log('Timed out waiting for nested object') + logger.error('Timed out waiting for nested object') reject(new Error('Timeout waiting for nested object')) } else { // Nested object not yet created, continue waiting @@ -35,12 +37,22 @@ const waitForNestedObject = (rootObj, nestedPath, maxWaitTime = 10000, interval } const checkIfEventisEnabled = (event) => { - return new Promise((resolve, reject) => { if (!disabledCallbacks.includes(event)) { resolve() } }) + return new Promise((resolve) => { if (!disabledCallbacks.includes(event)) { resolve() } }) +} + +const sendMessageSeenStatus = async (message) => { + try { + const chat = await message.getChat() + await chat.sendSeen() + } catch (error) { + logger.error(error, 'Failed to send seen status') + } } module.exports = { triggerWebhook, sendErrorResponse, waitForNestedObject, - checkIfEventisEnabled + checkIfEventisEnabled, + sendMessageSeenStatus }