// Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import { ipcRenderer } from 'electron'; import { explodePromise } from './util/explodePromise'; import { SECOND } from './util/durations'; import * as log from './logging/log'; import type { IPCResponse as ChallengeResponseType } from './challenge'; type ResolveType = (data: unknown) => void; export class CI { private readonly eventListeners = new Map>(); private readonly completedEvents = new Map>(); constructor(public readonly deviceName: string) { ipcRenderer.on('ci:event', (_, event, data) => { this.handleEvent(event, data); }); } public async waitForEvent( event: string, timeout = 60 * SECOND ): Promise { const pendingCompleted = this.completedEvents.get(event) || []; const pending = pendingCompleted.shift(); if (pending) { log.info(`CI: resolving pending result for ${event}`, pending); if (pendingCompleted.length === 0) { this.completedEvents.delete(event); } return pending; } log.info(`CI: waiting for event ${event}`); const { resolve, reject, promise } = explodePromise(); const timer = setTimeout(() => { reject(new Error('Timed out')); }, timeout); let list = this.eventListeners.get(event); if (!list) { list = []; this.eventListeners.set(event, list); } list.push((value: unknown) => { clearTimeout(timer); resolve(value); }); return promise; } public setProvisioningURL(url: string): void { this.handleEvent('provisioning-url', url); } public handleEvent(event: string, data: unknown): void { const list = this.eventListeners.get(event) || []; const resolve = list.shift(); if (resolve) { if (list.length === 0) { this.eventListeners.delete(event); } log.info(`CI: got event ${event} with data`, data); resolve(data); return; } log.info(`CI: postponing event ${event}`); let resultList = this.completedEvents.get(event); if (!resultList) { resultList = []; this.completedEvents.set(event, resultList); } resultList.push(data); } public solveChallenge(response: ChallengeResponseType): void { window.Signal.challengeHandler?.onResponse(response); } }