import { v4 } from 'uuid' import { Event } from '../Events' import { EventBusInterface } from './EventBusInterface' export type RpcEvent = { topic: string } export class Rpc { constructor(private participant: EventBusInterface) {} // tslint:disable-next-line:member-access async call( event: RpcEvent, request: RpcRequest, timeout: number = 0 ): Promise { return new Promise((resolve, reject) => { const id = v4() const responseEvent: Event = { topic: `${event.topic}/response/${id}` } const requestEvent: Event = { topic: `${event.topic}/request` } const callback = (result: { id: string; payload: RpcResponse; error: unknown }) => { this.participant.unsubscribe(responseEvent as any, callback) if (result.error) { reject(result.error) } else { resolve(result.payload) } console.log('received', result) } this.participant.subscribe(responseEvent, callback) this.participant.emit(requestEvent, { id, payload: request }) if (timeout > 0) { setTimeout(() => { reject(new Error(`Did not respond to ${event.topic} within ${timeout}ms`)) this.participant.unsubscribe(responseEvent as any, callback) }, 10000) } }) } // tslint:disable-next-line:member-access async on( event: RpcEvent, handler: (request: RpcRequest) => Promise ) { this.participant.subscribe({ topic: `${event.topic}/request` }, async request => { let payload let error try { payload = await handler((request as any).payload) } catch (e) { error = e } const { id } = request as any console.log(`${event.topic}/response/${id}`, payload, error) this.participant.emit({ topic: `${event.topic}/response/${id}` }, { id, payload, error }) }) } }