Files
com.blitzwallet/app/functions/handleEventEmitters.js
T

173 lines
4.8 KiB
JavaScript

import { AppState } from 'react-native';
const eventQueue = [];
let appStateSubscription = null;
let lastAppState = AppState.currentState;
// Track if we're currently processing the queue to prevent double-processing
let isProcessingQueue = false;
const handleEventEmitterPost = (eventEmitter, eventName, ...eventParams) => {
try {
const listenerCount = eventEmitter.listenerCount?.(eventName);
const [updateType] = eventParams;
const currentAppState = AppState.currentState;
// Determine if we should emit immediately
const isAppActive = currentAppState === 'active';
const hasListeners = listenerCount > 0;
// Only emit immediately if:
// 1. App is active AND has listeners, OR
// 2. It's a user-initiated action AND has listeners (these happen during active state)
if (hasListeners && isAppActive) {
console.log(
`Emitting ${eventName} immediately (type: ${updateType}, active: ${isAppActive})`,
);
eventEmitter.emit(eventName, ...eventParams);
return;
}
// Otherwise, queue the event for later processing
console.log(
`Queueing ${eventName} (type: ${updateType}, active: ${isAppActive}, listeners: ${listenerCount})`,
);
eventQueue.push({
eventEmitter,
eventName,
eventParams,
timestamp: Date.now(),
});
// Set up AppState listener if not already set up
if (!appStateSubscription) {
setupAppStateListener();
}
} catch (err) {
console.log('Error handling event emitter', err);
// Fallback: try to emit anyway
try {
eventEmitter.emit(eventName, ...eventParams);
} catch (emitErr) {
console.log('Failed to emit event in fallback', emitErr);
}
}
};
const setupAppStateListener = () => {
const handleAppStateChange = nextAppState => {
console.log(`AppState changed from ${lastAppState} to ${nextAppState}`);
// Only process queue when transitioning TO active state
if (nextAppState === 'active') {
processQueuedEvents();
}
lastAppState = nextAppState;
};
console.log('Adding single AppState subscription');
appStateSubscription = AppState.addEventListener(
'change',
handleAppStateChange,
);
};
const processQueuedEvents = async () => {
if (isProcessingQueue) {
console.log('Already processing queue, skipping...');
return;
}
if (eventQueue.length === 0) {
console.log('No events to process');
return;
}
isProcessingQueue = true;
console.log(`Processing ${eventQueue.length} queued events`);
// Process all queued events
const eventsToProcess = [...eventQueue];
eventQueue.length = 0; // Clear the queue
for (const queuedEvent of eventsToProcess) {
const { eventEmitter, eventName, eventParams, timestamp } = queuedEvent;
const age = Date.now() - timestamp;
try {
const listenerCount = eventEmitter.listenerCount?.(eventName);
if (!listenerCount) {
console.log(
`No listeners found for ${eventName} after ${age}ms, using fallback`,
);
await attemptEmitWithRetry(eventEmitter, eventName, eventParams);
} else {
console.log(`Emitting queued ${eventName} after ${age}ms`);
eventEmitter.emit(eventName, ...eventParams);
}
// Small delay between events to prevent overwhelming the system
await new Promise(resolve => setTimeout(resolve, 50));
} catch (err) {
console.error(`Error processing queued event ${eventName}:`, err);
}
}
isProcessingQueue = false;
console.log('Finished processing queued events');
};
const attemptEmitWithRetry = async (eventEmitter, eventName, eventParams) => {
let attempts = 0;
const maxAttempts = 3;
const retryDelay = 2000;
return new Promise(resolve => {
const attemptEmit = () => {
attempts++;
console.log(`Retry attempt ${attempts}/${maxAttempts} for ${eventName}`);
const listenerCount = eventEmitter.listenerCount?.(eventName);
if (listenerCount > 0) {
const success = eventEmitter.emit(eventName, ...eventParams);
if (success) {
console.log(
`Successfully emitted ${eventName} on attempt ${attempts}`,
);
resolve(true);
return;
}
}
if (attempts >= maxAttempts) {
console.log(
`Failed to emit ${eventName} after ${maxAttempts} attempts`,
);
resolve(false);
return;
}
setTimeout(attemptEmit, retryDelay);
};
attemptEmit();
});
};
const cleanupEventHandler = () => {
if (appStateSubscription) {
console.log('Cleaning up AppState subscription');
appStateSubscription.remove();
appStateSubscription = null;
}
eventQueue.length = 0;
isProcessingQueue = false;
lastAppState = AppState.currentState;
};
// Export functions
export { handleEventEmitterPost, cleanupEventHandler };