feat: add pino logger
This commit is contained in:
parent
c12dc1a6c7
commit
3015f13e0d
10 changed files with 195 additions and 47 deletions
122
package-lock.json
generated
122
package-lock.json
generated
|
|
@ -13,6 +13,7 @@
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"express": "^4.21.1",
|
"express": "^4.21.1",
|
||||||
"express-rate-limit": "^7.4.1",
|
"express-rate-limit": "^7.4.1",
|
||||||
|
"pino": "^9.5.0",
|
||||||
"qr-image": "^3.2.0",
|
"qr-image": "^3.2.0",
|
||||||
"qrcode-terminal": "^0.12.0",
|
"qrcode-terminal": "^0.12.0",
|
||||||
"swagger-ui-express": "^5.0.1",
|
"swagger-ui-express": "^5.0.1",
|
||||||
|
|
@ -1697,6 +1698,15 @@
|
||||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/available-typed-arrays": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
||||||
|
|
@ -3605,6 +3615,15 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/fast-safe-stringify": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
|
"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"
|
"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": {
|
"node_modules/on-finished": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
||||||
|
|
@ -6328,6 +6356,43 @@
|
||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
"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": {
|
"node_modules/pirates": {
|
||||||
"version": "4.0.6",
|
"version": "4.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
|
||||||
|
|
@ -6462,6 +6527,12 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true
|
"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": {
|
"node_modules/progress": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
|
||||||
|
|
@ -6652,6 +6723,12 @@
|
||||||
],
|
],
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/range-parser": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||||
|
|
@ -6730,6 +6807,15 @@
|
||||||
"node": ">=10"
|
"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": {
|
"node_modules/reflect.getprototypeof": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.7.tgz",
|
||||||
|
|
@ -6963,6 +7049,15 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"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": {
|
"node_modules/safer-buffer": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||||
|
|
@ -7153,6 +7248,15 @@
|
||||||
"node": ">=8"
|
"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": {
|
"node_modules/source-map": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
|
|
@ -7174,6 +7278,15 @@
|
||||||
"source-map": "^0.6.0"
|
"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": {
|
"node_modules/sprintf-js": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||||
|
|
@ -7538,6 +7651,15 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/through": {
|
||||||
"version": "2.3.8",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"express": "^4.21.1",
|
"express": "^4.21.1",
|
||||||
"express-rate-limit": "^7.4.1",
|
"express-rate-limit": "^7.4.1",
|
||||||
|
"pino": "^9.5.0",
|
||||||
"qr-image": "^3.2.0",
|
"qr-image": "^3.2.0",
|
||||||
"qrcode-terminal": "^0.12.0",
|
"qrcode-terminal": "^0.12.0",
|
||||||
"swagger-ui-express": "^5.0.1",
|
"swagger-ui-express": "^5.0.1",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
const app = require('./src/app')
|
const app = require('./src/app')
|
||||||
const { baseWebhookURL } = require('./src/config')
|
const { baseWebhookURL } = require('./src/config')
|
||||||
|
const { logger } = require('./src/logger')
|
||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
|
|
||||||
// Start the server
|
// Start the server
|
||||||
|
|
@ -7,12 +8,12 @@ const port = process.env.PORT || 3000
|
||||||
|
|
||||||
// Check if BASE_WEBHOOK_URL environment variable is available
|
// Check if BASE_WEBHOOK_URL environment variable is available
|
||||||
if (!baseWebhookURL) {
|
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
|
process.exit(1) // Terminate the application with an error code
|
||||||
}
|
}
|
||||||
|
|
||||||
app.listen(port, () => {
|
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
|
// puppeteer uses subscriptions to SIGINT, SIGTERM, and SIGHUP to know when to close browser instances
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ const recoverSessions = (process.env.RECOVER_SESSIONS || '').toLowerCase() === '
|
||||||
const chromeBin = process.env.CHROME_BIN || null
|
const chromeBin = process.env.CHROME_BIN || null
|
||||||
const headless = process.env.HEADLESS ? (process.env.HEADLESS).toLowerCase() === 'true' : true
|
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 releaseBrowserLock = process.env.RELEASE_BROWSER_LOCK ? (process.env.RELEASE_BROWSER_LOCK).toLowerCase() === 'true' : true
|
||||||
|
const logLevel = process.env.LOGLEVEL || 'info'
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
sessionFolderPath,
|
sessionFolderPath,
|
||||||
|
|
@ -35,5 +36,6 @@ module.exports = {
|
||||||
recoverSessions,
|
recoverSessions,
|
||||||
chromeBin,
|
chromeBin,
|
||||||
headless,
|
headless,
|
||||||
releaseBrowserLock
|
releaseBrowserLock,
|
||||||
|
logLevel
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,11 +105,10 @@ const sendMessage = async (req, res) => {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
default:
|
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 })
|
res.json({ success: true, message: messageOut })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
|
||||||
sendErrorResponse(res, 500, error.message)
|
sendErrorResponse(res, 500, error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ const fsp = require('fs').promises
|
||||||
const qrcode = require('qrcode-terminal')
|
const qrcode = require('qrcode-terminal')
|
||||||
const { sessionFolderPath } = require('../config')
|
const { sessionFolderPath } = require('../config')
|
||||||
const { sendErrorResponse } = require('../utils')
|
const { sendErrorResponse } = require('../utils')
|
||||||
|
const { logger } = require('../logger')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responds to request with 'pong'
|
* 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)
|
sendErrorResponse(res, 500, error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
const qr = require('qr-image')
|
const qr = require('qr-image')
|
||||||
const { setupSession, deleteSession, reloadSession, validateSession, flushSessions, sessions } = require('../sessions')
|
const { setupSession, deleteSession, reloadSession, validateSession, flushSessions, sessions } = require('../sessions')
|
||||||
const { sendErrorResponse, waitForNestedObject } = require('../utils')
|
const { sendErrorResponse, waitForNestedObject } = require('../utils')
|
||||||
|
const { logger } = require('../logger')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts a session for the given session ID.
|
* Starts a session for the given session ID.
|
||||||
|
|
@ -16,8 +17,8 @@ const { sendErrorResponse, waitForNestedObject } = require('../utils')
|
||||||
const startSession = async (req, res) => {
|
const startSession = async (req, res) => {
|
||||||
// #swagger.summary = 'Start new session'
|
// #swagger.summary = 'Start new session'
|
||||||
// #swagger.description = 'Starts a session for the given session ID.'
|
// #swagger.description = 'Starts a session for the given session ID.'
|
||||||
try {
|
|
||||||
const sessionId = req.params.sessionId
|
const sessionId = req.params.sessionId
|
||||||
|
try {
|
||||||
const setupSessionReturn = await setupSession(sessionId)
|
const setupSessionReturn = await setupSession(sessionId)
|
||||||
if (!setupSessionReturn.success) {
|
if (!setupSessionReturn.success) {
|
||||||
/* #swagger.responses[422] = {
|
/* #swagger.responses[422] = {
|
||||||
|
|
@ -45,7 +46,7 @@ const startSession = async (req, res) => {
|
||||||
await waitForNestedObject(setupSessionReturn.client, 'pupPage')
|
await waitForNestedObject(setupSessionReturn.client, 'pupPage')
|
||||||
res.json({ success: true, message: setupSessionReturn.message })
|
res.json({ success: true, message: setupSessionReturn.message })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('startSession ERROR', error)
|
logger.error({ sessionId, err: error }, 'Failed to start session')
|
||||||
sendErrorResponse(res, 500, error.message)
|
sendErrorResponse(res, 500, error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -64,8 +65,8 @@ const startSession = async (req, res) => {
|
||||||
const statusSession = async (req, res) => {
|
const statusSession = async (req, res) => {
|
||||||
// #swagger.summary = 'Get session status'
|
// #swagger.summary = 'Get session status'
|
||||||
// #swagger.description = 'Status of the session with the given session ID.'
|
// #swagger.description = 'Status of the session with the given session ID.'
|
||||||
try {
|
|
||||||
const sessionId = req.params.sessionId
|
const sessionId = req.params.sessionId
|
||||||
|
try {
|
||||||
const sessionData = await validateSession(sessionId)
|
const sessionData = await validateSession(sessionId)
|
||||||
/* #swagger.responses[200] = {
|
/* #swagger.responses[200] = {
|
||||||
description: "Status of the session.",
|
description: "Status of the session.",
|
||||||
|
|
@ -78,7 +79,7 @@ const statusSession = async (req, res) => {
|
||||||
*/
|
*/
|
||||||
res.json(sessionData)
|
res.json(sessionData)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('statusSession ERROR', error)
|
logger.error({ sessionId, err: error }, 'Failed to get session status')
|
||||||
sendErrorResponse(res, 500, error.message)
|
sendErrorResponse(res, 500, error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -97,8 +98,8 @@ const statusSession = async (req, res) => {
|
||||||
const sessionQrCode = async (req, res) => {
|
const sessionQrCode = async (req, res) => {
|
||||||
// #swagger.summary = 'Get session QR code'
|
// #swagger.summary = 'Get session QR code'
|
||||||
// #swagger.description = 'QR code of the session with the given session ID.'
|
// #swagger.description = 'QR code of the session with the given session ID.'
|
||||||
try {
|
|
||||||
const sessionId = req.params.sessionId
|
const sessionId = req.params.sessionId
|
||||||
|
try {
|
||||||
const session = sessions.get(sessionId)
|
const session = sessions.get(sessionId)
|
||||||
if (!session) {
|
if (!session) {
|
||||||
return res.json({ success: false, message: 'session_not_found' })
|
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' })
|
return res.json({ success: false, message: 'qr code not ready or already scanned' })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('sessionQrCode ERROR', error)
|
logger.error({ sessionId, err: error }, 'Failed to get session qr code')
|
||||||
sendErrorResponse(res, 500, error.message)
|
sendErrorResponse(res, 500, error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -127,8 +128,8 @@ const sessionQrCode = async (req, res) => {
|
||||||
const sessionQrCodeImage = async (req, res) => {
|
const sessionQrCodeImage = async (req, res) => {
|
||||||
// #swagger.summary = 'Get session QR code as image'
|
// #swagger.summary = 'Get session QR code as image'
|
||||||
// #swagger.description = 'QR code as image of the session with the given session ID.'
|
// #swagger.description = 'QR code as image of the session with the given session ID.'
|
||||||
try {
|
|
||||||
const sessionId = req.params.sessionId
|
const sessionId = req.params.sessionId
|
||||||
|
try {
|
||||||
const session = sessions.get(sessionId)
|
const session = sessions.get(sessionId)
|
||||||
if (!session) {
|
if (!session) {
|
||||||
return res.json({ success: false, message: 'session_not_found' })
|
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' })
|
return res.json({ success: false, message: 'qr code not ready or already scanned' })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('sessionQrCodeImage ERROR', error)
|
logger.error({ sessionId, err: error }, 'Failed to get session qr code image')
|
||||||
sendErrorResponse(res, 500, error.message)
|
sendErrorResponse(res, 500, error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -168,8 +169,8 @@ const sessionQrCodeImage = async (req, res) => {
|
||||||
const restartSession = async (req, res) => {
|
const restartSession = async (req, res) => {
|
||||||
// #swagger.summary = 'Restart session'
|
// #swagger.summary = 'Restart session'
|
||||||
// #swagger.description = 'Restarts the session with the given session ID.'
|
// #swagger.description = 'Restarts the session with the given session ID.'
|
||||||
try {
|
|
||||||
const sessionId = req.params.sessionId
|
const sessionId = req.params.sessionId
|
||||||
|
try {
|
||||||
const validation = await validateSession(sessionId)
|
const validation = await validateSession(sessionId)
|
||||||
if (validation.message === 'session_not_found') {
|
if (validation.message === 'session_not_found') {
|
||||||
return res.json(validation)
|
return res.json(validation)
|
||||||
|
|
@ -186,7 +187,7 @@ const restartSession = async (req, res) => {
|
||||||
*/
|
*/
|
||||||
res.json({ success: true, message: 'Restarted successfully' })
|
res.json({ success: true, message: 'Restarted successfully' })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('restartSession ERROR', error)
|
logger.error({ sessionId, err: error }, 'Failed to restart session')
|
||||||
sendErrorResponse(res, 500, error.message)
|
sendErrorResponse(res, 500, error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -205,8 +206,8 @@ const restartSession = async (req, res) => {
|
||||||
const terminateSession = async (req, res) => {
|
const terminateSession = async (req, res) => {
|
||||||
// #swagger.summary = 'Terminate session'
|
// #swagger.summary = 'Terminate session'
|
||||||
// #swagger.description = 'Terminates the session with the given session ID.'
|
// #swagger.description = 'Terminates the session with the given session ID.'
|
||||||
try {
|
|
||||||
const sessionId = req.params.sessionId
|
const sessionId = req.params.sessionId
|
||||||
|
try {
|
||||||
const validation = await validateSession(sessionId)
|
const validation = await validateSession(sessionId)
|
||||||
if (validation.message === 'session_not_found') {
|
if (validation.message === 'session_not_found') {
|
||||||
return res.json(validation)
|
return res.json(validation)
|
||||||
|
|
@ -223,7 +224,7 @@ const terminateSession = async (req, res) => {
|
||||||
*/
|
*/
|
||||||
res.json({ success: true, message: 'Logged out successfully' })
|
res.json({ success: true, message: 'Logged out successfully' })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('terminateSession ERROR', error)
|
logger.error({ sessionId, err: error }, 'Failed to terminate session')
|
||||||
sendErrorResponse(res, 500, error.message)
|
sendErrorResponse(res, 500, error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -254,7 +255,7 @@ const terminateInactiveSessions = async (req, res) => {
|
||||||
*/
|
*/
|
||||||
res.json({ success: true, message: 'Flush completed successfully' })
|
res.json({ success: true, message: 'Flush completed successfully' })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('terminateInactiveSessions ERROR', error)
|
logger.error(error, 'Failed to terminate inactive sessions')
|
||||||
sendErrorResponse(res, 500, error.message)
|
sendErrorResponse(res, 500, error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -285,7 +286,7 @@ const terminateAllSessions = async (req, res) => {
|
||||||
*/
|
*/
|
||||||
res.json({ success: true, message: 'Flush completed successfully' })
|
res.json({ success: true, message: 'Flush completed successfully' })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('terminateAllSessions ERROR', error)
|
logger.error(error, 'Failed to terminate all sessions')
|
||||||
sendErrorResponse(res, 500, error.message)
|
sendErrorResponse(res, 500, error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
src/logger.js
Normal file
12
src/logger.js
Normal file
|
|
@ -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 }
|
||||||
|
|
@ -3,7 +3,8 @@ const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const sessions = new Map()
|
const sessions = new Map()
|
||||||
const { baseWebhookURL, sessionFolderPath, maxAttachmentSize, setMessagesAsSeen, webVersion, webVersionCacheType, recoverSessions, chromeBin, headless, releaseBrowserLock } = require('./config')
|
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
|
// Function to validate if the session is ready
|
||||||
const validateSession = async (sessionId) => {
|
const validateSession = async (sessionId) => {
|
||||||
|
|
@ -53,7 +54,7 @@ const validateSession = async (sessionId) => {
|
||||||
returnData.message = 'session_connected'
|
returnData.message = 'session_connected'
|
||||||
return returnData
|
return returnData
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
logger.error({ sessionId, err: error }, 'Failed to validate session')
|
||||||
return { success: false, state: null, message: error.message }
|
return { success: false, state: null, message: error.message }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -72,14 +73,13 @@ const restoreSessions = () => {
|
||||||
const match = file.match(/^session-(.+)$/)
|
const match = file.match(/^session-(.+)$/)
|
||||||
if (match) {
|
if (match) {
|
||||||
const sessionId = match[1]
|
const sessionId = match[1]
|
||||||
console.log('existing session detected', sessionId)
|
logger.warn({ sessionId }, 'existing session detected')
|
||||||
await setupSession(sessionId)
|
await setupSession(sessionId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
logger.error(error, 'Failed to restore sessions')
|
||||||
console.error('Failed to restore sessions:', error)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,7 +131,7 @@ const setupSession = async (sessionId) => {
|
||||||
const singletonLockPath = path.resolve(path.join(sessionFolderPath, `session-${sessionId}`, 'SingletonLock'))
|
const singletonLockPath = path.resolve(path.join(sessionFolderPath, `session-${sessionId}`, 'SingletonLock'))
|
||||||
const singletonLockExists = await fs.promises.lstat(singletonLockPath).then(() => true).catch(() => false)
|
const singletonLockExists = await fs.promises.lstat(singletonLockPath).then(() => true).catch(() => false)
|
||||||
if (singletonLockExists) {
|
if (singletonLockExists) {
|
||||||
console.log('Browser lock file exists, removing ', sessionId)
|
logger.warn({ sessionId }, 'Browser lock file exists, removing')
|
||||||
await fs.promises.unlink(singletonLockPath)
|
await fs.promises.unlink(singletonLockPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -139,7 +139,7 @@ const setupSession = async (sessionId) => {
|
||||||
try {
|
try {
|
||||||
await client.initialize()
|
await client.initialize()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('Initialize error:', error.message)
|
logger.error({ sessionId, err: error }, 'Initialize error')
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,12 +166,12 @@ const initializeEvents = (client, sessionId) => {
|
||||||
}
|
}
|
||||||
client.pupPage.once('close', function () {
|
client.pupPage.once('close', function () {
|
||||||
// emitted when the page closes
|
// emitted when the page closes
|
||||||
console.log(`Browser page closed for ${sessionId}. Restoring`)
|
logger.warn({ sessionId }, 'Browser page closed. Restoring')
|
||||||
restartSession(sessionId)
|
restartSession(sessionId)
|
||||||
})
|
})
|
||||||
client.pupPage.once('error', function () {
|
client.pupPage.once('error', function () {
|
||||||
// emitted when the page crashes
|
// 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)
|
restartSession(sessionId)
|
||||||
})
|
})
|
||||||
}).catch(e => { })
|
}).catch(e => { })
|
||||||
|
|
@ -270,14 +270,13 @@ const initializeEvents = (client, sessionId) => {
|
||||||
checkIfEventisEnabled('media').then(_ => {
|
checkIfEventisEnabled('media').then(_ => {
|
||||||
message.downloadMedia().then(messageMedia => {
|
message.downloadMedia().then(messageMedia => {
|
||||||
triggerWebhook(sessionWebhook, sessionId, 'media', { messageMedia, message })
|
triggerWebhook(sessionWebhook, sessionId, 'media', { messageMedia, message })
|
||||||
}).catch(e => {
|
}).catch(error => {
|
||||||
console.log('Download media error:', e.message)
|
logger.error({ sessionId, err: error }, 'Failed to download media')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (setMessagesAsSeen) {
|
if (setMessagesAsSeen) {
|
||||||
const chat = await message.getChat()
|
sendMessageSeenStatus(message)
|
||||||
chat.sendSeen()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -287,8 +286,7 @@ const initializeEvents = (client, sessionId) => {
|
||||||
client.on('message_ack', async (message, ack) => {
|
client.on('message_ack', async (message, ack) => {
|
||||||
triggerWebhook(sessionWebhook, sessionId, 'message_ack', { message, ack })
|
triggerWebhook(sessionWebhook, sessionId, 'message_ack', { message, ack })
|
||||||
if (setMessagesAsSeen) {
|
if (setMessagesAsSeen) {
|
||||||
const chat = await message.getChat()
|
sendMessageSeenStatus(message)
|
||||||
chat.sendSeen()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -298,8 +296,7 @@ const initializeEvents = (client, sessionId) => {
|
||||||
client.on('message_create', async (message) => {
|
client.on('message_create', async (message) => {
|
||||||
triggerWebhook(sessionWebhook, sessionId, 'message_create', { message })
|
triggerWebhook(sessionWebhook, sessionId, 'message_create', { message })
|
||||||
if (setMessagesAsSeen) {
|
if (setMessagesAsSeen) {
|
||||||
const chat = await message.getChat()
|
sendMessageSeenStatus(message)
|
||||||
chat.sendSeen()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -407,7 +404,7 @@ const deleteSessionFolder = async (sessionId) => {
|
||||||
}
|
}
|
||||||
await fs.promises.rm(resolvedTargetDirPath, { recursive: true, force: true })
|
await fs.promises.rm(resolvedTargetDirPath, { recursive: true, force: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('Folder deletion error', error)
|
logger.error({ sessionId, err: error }, 'Folder deletion error')
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -437,7 +434,7 @@ const reloadSession = async (sessionId) => {
|
||||||
sessions.delete(sessionId)
|
sessions.delete(sessionId)
|
||||||
await setupSession(sessionId)
|
await setupSession(sessionId)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
logger.error({ sessionId, err: error }, 'Failed to reload session')
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -452,11 +449,11 @@ const deleteSession = async (sessionId, validation) => {
|
||||||
client.pupPage?.removeAllListeners('error')
|
client.pupPage?.removeAllListeners('error')
|
||||||
if (validation.success) {
|
if (validation.success) {
|
||||||
// Client Connected, request logout
|
// Client Connected, request logout
|
||||||
console.log(`Logging out session ${sessionId}`)
|
logger.info({ sessionId }, 'Logging out session')
|
||||||
await client.logout()
|
await client.logout()
|
||||||
} else if (validation.message === 'session_not_connected') {
|
} else if (validation.message === 'session_not_connected') {
|
||||||
// Client not Connected, request destroy
|
// Client not Connected, request destroy
|
||||||
console.log(`Destroying session ${sessionId}`)
|
logger.info({ sessionId }, 'Destroying session')
|
||||||
await client.destroy()
|
await client.destroy()
|
||||||
}
|
}
|
||||||
// Wait 10 secs for client.pupBrowser to be disconnected before deleting the folder
|
// 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)
|
await deleteSessionFolder(sessionId)
|
||||||
sessions.delete(sessionId)
|
sessions.delete(sessionId)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
logger.error({ sessionId, err: error }, 'Failed to delete session')
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -491,7 +488,7 @@ const flushSessions = async (deleteOnlyInactive) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
logger.error(error, 'Failed to flush sessions')
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
20
src/utils.js
20
src/utils.js
|
|
@ -1,10 +1,12 @@
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const { globalApiKey, disabledCallbacks } = require('./config')
|
const { globalApiKey, disabledCallbacks } = require('./config')
|
||||||
|
const { logger } = require('./logger')
|
||||||
|
|
||||||
// Trigger webhook endpoint
|
// Trigger webhook endpoint
|
||||||
const triggerWebhook = (webhookURL, sessionId, dataType, data) => {
|
const triggerWebhook = (webhookURL, sessionId, dataType, data) => {
|
||||||
axios.post(webhookURL, { dataType, data, sessionId }, { headers: { 'x-api-key': globalApiKey } })
|
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
|
// Function to send a response with error status and message
|
||||||
|
|
@ -23,7 +25,7 @@ const waitForNestedObject = (rootObj, nestedPath, maxWaitTime = 10000, interval
|
||||||
resolve()
|
resolve()
|
||||||
} else if (Date.now() - start > maxWaitTime) {
|
} else if (Date.now() - start > maxWaitTime) {
|
||||||
// Maximum wait time exceeded, reject the promise
|
// 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'))
|
reject(new Error('Timeout waiting for nested object'))
|
||||||
} else {
|
} else {
|
||||||
// Nested object not yet created, continue waiting
|
// Nested object not yet created, continue waiting
|
||||||
|
|
@ -35,12 +37,22 @@ const waitForNestedObject = (rootObj, nestedPath, maxWaitTime = 10000, interval
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkIfEventisEnabled = (event) => {
|
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 = {
|
module.exports = {
|
||||||
triggerWebhook,
|
triggerWebhook,
|
||||||
sendErrorResponse,
|
sendErrorResponse,
|
||||||
waitForNestedObject,
|
waitForNestedObject,
|
||||||
checkIfEventisEnabled
|
checkIfEventisEnabled,
|
||||||
|
sendMessageSeenStatus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue