diff --git a/src/bot/orchestrator.ts b/src/bot/orchestrator.ts index ca6c5ed..1dd5c02 100644 --- a/src/bot/orchestrator.ts +++ b/src/bot/orchestrator.ts @@ -133,7 +133,9 @@ export class BotOrchestrator { * Connect to the Gateway WebSocket for this session. */ private async _connectToGateway(): Promise { - const wsUrl = `${this._options.gatewayWsUrl}/${this._options.instanceId}/bot/ws/${this._sessionId}`; + // gatewayWsUrl is the full WebSocket URL provided by the Gateway + // It already includes instanceId and sessionId + const wsUrl = this._options.gatewayWsUrl; this._logger.info(`Connecting to Gateway: ${wsUrl}`); return new Promise((resolve, reject) => { diff --git a/src/index.ts b/src/index.ts index 3852b73..70a81d0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,8 +19,8 @@ async function main(): Promise { // Start HTTP server httpServer = new HttpServer({ - onJoinRequest: async (sessionId, meetingUrl, botName, instanceId) => { - await sessionManager.createSession(sessionId, meetingUrl, botName, instanceId); + onJoinRequest: async (sessionId, meetingUrl, botName, instanceId, gatewayWsUrl) => { + await sessionManager.createSession(sessionId, meetingUrl, botName, instanceId, gatewayWsUrl); }, onLeaveRequest: async (sessionId) => { await sessionManager.endSession(sessionId); diff --git a/src/server/httpServer.ts b/src/server/httpServer.ts index 776d8ac..8152ed1 100644 --- a/src/server/httpServer.ts +++ b/src/server/httpServer.ts @@ -4,7 +4,7 @@ import { logger } from '../utils/logger'; import { config } from '../config'; export interface HttpServerCallbacks { - onJoinRequest: (sessionId: string, meetingUrl: string, botName?: string, instanceId?: string) => Promise; + onJoinRequest: (sessionId: string, meetingUrl: string, botName?: string, instanceId?: string, gatewayWsUrl?: string) => Promise; onLeaveRequest: (sessionId: string) => Promise; onStatusRequest: (sessionId: string) => { state: string; error?: string } | null; } @@ -77,14 +77,14 @@ export class HttpServer { // Deploy a new bot this._app.post('/api/bot', async (req: Request, res: Response) => { try { - const { sessionId, meetingUrl, botName, instanceId } = req.body; + const { sessionId, meetingUrl, botName, instanceId, gatewayWsUrl } = req.body; if (!sessionId || !meetingUrl) { res.status(400).json({ error: 'Missing required fields: sessionId, meetingUrl' }); return; } - await this._callbacks.onJoinRequest(sessionId, meetingUrl, botName, instanceId); + await this._callbacks.onJoinRequest(sessionId, meetingUrl, botName, instanceId, gatewayWsUrl); res.json({ success: true, diff --git a/src/sessionManager.ts b/src/sessionManager.ts index 2808504..e888113 100644 --- a/src/sessionManager.ts +++ b/src/sessionManager.ts @@ -29,12 +29,14 @@ export class SessionManager { * @param meetingUrl - Teams meeting URL * @param botName - Display name for the bot * @param instanceId - Feature instance ID (for Gateway routing) + * @param gatewayWsUrl - Full WebSocket URL to connect back to Gateway (supports multi-instance) */ async createSession( sessionId: string, meetingUrl: string, botName?: string, - instanceId?: string + instanceId?: string, + gatewayWsUrl?: string ): Promise { if (this._sessions.has(sessionId)) { logger.warn(`Session ${sessionId} already exists`); @@ -42,6 +44,7 @@ export class SessionManager { } logger.info(`Creating session ${sessionId} for meeting: ${meetingUrl}`); + logger.info(`Gateway WebSocket URL: ${gatewayWsUrl || 'not provided, using config'}`); const callbacks: OrchestratorCallbacks = { onStateChange: (state, message) => { @@ -56,8 +59,10 @@ export class SessionManager { }; // Options for Gateway connection + // Use the gatewayWsUrl from the request if provided (supports multi-instance gateways) + // Otherwise fall back to config (for local development) const options: OrchestratorOptions = { - gatewayWsUrl: config.gatewayWsUrl, + gatewayWsUrl: gatewayWsUrl || config.gatewayWsUrl, instanceId: instanceId || 'default', };