UNPKG

@novo-learning/novo-sdk

Version:

SDK for the Novolanguage Speech Analysis API

113 lines (99 loc) 3.6 kB
import { AsrMessageType } from '../entities/asr-message-type'; import { IntermediateResult, Result } from '../entities/index'; import { EventBus } from '../event-bus'; import { PermissionDeniedEvent } from '../events'; import { AsrMessageReceivedEvent } from '../events/asr-message-received.event'; import { RecognitionProgressEvent } from '../events/recognition-progress.event'; import { Deferred } from '../utils/deferred.promise'; class Message<T> { timestamp = new Date(); defer = new Deferred<T>(); constructor(readonly request: { event: string; data: { id: number; params?: unknown } }) {} } export class MessageQueue { private messageId = 0; // eslint-disable-next-line @typescript-eslint/no-explicit-any private requests: { [key: number]: Message<any> } = {}; constructor(private readonly eventBus: EventBus, private readonly websocket: WebSocket) { this.websocket.onmessage = (event): void => { try { const result: { event: AsrMessageType; data: IntermediateResult | Result; error?: string } = JSON.parse( event.data, ); if (result.error) { if (result.error.indexOf('Unauthorized') >= 0) { this.eventBus.dispatch<PermissionDeniedEvent>(PermissionDeniedEvent.type); return; } console.error(result.error); return; } if (!result?.data) { return; } if (this.isIntermediateResult(result)) { this.parseIntermediateResult(result.data); } else { this.parseResult(result.data as Result); } } catch (err: unknown) { if (typeof event.data === 'string') { if (event.data.indexOf('Unauthorized') >= 0) { this.eventBus.dispatch<PermissionDeniedEvent>(PermissionDeniedEvent.type); return; } } // Message was not JSON console.error(err); } }; } async request<P, T>(method: string, params?: P): Promise<T | undefined> { if (this.websocket?.readyState === WebSocket.OPEN) { const id = this.getID(); const request = { event: method, data: { id, params }, }; this.requests[id] = new Message<T>(request); this.websocket.send(JSON.stringify(request)); return this.requests[id].defer.promise; } return undefined; } parseIntermediateResult(result: IntermediateResult): void { this.eventBus.dispatch<RecognitionProgressEvent>(RecognitionProgressEvent.type, result); } parseResult(result: Result): void { if (result.result !== AsrMessageType.PONG) { this.eventBus.dispatch<AsrMessageReceivedEvent>(AsrMessageReceivedEvent.type, { message: result }); } if (!(result.id in this.requests)) { console.error('Could not interpret result', result); return; } const request = this.requests[result.id]; if (request != null) { delete this.requests[result.id]; } if (result.result) { request.defer.resolve(result.result); } else { request.defer.reject(result.error); } } isIntermediateResult(result: { event: AsrMessageType; data: Result | IntermediateResult; }): result is { event: AsrMessageType; data: IntermediateResult } { return result.event === AsrMessageType.INTERMEDIATE_RESULT; } clearMessageQueue(): void { Object.keys(this.requests).forEach((requestId) => this.requests[Number(requestId)].defer.reject('Connection to speech recognizer was lost'), ); } private getID(): number { return ++this.messageId; } }