fix: optimize getLIDsForPNs and add getPNsForLIDs (#2274)
* fix: optimize lid-mapping and add getpnsforlids * fix: lint * fix: reintroduce store and fix partial returns * fix: lint
This commit is contained in:
+104
-45
@@ -39,7 +39,7 @@ export class LIDMappingStore {
|
|||||||
const lidDecoded = jidDecode(lid)
|
const lidDecoded = jidDecode(lid)
|
||||||
const pnDecoded = jidDecode(pn)
|
const pnDecoded = jidDecode(pn)
|
||||||
|
|
||||||
if (!lidDecoded || !pnDecoded) return
|
if (!lidDecoded || !pnDecoded) continue
|
||||||
|
|
||||||
const pnUser = pnDecoded.user
|
const pnUser = pnDecoded.user
|
||||||
const lidUser = lidDecoded.user
|
const lidUser = lidDecoded.user
|
||||||
@@ -92,6 +92,26 @@ export class LIDMappingStore {
|
|||||||
const usyncFetch: { [_: string]: number[] } = {}
|
const usyncFetch: { [_: string]: number[] } = {}
|
||||||
// mapped from pn to lid mapping to prevent duplication in results later
|
// mapped from pn to lid mapping to prevent duplication in results later
|
||||||
const successfulPairs: { [_: string]: LIDMapping } = {}
|
const successfulPairs: { [_: string]: LIDMapping } = {}
|
||||||
|
const pending: Array<{ pn: string; pnUser: string; decoded: ReturnType<typeof jidDecode> }> = []
|
||||||
|
|
||||||
|
const addResolvedPair = (pn: string, decoded: ReturnType<typeof jidDecode>, lidUser: string) => {
|
||||||
|
const normalizedLidUser = lidUser.toString()
|
||||||
|
if (!normalizedLidUser) {
|
||||||
|
this.logger.warn(`Invalid or empty LID user for PN ${pn}: lidUser = "${lidUser}"`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push the PN device ID to the LID to maintain device separation
|
||||||
|
const pnDevice = decoded!.device !== undefined ? decoded!.device : 0
|
||||||
|
const deviceSpecificLid = `${normalizedLidUser}${!!pnDevice ? `:${pnDevice}` : ``}@${
|
||||||
|
decoded!.server === 'hosted' ? 'hosted.lid' : 'lid'
|
||||||
|
}`
|
||||||
|
|
||||||
|
this.logger.trace(`getLIDForPN: ${pn} → ${deviceSpecificLid} (user mapping with device ${pnDevice})`)
|
||||||
|
successfulPairs[pn] = { lid: deviceSpecificLid, pn }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
for (const pn of pns) {
|
for (const pn of pns) {
|
||||||
if (!isPnUser(pn) && !isHostedPnUser(pn)) continue
|
if (!isPnUser(pn) && !isHostedPnUser(pn)) continue
|
||||||
|
|
||||||
@@ -100,19 +120,40 @@ export class LIDMappingStore {
|
|||||||
|
|
||||||
// Check cache first for PN → LID mapping
|
// Check cache first for PN → LID mapping
|
||||||
const pnUser = decoded.user
|
const pnUser = decoded.user
|
||||||
let lidUser = this.mappingCache.get(`pn:${pnUser}`)
|
const cached = this.mappingCache.get(`pn:${pnUser}`)
|
||||||
|
if (cached && typeof cached === 'string') {
|
||||||
|
if (!addResolvedPair(pn, decoded, cached)) {
|
||||||
|
this.logger.warn(`Invalid entry for ${pn} (pair not resolved)`)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if (!lidUser) {
|
continue
|
||||||
// Cache miss - check database
|
}
|
||||||
const stored = await this.keys.get('lid-mapping', [pnUser])
|
|
||||||
lidUser = stored[pnUser]
|
|
||||||
|
|
||||||
if (lidUser) {
|
pending.push({ pn, pnUser, decoded })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pending.length) {
|
||||||
|
const pnUsers = [...new Set(pending.map(item => item.pnUser))]
|
||||||
|
const stored = await this.keys.get('lid-mapping', pnUsers)
|
||||||
|
for (const pnUser of pnUsers) {
|
||||||
|
const lidUser = stored[pnUser]
|
||||||
|
if (lidUser && typeof lidUser === 'string') {
|
||||||
this.mappingCache.set(`pn:${pnUser}`, lidUser)
|
this.mappingCache.set(`pn:${pnUser}`, lidUser)
|
||||||
this.mappingCache.set(`lid:${lidUser}`, pnUser)
|
this.mappingCache.set(`lid:${lidUser}`, pnUser)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const { pn, pnUser, decoded } of pending) {
|
||||||
|
const cached = this.mappingCache.get(`pn:${pnUser}`)
|
||||||
|
if (cached && typeof cached === 'string') {
|
||||||
|
if (!addResolvedPair(pn, decoded, cached)) {
|
||||||
|
this.logger.warn(`Invalid entry for ${pn} (pair not resolved)`)
|
||||||
|
continue
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.logger.trace(`No LID mapping found for PN user ${pnUser}; batch getting from USync`)
|
this.logger.trace(`No LID mapping found for PN user ${pnUser}; batch getting from USync`)
|
||||||
const device = decoded.device || 0
|
const device = decoded!.device || 0
|
||||||
let normalizedPn = jidNormalizedUser(pn)
|
let normalizedPn = jidNormalizedUser(pn)
|
||||||
if (isHostedPnUser(normalizedPn)) {
|
if (isHostedPnUser(normalizedPn)) {
|
||||||
normalizedPn = `${pnUser}@s.whatsapp.net`
|
normalizedPn = `${pnUser}@s.whatsapp.net`
|
||||||
@@ -123,23 +164,8 @@ export class LIDMappingStore {
|
|||||||
} else {
|
} else {
|
||||||
usyncFetch[normalizedPn]?.push(device)
|
usyncFetch[normalizedPn]?.push(device)
|
||||||
}
|
}
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lidUser = lidUser.toString()
|
|
||||||
if (!lidUser) {
|
|
||||||
this.logger.warn(`Invalid or empty LID user for PN ${pn}: lidUser = "${lidUser}"`)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push the PN device ID to the LID to maintain device separation
|
|
||||||
const pnDevice = decoded.device !== undefined ? decoded.device : 0
|
|
||||||
const deviceSpecificLid = `${lidUser}${!!pnDevice ? `:${pnDevice}` : ``}@${decoded.server === 'hosted' ? 'hosted.lid' : 'lid'}`
|
|
||||||
|
|
||||||
this.logger.trace(`getLIDForPN: ${pn} → ${deviceSpecificLid} (user mapping with device ${pnDevice})`)
|
|
||||||
successfulPairs[pn] = { lid: deviceSpecificLid, pn }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Object.keys(usyncFetch).length > 0) {
|
if (Object.keys(usyncFetch).length > 0) {
|
||||||
@@ -166,44 +192,77 @@ export class LIDMappingStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return null
|
this.logger.warn('USync fetch yielded no results for pending PNs')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Object.values(successfulPairs)
|
return Object.values(successfulPairs).length > 0 ? Object.values(successfulPairs) : null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get PN for LID - USER LEVEL with device construction
|
* Get PN for LID - USER LEVEL with device construction
|
||||||
*/
|
*/
|
||||||
async getPNForLID(lid: string): Promise<string | null> {
|
async getPNForLID(lid: string): Promise<string | null> {
|
||||||
if (!isLidUser(lid)) return null
|
return (await this.getPNsForLIDs([lid]))?.[0]?.pn || null
|
||||||
|
}
|
||||||
|
|
||||||
const decoded = jidDecode(lid)
|
async getPNsForLIDs(lids: string[]): Promise<LIDMapping[] | null> {
|
||||||
if (!decoded) return null
|
const successfulPairs: { [_: string]: LIDMapping } = {}
|
||||||
|
const pending: Array<{ lid: string; lidUser: string; decoded: ReturnType<typeof jidDecode> }> = []
|
||||||
// Check cache first for LID → PN mapping
|
|
||||||
const lidUser = decoded.user
|
|
||||||
let pnUser = this.mappingCache.get(`lid:${lidUser}`)
|
|
||||||
|
|
||||||
if (!pnUser || typeof pnUser !== 'string') {
|
|
||||||
// Cache miss - check database
|
|
||||||
const stored = await this.keys.get('lid-mapping', [`${lidUser}_reverse`])
|
|
||||||
pnUser = stored[`${lidUser}_reverse`]
|
|
||||||
|
|
||||||
|
const addResolvedPair = (lid: string, decoded: ReturnType<typeof jidDecode>, pnUser: string) => {
|
||||||
if (!pnUser || typeof pnUser !== 'string') {
|
if (!pnUser || typeof pnUser !== 'string') {
|
||||||
this.logger.trace(`No reverse mapping found for LID user: ${lidUser}`)
|
return false
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mappingCache.set(`lid:${lidUser}`, pnUser)
|
const lidDevice = decoded!.device !== undefined ? decoded!.device : 0
|
||||||
|
const pnJid = `${pnUser}:${lidDevice}@${
|
||||||
|
decoded!.domainType === WAJIDDomains.HOSTED_LID ? 'hosted' : 's.whatsapp.net'
|
||||||
|
}`
|
||||||
|
|
||||||
|
this.logger.trace(`Found reverse mapping: ${lid} → ${pnJid}`)
|
||||||
|
successfulPairs[lid] = { lid, pn: pnJid }
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct device-specific PN JID
|
for (const lid of lids) {
|
||||||
const lidDevice = decoded.device !== undefined ? decoded.device : 0
|
if (!isLidUser(lid)) continue
|
||||||
const pnJid = `${pnUser}:${lidDevice}@${decoded.domainType === WAJIDDomains.HOSTED_LID ? 'hosted' : 's.whatsapp.net'}`
|
|
||||||
|
|
||||||
this.logger.trace(`Found reverse mapping: ${lid} → ${pnJid}`)
|
const decoded = jidDecode(lid)
|
||||||
return pnJid
|
if (!decoded) continue
|
||||||
|
|
||||||
|
const lidUser = decoded.user
|
||||||
|
const cached = this.mappingCache.get(`lid:${lidUser}`)
|
||||||
|
if (cached && typeof cached === 'string') {
|
||||||
|
addResolvedPair(lid, decoded, cached)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pending.push({ lid, lidUser, decoded })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pending.length) {
|
||||||
|
const reverseKeys = [...new Set(pending.map(item => `${item.lidUser}_reverse`))]
|
||||||
|
const stored = await this.keys.get('lid-mapping', reverseKeys)
|
||||||
|
|
||||||
|
for (const { lid, lidUser, decoded } of pending) {
|
||||||
|
let pnUser = this.mappingCache.get(`lid:${lidUser}`)
|
||||||
|
if (!pnUser || typeof pnUser !== 'string') {
|
||||||
|
pnUser = stored[`${lidUser}_reverse`]
|
||||||
|
if (pnUser && typeof pnUser === 'string') {
|
||||||
|
this.mappingCache.set(`lid:${lidUser}`, pnUser)
|
||||||
|
this.mappingCache.set(`pn:${pnUser}`, lidUser)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pnUser && typeof pnUser === 'string') {
|
||||||
|
addResolvedPair(lid, decoded, pnUser)
|
||||||
|
} else {
|
||||||
|
this.logger.trace(`No reverse mapping found for LID user: ${lidUser}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.values(successfulPairs).length ? Object.values(successfulPairs) : null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user