/** * Stock Bot Web API - REST API service for web application */ import { Hono } from 'hono'; import { cors } from 'hono/cors'; import { initializeServiceConfig } from '@stock-bot/config'; import { getLogger, setLoggerConfig, shutdownLoggers } from '@stock-bot/logger'; import { createAndConnectMongoDBClient, MongoDBClient } from '@stock-bot/mongodb-client'; import { createAndConnectPostgreSQLClient, PostgreSQLClient } from '@stock-bot/postgres-client'; import { Shutdown } from '@stock-bot/shutdown'; // Import routes import { exchangeRoutes } from './routes/exchange.routes'; import { healthRoutes } from './routes/health.routes'; import { setMongoDBClient, setPostgreSQLClient } from './clients'; // Initialize configuration with automatic monorepo config inheritance const config = await initializeServiceConfig(); const serviceConfig = config.service; const databaseConfig = config.database; // Initialize logger with config const loggingConfig = config.logging; if (loggingConfig) { setLoggerConfig({ logLevel: loggingConfig.level, logConsole: true, logFile: false, environment: serviceConfig.environment, }); } const app = new Hono(); // Add CORS middleware app.use( '*', cors({ origin: ['http://localhost:4200', 'http://localhost:3000', 'http://localhost:3002'], // React dev server ports allowMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], allowHeaders: ['Content-Type', 'Authorization'], credentials: true, }) ); const logger = getLogger('web-api'); const PORT = serviceConfig.port; let server: ReturnType | null = null; let postgresClient: PostgreSQLClient | null = null; let mongoClient: MongoDBClient | null = null; // Initialize shutdown manager const shutdown = Shutdown.getInstance({ timeout: 15000 }); // Add routes app.route('/health', healthRoutes); app.route('/api/exchanges', exchangeRoutes); // Basic API info endpoint app.get('/', c => { return c.json({ name: 'Stock Bot Web API', version: '1.0.0', status: 'running', timestamp: new Date().toISOString(), endpoints: { health: '/health', exchanges: '/api/exchanges', }, }); }); // Initialize services async function initializeServices() { logger.info('Initializing web API service...'); try { // Initialize MongoDB client logger.info('Connecting to MongoDB...'); const mongoConfig = databaseConfig.mongodb; mongoClient = await createAndConnectMongoDBClient({ uri: mongoConfig.uri, database: mongoConfig.database, host: mongoConfig.host, port: mongoConfig.port, timeouts: { connectTimeout: 30000, socketTimeout: 30000, serverSelectionTimeout: 5000, }, }); setMongoDBClient(mongoClient); logger.info('MongoDB connected'); // Initialize PostgreSQL client logger.info('Connecting to PostgreSQL...'); const pgConfig = databaseConfig.postgres; postgresClient = await createAndConnectPostgreSQLClient({ host: pgConfig.host, port: pgConfig.port, database: pgConfig.database, username: pgConfig.user, password: pgConfig.password, poolSettings: { min: 2, max: pgConfig.poolSize || 10, idleTimeoutMillis: pgConfig.idleTimeout || 30000, }, }); setPostgreSQLClient(postgresClient); logger.info('PostgreSQL connected'); logger.info('All services initialized successfully'); } catch (error) { logger.error('Failed to initialize services', { error }); throw error; } } // Start server async function startServer() { await initializeServices(); server = Bun.serve({ port: PORT, fetch: app.fetch, development: serviceConfig.environment === 'development', }); logger.info(`Stock Bot Web API started on port ${PORT}`); } // Register shutdown handlers shutdown.onShutdown(async () => { if (server) { logger.info('Stopping HTTP server...'); try { server.stop(); logger.info('HTTP server stopped'); } catch (error) { logger.error('Error stopping HTTP server', { error }); } } }); shutdown.onShutdown(async () => { logger.info('Disconnecting from databases...'); try { if (mongoClient) { await mongoClient.disconnect(); } if (postgresClient) { await postgresClient.disconnect(); } logger.info('Database connections closed'); } catch (error) { logger.error('Error closing database connections', { error }); } }); shutdown.onShutdown(async () => { try { await shutdownLoggers(); process.stdout.write('Web API loggers shut down\n'); } catch (error) { process.stderr.write(`Error shutting down loggers: ${error}\n`); } }); // Start the service startServer().catch(error => { logger.error('Failed to start web API service', { error }); process.exit(1); }); logger.info('Web API service startup initiated');