import { NativeModules, NativeEventEmitter, EventSubscriptionVendor, } from 'react-native'; /** * Interface for a background module. */ interface PLXBackgroundInterface extends EventSubscriptionVendor { /** * Create a timer. * @param timeout Time after timer resolves. * @param timeoutId Timer identifier. */ setTimeout(timeout: number, timeoutId: string): Promise<string>; /** * Clear a timer. * @param timeoutId Timer identifier. */ clearTimeout(timeoutId: string): void; /** * Mark the begining of a background task. * @param taskName Task name. */ startBackgroundTask(taskName: string): Promise<string>; /** * Mark the end of background task. * @param taskName Task name. */ endBackgroundTask(taskName: string): void; /** * Marks background processing task as completed. * @param taskName Task name identifier. * @param result True if task completed successfully */ completeBackgroundProcessing(taskName: string, result: boolean): void; /** * Schedule task number of milliseconds into the future. There is no guarantee * that task will execute exactly in specified time. * @param taskName Task name identifier. * @param timeout Timeout in milliseconds. */ scheduleBackgroundProcessing( taskName: string, timeout: number, ): Promise<string>; /** * Cancel background processing task. * @param taskName Task name identifier. */ cancelBackgroundProcess(taskName: string): void; /** * Cancel all background processing tasks. */ cancelAllScheduledBackgroundProcesses(): void; } // Events emitted by PLXBackground module. const BackgroundTaskExpired = 'BackgroundTaskExpired'; const BackgroundProcessingExecuting = 'BackgroundProcessingExecuting'; const BackgroundProcessingExpired = 'BackgroundProcessingExpired'; interface BackgroundTaskExpiredEvent { taskName: string; } interface BackgroundProcessingExecutingEvent { taskName: string; } interface BackgroundProcessingExpiredEvent { taskName: string; } // Getting handles to background module and its event emitter. const PLXBackground: PLXBackgroundInterface = NativeModules.PLXBackground; if (PLXBackground == null) { console.error('PLXBackground is not defined!'); } const PLXEventEmitter = new NativeEventEmitter(PLXBackground); // Timers identifiers. let nextTimeoutId = 0; /** * Create a timer. * @param callback Callback invoked when timer fires. * @param timeout Time after which timer fires. */ const setTimeout = (callback: () => void, timeout: number) => { const timeoutId = nextTimeoutId++; PLXBackground.setTimeout(timeout, timeoutId.toString()).then(() => { callback(); }); return timeoutId; }; /** * Clears timer with specified id. * @param timeoutId Timer ID. */ const clearTimeout = (timeoutId: number) => { PLXBackground.clearTimeout(timeoutId.toString()); }; /** * Starts background task. * @param taskName Name of a task * @param expiredCallback Callback invoked when task expired. User should call * `endBackgroundTask` as soon as possible. */ const startBackgroundTask = async ( taskName: string, expiredCallback: (taskName: string) => void, ) => { const listener = (event: BackgroundTaskExpiredEvent) => { if (event.taskName === taskName) { expiredCallback(event.taskName); PLXEventEmitter.removeListener(BackgroundTaskExpired, listener); } }; try { PLXEventEmitter.addListener(BackgroundTaskExpired, listener); await PLXBackground.startBackgroundTask(taskName); } catch { PLXEventEmitter.removeListener(BackgroundTaskExpired, listener); } return taskName; }; let registeredCallbacks: { [taskName: string]: { execution: (event: BackgroundProcessingExecutingEvent) => void; expired: (event: BackgroundProcessingExpiredEvent) => void; }; } = {}; /** * * @param taskName Task name to execute. * @param timeout Timeout in millisecond after which task executes. * @param taskExecutionCallback Callback invoked when task execution started. * @param taskExpiredCallback Callback invoked when task execution expired. */ const scheduleBackgroundProcessingTask = async ( taskName: string, timeout: number, taskExecutionCallback: (taskName: string) => void, taskExpiredCallback: (taskName: string) => void, ) => { const executingCallback = (event: BackgroundProcessingExecutingEvent) => { taskExecutionCallback(event.taskName); }; const expiredCallback = (event: BackgroundProcessingExpiredEvent) => { taskExpiredCallback(event.taskName); }; PLXEventEmitter.addListener(BackgroundProcessingExecuting, executingCallback); PLXEventEmitter.addListener(BackgroundProcessingExpired, expiredCallback); try { await PLXBackground.scheduleBackgroundProcessing(taskName, timeout); registeredCallbacks[taskName] = { execution: executingCallback, expired: expiredCallback, }; } catch (error) { PLXEventEmitter.removeListener( BackgroundProcessingExecuting, executingCallback, ); PLXEventEmitter.removeListener( BackgroundProcessingExpired, expiredCallback, ); throw error; } }; /** * Mark background processing task as completed. * @param taskName Task name. * @param result True if task completed successfully */ const completeBackgroundProcessingTask = ( taskName: string, result: boolean, ) => { const callbacks = registeredCallbacks[taskName]; if (callbacks != null) { PLXEventEmitter.removeListener( BackgroundProcessingExecuting, callbacks.execution, ); PLXEventEmitter.removeListener( BackgroundProcessingExpired, callbacks.expired, ); delete registeredCallbacks[taskName]; } PLXBackground.completeBackgroundProcessing(taskName, result); }; /** * Cancel background processing task. * @param taskName Task name */ const cancelBackgroundProcessingTask = (taskName: string) => { const callbacks = registeredCallbacks[taskName]; if (callbacks != null) { PLXEventEmitter.removeListener( BackgroundProcessingExecuting, callbacks.execution, ); PLXEventEmitter.removeListener( BackgroundProcessingExpired, callbacks.expired, ); delete registeredCallbacks[taskName]; } PLXBackground.cancelBackgroundProcess(taskName); }; /** * Cancel all background processing tasks */ const cancelAllBackgroundProcessingTasks = () => { PLXEventEmitter.removeAllListeners(BackgroundProcessingExecuting); PLXEventEmitter.removeAllListeners(BackgroundProcessingExpired); registeredCallbacks = {}; }; export default { setTimeout, clearTimeout, startBackgroundTask, endBackgroundTask: PLXBackground.endBackgroundTask, scheduleBackgroundProcessingTask, completeBackgroundProcessingTask, cancelBackgroundProcessingTask, cancelAllBackgroundProcessingTasks, };