140 lines
3.7 KiB
TypeScript
140 lines
3.7 KiB
TypeScript
import express, { Express, Request, Response } from 'express';
|
|
import { Server } from 'http';
|
|
import { logger } from '../utils/logger';
|
|
import { config } from '../config';
|
|
|
|
export interface HttpServerCallbacks {
|
|
onJoinRequest: (sessionId: string, meetingUrl: string, botName?: string, instanceId?: string, gatewayWsUrl?: string) => Promise<void>;
|
|
onLeaveRequest: (sessionId: string) => Promise<void>;
|
|
onStatusRequest: (sessionId: string) => { state: string; error?: string } | null;
|
|
}
|
|
|
|
/**
|
|
* HTTP server for the Bot Launcher API.
|
|
* Provides endpoints to deploy/control bots.
|
|
*/
|
|
export class HttpServer {
|
|
private _app: Express;
|
|
private _server: Server | null = null;
|
|
private _callbacks: HttpServerCallbacks;
|
|
|
|
constructor(callbacks: HttpServerCallbacks) {
|
|
this._callbacks = callbacks;
|
|
this._app = express();
|
|
this._setupMiddleware();
|
|
this._setupRoutes();
|
|
}
|
|
|
|
/**
|
|
* Start the HTTP server.
|
|
*/
|
|
async start(): Promise<void> {
|
|
return new Promise((resolve) => {
|
|
this._server = this._app.listen(config.port, () => {
|
|
logger.info(`HTTP server listening on port ${config.port}`);
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Stop the HTTP server.
|
|
*/
|
|
async stop(): Promise<void> {
|
|
return new Promise((resolve, reject) => {
|
|
if (!this._server) {
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
this._server.close((err) => {
|
|
if (err) {
|
|
reject(err);
|
|
} else {
|
|
logger.info('HTTP server stopped');
|
|
resolve();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
private _setupMiddleware(): void {
|
|
this._app.use(express.json());
|
|
|
|
// Request logging
|
|
this._app.use((req, res, next) => {
|
|
logger.debug(`${req.method} ${req.path}`);
|
|
next();
|
|
});
|
|
}
|
|
|
|
private _setupRoutes(): void {
|
|
// Health check
|
|
this._app.get('/health', (req: Request, res: Response) => {
|
|
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
|
});
|
|
|
|
// Deploy a new bot
|
|
this._app.post('/api/bot', async (req: Request, res: Response) => {
|
|
try {
|
|
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, gatewayWsUrl);
|
|
|
|
res.json({
|
|
success: true,
|
|
sessionId,
|
|
message: 'Bot deployment started',
|
|
});
|
|
} catch (error) {
|
|
logger.error('Error deploying bot:', error);
|
|
res.status(500).json({ error: (error as Error).message });
|
|
}
|
|
});
|
|
|
|
// Leave meeting
|
|
this._app.post('/api/bot/:sessionId/leave', async (req: Request, res: Response) => {
|
|
try {
|
|
const { sessionId } = req.params;
|
|
|
|
await this._callbacks.onLeaveRequest(sessionId);
|
|
|
|
res.json({
|
|
success: true,
|
|
sessionId,
|
|
message: 'Bot leave initiated',
|
|
});
|
|
} catch (error) {
|
|
logger.error('Error leaving meeting:', error);
|
|
res.status(500).json({ error: (error as Error).message });
|
|
}
|
|
});
|
|
|
|
// Get bot status
|
|
this._app.get('/api/bot/:sessionId/status', (req: Request, res: Response) => {
|
|
const { sessionId } = req.params;
|
|
const status = this._callbacks.onStatusRequest(sessionId);
|
|
|
|
if (!status) {
|
|
res.status(404).json({ error: 'Session not found' });
|
|
return;
|
|
}
|
|
|
|
res.json({
|
|
sessionId,
|
|
...status,
|
|
});
|
|
});
|
|
|
|
// List all active bots
|
|
this._app.get('/api/bots', (req: Request, res: Response) => {
|
|
// This would need access to the session manager
|
|
res.json({ message: 'Not implemented' });
|
|
});
|
|
}
|
|
}
|