refactor: replace async-lock with async-mutex (#1304)

Co-authored-by: Rajeh Taher <rajeh@reforward.dev>
This commit is contained in:
João Lucas de Oliveira Lopes
2025-03-14 19:45:30 -03:00
committed by GitHub
parent 63cc75d78e
commit 88e9cfa4e3
3 changed files with 48 additions and 63 deletions

View File

@@ -1,4 +1,4 @@
import AsyncLock from 'async-lock'
import { Mutex } from 'async-mutex'
import { mkdir, readFile, stat, unlink, writeFile } from 'fs/promises'
import { join } from 'path'
import { proto } from '../../WAProto'
@@ -9,9 +9,19 @@ import { BufferJSON } from './generics'
// We need to lock files due to the fact that we are using async functions to read and write files
// https://github.com/WhiskeySockets/Baileys/issues/794
// https://github.com/nodejs/node/issues/26338
// Default pending is 1000, set it to infinity
// https://github.com/rogierschouten/async-lock/issues/63
const fileLock = new AsyncLock({ maxPending: Infinity })
// Use a Map to store mutexes for each file path
const fileLocks = new Map<string, Mutex>()
// Get or create a mutex for a specific file path
const getFileLock = (path: string): Mutex => {
let mutex = fileLocks.get(path)
if(!mutex) {
mutex = new Mutex()
fileLocks.set(path, mutex)
}
return mutex
}
/**
* stores the full authentication state in a single folder.
@@ -22,22 +32,32 @@ const fileLock = new AsyncLock({ maxPending: Infinity })
* */
export const useMultiFileAuthState = async(folder: string): Promise<{ state: AuthenticationState, saveCreds: () => Promise<void> }> => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const writeData = (data: any, file: string) => {
const writeData = async(data: any, file: string) => {
const filePath = join(folder, fixFileName(file)!)
return fileLock.acquire(
filePath,
() => writeFile(join(filePath), JSON.stringify(data, BufferJSON.replacer))
)
const mutex = getFileLock(filePath)
return mutex.acquire().then(async(release) => {
try {
await writeFile(filePath, JSON.stringify(data, BufferJSON.replacer))
} finally {
release()
}
})
}
const readData = async(file: string) => {
try {
const filePath = join(folder, fixFileName(file)!)
const data = await fileLock.acquire(
filePath,
() => readFile(filePath, { encoding: 'utf-8' })
)
return JSON.parse(data, BufferJSON.reviver)
const mutex = getFileLock(filePath)
return await mutex.acquire().then(async(release) => {
try {
const data = await readFile(filePath, { encoding: 'utf-8' })
return JSON.parse(data, BufferJSON.reviver)
} finally {
release()
}
})
} catch(error) {
return null
}
@@ -46,12 +66,17 @@ export const useMultiFileAuthState = async(folder: string): Promise<{ state: Aut
const removeData = async(file: string) => {
try {
const filePath = join(folder, fixFileName(file)!)
await fileLock.acquire(
filePath,
() => unlink(filePath)
)
} catch{
const mutex = getFileLock(filePath)
return mutex.acquire().then(async(release) => {
try {
await unlink(filePath)
} catch{
} finally {
release()
}
})
} catch{
}
}
@@ -103,8 +128,8 @@ export const useMultiFileAuthState = async(folder: string): Promise<{ state: Aut
}
}
},
saveCreds: () => {
saveCreds: async() => {
return writeData(creds, 'creds.json')
}
}
}
}