From 9065ab690fde0641e3eac458c1521e1d151c5050 Mon Sep 17 00:00:00 2001 From: allburov Date: Sat, 1 Jun 2024 14:32:19 +0700 Subject: [PATCH] Lock file on save and read (#824) Fix #794 --- package.json | 5 +++-- src/Utils/use-multi-file-auth-state.ts | 28 ++++++++++++++++++++++---- yarn.lock | 5 +++++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index fb6fb04..e9090a3 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "dependencies": { "@adiwajshing/keyed-db": "^0.2.4", "@hapi/boom": "^9.1.3", + "async-lock": "^1.4.1", "audio-decode": "^2.1.3", "axios": "^1.3.3", "cache-manager": "4.0.1", @@ -69,6 +70,7 @@ "eslint": "^8.0.0", "jest": "^27.0.6", "jimp": "^0.16.1", + "json": "^11.0.0", "link-preview-js": "^3.0.0", "open": "^8.4.2", "qrcode-terminal": "^0.12.0", @@ -77,8 +79,7 @@ "ts-jest": "^27.0.3", "ts-node": "^10.8.1", "typedoc": "^0.24.7", - "typescript": "^4.6.4", - "json": "^11.0.0" + "typescript": "^4.6.4" }, "peerDependencies": { "jimp": "^0.16.1", diff --git a/src/Utils/use-multi-file-auth-state.ts b/src/Utils/use-multi-file-auth-state.ts index 4758d3c..812d792 100644 --- a/src/Utils/use-multi-file-auth-state.ts +++ b/src/Utils/use-multi-file-auth-state.ts @@ -1,3 +1,4 @@ +import AsyncLock from 'async-lock' import { mkdir, readFile, stat, unlink, writeFile } from 'fs/promises' import { join } from 'path' import { proto } from '../../WAProto' @@ -5,6 +6,13 @@ import { AuthenticationCreds, AuthenticationState, SignalDataTypeMap } from '../ import { initAuthCreds } from './auth-utils' 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 }) + /** * stores the full authentication state in a single folder. * Far more efficient than singlefileauthstate @@ -15,12 +23,20 @@ import { BufferJSON } from './generics' export const useMultiFileAuthState = async(folder: string): Promise<{ state: AuthenticationState, saveCreds: () => Promise }> => { const writeData = (data: any, file: string) => { - return writeFile(join(folder, fixFileName(file)!), JSON.stringify(data, BufferJSON.replacer)) + const filePath = join(folder, fixFileName(file)!) + return fileLock.acquire( + filePath, + () => writeFile(join(filePath), JSON.stringify(data, BufferJSON.replacer)) + ) } const readData = async(file: string) => { try { - const data = await readFile(join(folder, fixFileName(file)!), { encoding: 'utf-8' }) + const filePath = join(folder, fixFileName(file)!) + const data = await fileLock.acquire( + filePath, + () => readFile(filePath, { encoding: 'utf-8' }) + ) return JSON.parse(data, BufferJSON.reviver) } catch(error) { return null @@ -29,7 +45,11 @@ export const useMultiFileAuthState = async(folder: string): Promise<{ state: Aut const removeData = async(file: string) => { try { - await unlink(join(folder, fixFileName(file)!)) + const filePath = join(folder, fixFileName(file)!) + await fileLock.acquire( + filePath, + () => unlink(filePath) + ) } catch{ } @@ -87,4 +107,4 @@ export const useMultiFileAuthState = async(folder: string): Promise<{ state: Aut return writeData(creds, 'creds.json') } } -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index 613f45a..cb5370c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1724,6 +1724,11 @@ ast-types@^0.13.4: dependencies: tslib "^2.0.1" +async-lock@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.4.1.tgz#56b8718915a9b68b10fce2f2a9a3dddf765ef53f" + integrity sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ== + async-retry@1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280"