feat: release browser lock and await setup

This commit is contained in:
Anton Voylenko 2024-12-03 01:17:47 +02:00
commit fdd32f8474
5 changed files with 29 additions and 11 deletions

View file

@ -16,6 +16,7 @@ WEB_VERSION_CACHE_TYPE=none # OPTIONAL, DETERMINTES WHERE TO GET THE WHATSAPP WE
RECOVER_SESSIONS=TRUE # OPTIONAL, SHOULD WE RECOVER THE SESSION IN CASE OF PAGE FAILURES RECOVER_SESSIONS=TRUE # OPTIONAL, SHOULD WE RECOVER THE SESSION IN CASE OF PAGE FAILURES
CHROME_BIN= # OPTIONAL, PATH TO CHROME BINARY CHROME_BIN= # OPTIONAL, PATH TO CHROME BINARY
HEADLESS=TRUE # OPTIONAL, RUN CHROME IN HEADLESS MODE HEADLESS=TRUE # OPTIONAL, RUN CHROME IN HEADLESS MODE
RELEASE_BROWSER_LOCK=TRUE # OPTIONAL, RELEASE THE BROWSER LOCK ON SESSION INITIALIZATION
## Session File Storage ## ## Session File Storage ##
SESSIONS_PATH=./sessions # OPTIONAL SESSIONS_PATH=./sessions # OPTIONAL

View file

@ -17,6 +17,7 @@ const rateLimitWindowMs = parseInt(process.env.RATE_LIMIT_WINDOW_MS) || 1000
const recoverSessions = (process.env.RECOVER_SESSIONS || '').toLowerCase() === 'true' const recoverSessions = (process.env.RECOVER_SESSIONS || '').toLowerCase() === 'true'
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
module.exports = { module.exports = {
sessionFolderPath, sessionFolderPath,
@ -33,5 +34,6 @@ module.exports = {
rateLimitWindowMs, rateLimitWindowMs,
recoverSessions, recoverSessions,
chromeBin, chromeBin,
headless headless,
releaseBrowserLock
} }

View file

@ -43,11 +43,11 @@ const localCallbackExample = async (req, res) => {
try { try {
const { dataType, data } = req.body const { dataType, data } = req.body
if (dataType === 'qr') { qrcode.generate(data.qr, { small: true }) } if (dataType === 'qr') { qrcode.generate(data.qr, { small: true }) }
await fsp.writeFile(`${sessionFolderPath}/message_log.txt`, `${JSON.stringify(req.body)}\r\n`, { flag: 'a+' }, _ => _) await fsp.mkdir(sessionFolderPath, { recursive: true })
await fsp.writeFile(`${sessionFolderPath}/message_log.txt`, `${JSON.stringify(req.body)}\r\n`, { flag: 'a+' })
res.json({ success: true }) res.json({ success: true })
} catch (error) { } catch (error) {
console.log(error) console.log(error)
await fsp.writeFile(`${sessionFolderPath}/message_log.txt`, `(ERROR) ${JSON.stringify(error)}\r\n`, { flag: 'a+' }, _ => _)
sendErrorResponse(res, 500, error.message) sendErrorResponse(res, 500, error.message)
} }
} }

View file

@ -18,7 +18,7 @@ const startSession = async (req, res) => {
// #swagger.description = 'Starts a session for the given session ID.' // #swagger.description = 'Starts a session for the given session ID.'
try { try {
const sessionId = req.params.sessionId const sessionId = req.params.sessionId
const setupSessionReturn = setupSession(sessionId) const setupSessionReturn = await setupSession(sessionId)
if (!setupSessionReturn.success) { if (!setupSessionReturn.success) {
/* #swagger.responses[422] = { /* #swagger.responses[422] = {
description: "Unprocessable Entity.", description: "Unprocessable Entity.",

View file

@ -2,7 +2,7 @@ const { Client, LocalAuth } = require('whatsapp-web.js')
const fs = require('fs') 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 } = 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 } = require('./utils')
// Function to validate if the session is ready // Function to validate if the session is ready
@ -65,7 +65,7 @@ const restoreSessions = () => {
fs.mkdirSync(sessionFolderPath) // Create the session directory if it doesn't exist fs.mkdirSync(sessionFolderPath) // Create the session directory if it doesn't exist
} }
// Read the contents of the folder // Read the contents of the folder
fs.readdir(sessionFolderPath, (_, files) => { fs.readdir(sessionFolderPath, async (_, files) => {
// Iterate through the files in the parent folder // Iterate through the files in the parent folder
for (const file of files) { for (const file of files) {
// Use regular expression to extract the string from the folder name // Use regular expression to extract the string from the folder name
@ -73,7 +73,7 @@ const restoreSessions = () => {
if (match) { if (match) {
const sessionId = match[1] const sessionId = match[1]
console.log('existing session detected', sessionId) console.log('existing session detected', sessionId)
setupSession(sessionId) await setupSession(sessionId)
} }
} }
}) })
@ -84,7 +84,7 @@ const restoreSessions = () => {
} }
// Setup Session // Setup Session
const setupSession = (sessionId) => { const setupSession = async (sessionId) => {
try { try {
if (sessions.has(sessionId)) { if (sessions.has(sessionId)) {
return { success: false, message: `Session already exists for: ${sessionId}`, client: sessions.get(sessionId) } return { success: false, message: `Session already exists for: ${sessionId}`, client: sessions.get(sessionId) }
@ -127,7 +127,22 @@ const setupSession = (sessionId) => {
const client = new Client(clientOptions) const client = new Client(clientOptions)
client.initialize().catch(err => console.log('Initialize error:', err.message)) if (releaseBrowserLock) {
// See https://github.com/puppeteer/puppeteer/issues/4860
const singletonLockPath = path.join(`${sessionFolderPath}-${sessionId}`, 'SingletonLock')
const singletonLockExists = await fs.promises.access(singletonLockPath).then(() => true).catch(() => false)
if (singletonLockExists) {
console.log('Browser lock file exists, removing ', sessionId)
await fs.promises.unlink(singletonLockPath)
}
}
try {
await client.initialize()
} catch (error) {
console.log('Initialize error:', error.message)
throw error
}
initializeEvents(client, sessionId) initializeEvents(client, sessionId)
@ -148,7 +163,7 @@ const initializeEvents = (client, sessionId) => {
const restartSession = async (sessionId) => { const restartSession = async (sessionId) => {
sessions.delete(sessionId) sessions.delete(sessionId)
await client.destroy().catch(e => { }) await client.destroy().catch(e => { })
setupSession(sessionId) await setupSession(sessionId)
} }
client.pupPage.once('close', function () { client.pupPage.once('close', function () {
// emitted when the page closes // emitted when the page closes
@ -402,7 +417,7 @@ const reloadSession = async (sessionId) => {
} }
} }
sessions.delete(sessionId) sessions.delete(sessionId)
setupSession(sessionId) await setupSession(sessionId)
} catch (error) { } catch (error) {
console.log(error) console.log(error)
throw error throw error