From a4a2631205ce0c36cbf1cc1e59b68b49734b2871 Mon Sep 17 00:00:00 2001 From: Ariel Mannes Date: Tue, 1 Jul 2025 12:28:02 +0300 Subject: [PATCH] use eventEmmiter2 to let user init the bot before sending session.initiated message --- package-lock.json | 7 +++++++ package.json | 1 + src/websocket/bot-api.ts | 8 +++++--- src/websocket/bot-conversation.ts | 32 ++++++++++++++++++++++++------- 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 24198f7..4e7f14b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "debug": "^4.4.1", + "eventemitter2": "^6.4.9", "ws": "^8.18.2" }, "devDependencies": { @@ -1162,6 +1163,12 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter2": { + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", + "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==", + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", diff --git a/package.json b/package.json index ace997f..00a934c 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ }, "dependencies": { "debug": "^4.4.1", + "eventemitter2": "^6.4.9", "ws": "^8.18.2" } } diff --git a/src/websocket/bot-api.ts b/src/websocket/bot-api.ts index 92b6929..20fe9ad 100644 --- a/src/websocket/bot-api.ts +++ b/src/websocket/bot-api.ts @@ -1,6 +1,7 @@ import debug from 'debug'; import http, { IncomingMessage } from 'node:http'; -import { EventEmitter } from 'node:events'; +import ee2 from 'eventemitter2'; +const { EventEmitter2 } = ee2; import { WebSocket, WebSocketServer } from 'ws'; import { BotConversationWebSocket } from './bot-conversation.js'; import { ProtocolMessage } from './types.js'; @@ -14,7 +15,7 @@ export interface BotApiServerOptions { token?: string; } -export class BotApiWebSocket extends EventEmitter { +export class BotApiWebSocket extends EventEmitter2 { private server?: http.Server; #port = 8080; @@ -39,8 +40,9 @@ export class BotApiWebSocket extends EventEmitter { }); webSockServer.on('connection', (websocket: WebSocket, request: IncomingMessage) => { const conversation = new BotConversationWebSocket(websocket); + // eslint-disable-next-line @typescript-eslint/no-misused-promises conversation.on('conversation.start', (initiateMessage: ProtocolMessage) => { - this.emit('conversation', conversation, { request, initiateMessage }); + return this.emitAsync('conversation', conversation, { request, initiateMessage }); }); }); diff --git a/src/websocket/bot-conversation.ts b/src/websocket/bot-conversation.ts index a7ed277..cae52f2 100644 --- a/src/websocket/bot-conversation.ts +++ b/src/websocket/bot-conversation.ts @@ -10,8 +10,9 @@ import { ProtocolMessage, VaicToBotMessageName } from './types.js'; -import { EventEmitter } from 'events'; +import ee2, { type Listener } from 'eventemitter2'; import { PassThrough, Readable, } from 'stream'; +const { EventEmitter2 } = ee2; const log = debug('ac-bot-api'); @@ -24,8 +25,15 @@ function redactMessage(message: ProtocolMessage) { }; } -// TODO: EventEmitter -export class BotConversationWebSocket extends EventEmitter { + +declare interface BotConversationEvents { + on(event: 'conversation.start', listener: (message: ProtocolMessage) => Promise): this | Listener; + on(event: 'userStream', listener: (stream: PassThrough, options: { message: ProtocolMessage }) => void): this | Listener; + on(event: 'activity', listener: (activity: BotActivity) => void): this | Listener; + on(event: 'end', listener: (message?: ProtocolMessage) => void): this | Listener; + on(event: 'error', listener: (error: Error) => void): this | Listener; +} +export class BotConversationWebSocket extends EventEmitter2 implements BotConversationEvents { private ended = false; private conversationId = ''; private mediaFormat = MediaFormat.RAW_LINEAR_16; @@ -108,10 +116,20 @@ export class BotConversationWebSocket extends EventEmitter { switch (msgJson.type) { case VaicToBotMessageName.sessionInitiate: { this.conversationId = msgJson.conversationId!; - this.emit('conversation.start', msgJson); - await this.send(BotToVaicMessageName.sessionAccepted, { - mediaFormat: this.mediaFormat - }); + try { + await this.emitAsync('conversation.start', msgJson); + await this.send(BotToVaicMessageName.sessionAccepted, { + mediaFormat: this.mediaFormat + }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (error: any) { + this.#log('Error handling conversation.start:', error); + await this.send(BotToVaicMessageName.sessionError, { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + reason: `Error handling conversation.start: ${error.message || error}`, + }); + this.close(); + } break; } case VaicToBotMessageName.sessionResume: