feat: add "multi file auth state" implementation

1. add multi file auth state since it's far more efficient than single state
2. deprecate single file auth state (please don't use it anymore)
This commit is contained in:
Adhiraj Singh
2022-05-22 21:21:35 +05:30
parent a8e209705a
commit 06437e182d
7 changed files with 177 additions and 88 deletions

View File

@@ -0,0 +1,78 @@
import { mkdir, readFile, stat, writeFile } from 'fs/promises'
import { join } from 'path'
import { proto } from '../../WAProto'
import { AuthenticationCreds, AuthenticationState, SignalDataTypeMap } from '../Types'
import { initAuthCreds } from './auth-utils'
import { BufferJSON } from './generics'
/**
* stores the full authentication state in a single folder.
* Far more efficient than singlefileauthstate
*
* Again, I wouldn't endorse this for any production level use other than perhaps a bot.
* Would recommend writing an auth state for use with a proper SQL or No-SQL DB
* */
export const useMultiFileAuthState = async(folder: string): Promise<{ state: AuthenticationState, saveCreds: () => Promise<void> }> => {
const writeData = (data: any, file: string) => {
return writeFile(join(folder, file), JSON.stringify(data, BufferJSON.replacer))
}
const readData = async(file: string) => {
try {
const data = await readFile(join(folder, file), { encoding: 'utf-8' })
return JSON.parse(data, BufferJSON.reviver)
} catch(error) {
return null
}
}
const folderInfo = await stat(folder).catch(() => { })
if(folderInfo) {
if(!folderInfo.isDirectory()) {
throw new Error(`found something that is not a directory at ${folder}, either delete it or specify a different location`)
}
} else {
await mkdir(folder, { recursive: true })
}
const creds: AuthenticationCreds = await readData('creds.json') || initAuthCreds()
return {
state: {
creds,
keys: {
get: async(type, ids) => {
const data: { [_: string]: SignalDataTypeMap[typeof type] } = { }
await Promise.all(
ids.map(
async id => {
let value = await readData(`${type}-${id}.json`)
if(type === 'app-state-sync-key') {
value = proto.AppStateSyncKeyData.fromObject(data)
}
data[id] = value
}
)
)
return data
},
set: async(data) => {
const tasks: Promise<void>[] = []
for(const category in data) {
for(const id in data[category]) {
tasks.push(writeData(data[category][id], `${category}-${id}.json`))
}
}
await Promise.all(tasks)
}
}
},
saveCreds: () => {
return writeData(creds, 'creds.json')
}
}
}