chore: sync submodule state (parent ref update)
Made-with: Cursor
This commit is contained in:
162
services/token-aggregation/src/api/server.ts
Normal file
162
services/token-aggregation/src/api/server.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
import express, { Express, Request, Response, NextFunction } from 'express';
|
||||
import cors from 'cors';
|
||||
import compression from 'compression';
|
||||
import { apiRateLimiter, strictRateLimiter } from './middleware/rate-limit';
|
||||
import tokenRoutes from './routes/tokens';
|
||||
import reportRoutes from './routes/report';
|
||||
import adminRoutes from './routes/admin';
|
||||
import configRoutes from './routes/config';
|
||||
import bridgeRoutes from './routes/bridge';
|
||||
import quoteRoutes from './routes/quote';
|
||||
import tokenMappingRoutes from './routes/token-mapping';
|
||||
import { MultiChainIndexer } from '../indexer/chain-indexer';
|
||||
import { getDatabasePool } from '../database/client';
|
||||
import winston from 'winston';
|
||||
|
||||
// Setup logger
|
||||
const logger = winston.createLogger({
|
||||
level: process.env.LOG_LEVEL || 'info',
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp(),
|
||||
winston.format.errors({ stack: true }),
|
||||
winston.format.json()
|
||||
),
|
||||
transports: [
|
||||
new winston.transports.Console({
|
||||
format: winston.format.combine(
|
||||
winston.format.colorize(),
|
||||
winston.format.simple()
|
||||
),
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
export class ApiServer {
|
||||
private app: Express;
|
||||
private port: number;
|
||||
private indexer: MultiChainIndexer;
|
||||
|
||||
constructor() {
|
||||
this.app = express();
|
||||
this.port = parseInt(process.env.PORT || '3000', 10);
|
||||
this.indexer = new MultiChainIndexer();
|
||||
|
||||
this.setupMiddleware();
|
||||
this.setupRoutes();
|
||||
this.setupErrorHandling();
|
||||
}
|
||||
|
||||
private setupMiddleware(): void {
|
||||
// CORS
|
||||
this.app.use(cors());
|
||||
|
||||
// Compression
|
||||
this.app.use(compression());
|
||||
|
||||
// Body parsing
|
||||
this.app.use(express.json());
|
||||
this.app.use(express.urlencoded({ extended: true }));
|
||||
|
||||
// Rate limiting
|
||||
this.app.use('/api/v1', apiRateLimiter);
|
||||
|
||||
// Request logging
|
||||
this.app.use((req: Request, res: Response, next: NextFunction) => {
|
||||
logger.info(`${req.method} ${req.path}`, {
|
||||
ip: req.ip,
|
||||
userAgent: req.get('user-agent'),
|
||||
});
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
private setupRoutes(): void {
|
||||
// Health check
|
||||
this.app.get('/health', async (req: Request, res: Response) => {
|
||||
try {
|
||||
// Check database connection
|
||||
const pool = getDatabasePool();
|
||||
await pool.query('SELECT 1');
|
||||
|
||||
res.json({
|
||||
status: 'healthy',
|
||||
timestamp: new Date().toISOString(),
|
||||
services: {
|
||||
database: 'connected',
|
||||
indexer: 'running',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
res.status(503).json({
|
||||
status: 'unhealthy',
|
||||
timestamp: new Date().toISOString(),
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// API routes
|
||||
this.app.use('/api/v1', tokenRoutes);
|
||||
this.app.use('/api/v1', configRoutes);
|
||||
this.app.use('/api/v1/report', reportRoutes);
|
||||
this.app.use('/api/v1/bridge', bridgeRoutes);
|
||||
this.app.use('/api/v1/token-mapping', tokenMappingRoutes);
|
||||
this.app.use('/api/v1', quoteRoutes);
|
||||
|
||||
// Admin routes (stricter rate limit)
|
||||
this.app.use('/api/v1/admin', strictRateLimiter, adminRoutes);
|
||||
|
||||
// Root
|
||||
this.app.get('/', (req: Request, res: Response) => {
|
||||
res.json({
|
||||
name: 'Token Aggregation Service',
|
||||
version: '1.0.0',
|
||||
endpoints: {
|
||||
health: '/health',
|
||||
api: '/api/v1',
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private setupErrorHandling(): void {
|
||||
// 404 handler
|
||||
this.app.use((req: Request, res: Response) => {
|
||||
res.status(404).json({ error: 'Not found' });
|
||||
});
|
||||
|
||||
// Error handler
|
||||
this.app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
|
||||
logger.error('Unhandled error:', err);
|
||||
res.status(500).json({
|
||||
error: 'Internal server error',
|
||||
message: process.env.NODE_ENV === 'development' ? err.message : undefined,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
try {
|
||||
// Initialize indexer
|
||||
await this.indexer.initialize();
|
||||
|
||||
// Start indexing
|
||||
await this.indexer.startAll();
|
||||
|
||||
// Start server
|
||||
this.app.listen(this.port, () => {
|
||||
logger.info(`Token Aggregation Service listening on port ${this.port}`);
|
||||
logger.info(`Health check: http://localhost:${this.port}/health`);
|
||||
logger.info(`API: http://localhost:${this.port}/api/v1`);
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Failed to start server:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
async stop(): Promise<void> {
|
||||
this.indexer.stopAll();
|
||||
logger.info('Server stopped');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user