fix: eliminate 40s message delivery delay caused by libsignal console dumps
fix: eliminate 40s message delivery delay caused by libsignal console dumps
This commit is contained in:
@@ -25,7 +25,7 @@ interface MockMessageRetryManager {
|
||||
/** Mirrors jidNormalizedUser: strips device suffix from JID user part */
|
||||
function jidNormalizedUser(jid: string): string {
|
||||
const atIdx = jid.indexOf('@')
|
||||
if(atIdx < 0) return jid
|
||||
if (atIdx < 0) return jid
|
||||
const user = jid.slice(0, atIdx)
|
||||
const server = jid.slice(atIdx + 1)
|
||||
const normalizedUser = user.includes(':') ? user.split(':')[0] : user
|
||||
@@ -46,9 +46,9 @@ async function handleBadAck463(
|
||||
const jid = jidNormalizedUser(attrs.from)
|
||||
const key: MockKey = { remoteJid: attrs.from, fromMe: true, id: msgId }
|
||||
|
||||
if(attrs.error === '463') {
|
||||
if (attrs.error === '463') {
|
||||
const retryKey = `${jid}:${msgId}`
|
||||
if(msgId && jid && !tcTokenRetriedMsgIds.has(retryKey)) {
|
||||
if (msgId && jid && !tcTokenRetriedMsgIds.has(retryKey)) {
|
||||
tcTokenRetriedMsgIds.add(retryKey)
|
||||
// Each entry auto-expires after 60s — naturally bounded under normal use
|
||||
setTimeout(() => tcTokenRetriedMsgIds.delete(retryKey), 60_000)
|
||||
@@ -57,7 +57,7 @@ async function handleBadAck463(
|
||||
(await getMessage(key)) ??
|
||||
// Fallback: ack can arrive <30ms after send, before store persists
|
||||
messageRetryManager?.getRecentMessage(jid, msgId)?.message
|
||||
if(msg) {
|
||||
if (msg) {
|
||||
try {
|
||||
await delayFn(1500)
|
||||
await relayMessage(jid, msg, {
|
||||
@@ -190,7 +190,7 @@ describe('handleBadAck error 463 retry', () => {
|
||||
})
|
||||
|
||||
it('should not retry for non-463 errors', async () => {
|
||||
for(const errorCode of ['479', '421']) {
|
||||
for (const errorCode of ['479', '421']) {
|
||||
mockGetMessage.mockClear()
|
||||
mockRelayMessage.mockClear()
|
||||
mockEmit.mockClear()
|
||||
@@ -274,7 +274,9 @@ describe('handleBadAck error 463 retry', () => {
|
||||
it('should fall back to messageRetryManager when getMessage returns undefined', async () => {
|
||||
const cachedMsg = { conversation: 'cached' }
|
||||
const mockRetryManager: MockMessageRetryManager = {
|
||||
getRecentMessage: jest.fn<(jid: string, msgId: string) => { message: any } | undefined>().mockReturnValue({ message: cachedMsg })
|
||||
getRecentMessage: jest
|
||||
.fn<(jid: string, msgId: string) => { message: any } | undefined>()
|
||||
.mockReturnValue({ message: cachedMsg })
|
||||
}
|
||||
mockGetMessage.mockResolvedValue(undefined)
|
||||
mockRelayMessage.mockResolvedValue(undefined)
|
||||
|
||||
@@ -36,15 +36,11 @@ function makeState(): OfflineBufferState {
|
||||
* Mirrors the process.nextTick block that arms the offline-buffer timer.
|
||||
* Only called when creds.me?.id is set (reconnection path).
|
||||
*/
|
||||
function startBuffer(
|
||||
state: OfflineBufferState,
|
||||
flush: () => void,
|
||||
warn: () => void
|
||||
): void {
|
||||
function startBuffer(state: OfflineBufferState, flush: () => void, warn: () => void): void {
|
||||
state.didStartBuffer = true
|
||||
state.offlineBufferTimeout = setTimeout(() => {
|
||||
state.offlineBufferTimeout = undefined
|
||||
if(state.didStartBuffer) {
|
||||
if (state.didStartBuffer) {
|
||||
warn()
|
||||
flush()
|
||||
state.didStartBuffer = false
|
||||
@@ -57,12 +53,12 @@ function startBuffer(
|
||||
* delivers all offline notifications before the safety timer fires.
|
||||
*/
|
||||
function onOffline(state: OfflineBufferState, flush: () => void): void {
|
||||
if(state.offlineBufferTimeout) {
|
||||
if (state.offlineBufferTimeout) {
|
||||
clearTimeout(state.offlineBufferTimeout)
|
||||
state.offlineBufferTimeout = undefined
|
||||
}
|
||||
|
||||
if(state.didStartBuffer) {
|
||||
if (state.didStartBuffer) {
|
||||
flush()
|
||||
state.didStartBuffer = false
|
||||
}
|
||||
@@ -73,7 +69,7 @@ function onOffline(state: OfflineBufferState, flush: () => void): void {
|
||||
* flag so a closing socket cannot emit stale events after the fact.
|
||||
*/
|
||||
function onClose(state: OfflineBufferState): void {
|
||||
if(state.offlineBufferTimeout) {
|
||||
if (state.offlineBufferTimeout) {
|
||||
clearTimeout(state.offlineBufferTimeout)
|
||||
state.offlineBufferTimeout = undefined
|
||||
}
|
||||
@@ -97,7 +93,7 @@ describe('offline-buffer safety timer (socket.ts)', () => {
|
||||
|
||||
afterEach(() => {
|
||||
// Clean up any remaining timer to avoid cross-test interference
|
||||
if(state.offlineBufferTimeout) {
|
||||
if (state.offlineBufferTimeout) {
|
||||
clearTimeout(state.offlineBufferTimeout)
|
||||
}
|
||||
|
||||
|
||||
@@ -596,8 +596,8 @@ describe('tctoken integration scenarios', () => {
|
||||
const expiredJids: string[] = []
|
||||
const validJids: string[] = []
|
||||
|
||||
for(const [jid, entry] of Object.entries(entries)) {
|
||||
if(isTcTokenExpired(entry.timestamp)) {
|
||||
for (const [jid, entry] of Object.entries(entries)) {
|
||||
if (isTcTokenExpired(entry.timestamp)) {
|
||||
expiredJids.push(jid)
|
||||
} else {
|
||||
validJids.push(jid)
|
||||
@@ -617,8 +617,8 @@ describe('tctoken integration scenarios', () => {
|
||||
}
|
||||
|
||||
const deletions: Record<string, null> = {}
|
||||
for(const [jid, entry] of Object.entries(entries)) {
|
||||
if(isTcTokenExpired(entry.timestamp)) {
|
||||
for (const [jid, entry] of Object.entries(entries)) {
|
||||
if (isTcTokenExpired(entry.timestamp)) {
|
||||
deletions[jid] = null
|
||||
}
|
||||
}
|
||||
@@ -635,8 +635,8 @@ describe('tctoken integration scenarios', () => {
|
||||
}
|
||||
|
||||
const deletions: Record<string, null> = {}
|
||||
for(const [jid, entry] of Object.entries(entries)) {
|
||||
if(isTcTokenExpired(entry.timestamp)) {
|
||||
for (const [jid, entry] of Object.entries(entries)) {
|
||||
if (isTcTokenExpired(entry.timestamp)) {
|
||||
deletions[jid] = null
|
||||
}
|
||||
}
|
||||
@@ -652,8 +652,8 @@ describe('tctoken integration scenarios', () => {
|
||||
}
|
||||
|
||||
const deletions: Record<string, null> = {}
|
||||
for(const [jid, entry] of Object.entries(entries)) {
|
||||
if(isTcTokenExpired(entry.timestamp)) {
|
||||
for (const [jid, entry] of Object.entries(entries)) {
|
||||
if (isTcTokenExpired(entry.timestamp)) {
|
||||
deletions[jid] = null
|
||||
}
|
||||
}
|
||||
@@ -669,8 +669,8 @@ describe('tctoken integration scenarios', () => {
|
||||
}
|
||||
|
||||
const deletions: Record<string, null> = {}
|
||||
for(const [jid, entry] of Object.entries(entries)) {
|
||||
if(isTcTokenExpired((entry as any).timestamp)) {
|
||||
for (const [jid, entry] of Object.entries(entries)) {
|
||||
if (isTcTokenExpired((entry as any).timestamp)) {
|
||||
deletions[jid] = null
|
||||
}
|
||||
}
|
||||
@@ -769,8 +769,8 @@ describe('tctoken integration scenarios', () => {
|
||||
it('index ignores sentinel key when loading', () => {
|
||||
const jids = [JID_A, INDEX_KEY, JID_B, '', null as any]
|
||||
const loaded = new Set<string>()
|
||||
for(const jid of jids) {
|
||||
if(jid && jid !== INDEX_KEY) {
|
||||
for (const jid of jids) {
|
||||
if (jid && jid !== INDEX_KEY) {
|
||||
loaded.add(jid)
|
||||
}
|
||||
}
|
||||
@@ -794,9 +794,9 @@ describe('tctoken integration scenarios', () => {
|
||||
}
|
||||
|
||||
const expiredDeletions: Record<string, null> = {}
|
||||
for(const jid of knownJids) {
|
||||
for (const jid of knownJids) {
|
||||
const entry = allTokens[jid]
|
||||
if(!entry?.token || isTcTokenExpired(entry.timestamp)) {
|
||||
if (!entry?.token || isTcTokenExpired(entry.timestamp)) {
|
||||
expiredDeletions[jid] = null
|
||||
knownJids.delete(jid)
|
||||
}
|
||||
@@ -823,7 +823,7 @@ describe('tctoken integration scenarios', () => {
|
||||
}
|
||||
|
||||
// First add → triggers save
|
||||
if(!knownJids.has(JID_A)) {
|
||||
if (!knownJids.has(JID_A)) {
|
||||
knownJids.add(JID_A)
|
||||
scheduleSave()
|
||||
}
|
||||
@@ -831,7 +831,7 @@ describe('tctoken integration scenarios', () => {
|
||||
expect(saveCount).toBe(1)
|
||||
|
||||
// Duplicate add → no save
|
||||
if(!knownJids.has(JID_A)) {
|
||||
if (!knownJids.has(JID_A)) {
|
||||
knownJids.add(JID_A)
|
||||
scheduleSave()
|
||||
}
|
||||
@@ -839,7 +839,7 @@ describe('tctoken integration scenarios', () => {
|
||||
expect(saveCount).toBe(1)
|
||||
|
||||
// New JID → triggers save
|
||||
if(!knownJids.has(JID_B)) {
|
||||
if (!knownJids.has(JID_B)) {
|
||||
knownJids.add(JID_B)
|
||||
scheduleSave()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user