primer commit
This commit is contained in:
293
gateway/src/index.ts
Normal file
293
gateway/src/index.ts
Normal file
@@ -0,0 +1,293 @@
|
||||
import express from 'express';
|
||||
//import cors from 'cors';
|
||||
import dotenv from 'dotenv';
|
||||
import { WhatsAppClient } from './whatsapp/client';
|
||||
import { QRSocketServer } from './sockets/qr.socket';
|
||||
import { SendController } from './api/send';
|
||||
import { StatusController } from './api/status';
|
||||
import { SessionController } from './api/session';
|
||||
import { MessagesController } from './api/messages';
|
||||
import { n8nController } from './api/n8n';
|
||||
import { WebhookController } from './api/webhook';
|
||||
import { AuthMiddleware } from './middleware/auth';
|
||||
import { logger } from './config/logger';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
class WhatsAppGateway {
|
||||
private app: express.Application;
|
||||
private whatsappClient!: WhatsAppClient;
|
||||
private socketServer!: QRSocketServer;
|
||||
private sendController!: SendController;
|
||||
private statusController!: StatusController;
|
||||
private sessionController!: SessionController;
|
||||
private messagesController!: MessagesController;
|
||||
private n8nController!: n8nController;
|
||||
private webhookController!: WebhookController;
|
||||
|
||||
constructor() {
|
||||
this.app = express();
|
||||
this.setupMiddleware();
|
||||
this.initializeComponents();
|
||||
this.setupRoutes();
|
||||
}
|
||||
|
||||
private setupMiddleware(): void {
|
||||
// Configure CORS for n8n and Manager
|
||||
const corsOrigins = [
|
||||
...(process.env.CORS_ORIGIN ? process.env.CORS_ORIGIN.split(',') : ['http://localhost:3002']),
|
||||
'http://localhost:3004', // Add 3004 for current setup
|
||||
'http://localhost:5678', // n8n default
|
||||
'http://localhost:5679', // n8n alternative
|
||||
...(process.env.N8N_ORIGINS ? process.env.N8N_ORIGINS.split(',') : [])
|
||||
];
|
||||
|
||||
// ⚠️ SOLUCIÓN BRUTA — SOLO DEV
|
||||
this.app.use((req, res, next) => {
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS');
|
||||
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
||||
|
||||
// Intercepta preflight
|
||||
if (req.method === 'OPTIONS') {
|
||||
return res.sendStatus(204);
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
/* this.app.use(cors({
|
||||
origin: corsOrigins,
|
||||
credentials: true,
|
||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
||||
allowedHeaders: ['Content-Type', 'Authorization']
|
||||
}));*/
|
||||
this.app.use(express.json({ limit: '10mb' }));
|
||||
this.app.use(express.urlencoded({ extended: true }));
|
||||
}
|
||||
|
||||
private initializeComponents(): void {
|
||||
const sessionId = process.env.SESSION_ID || 'default';
|
||||
|
||||
this.whatsappClient = new WhatsAppClient(sessionId);
|
||||
this.socketServer = new QRSocketServer(3003);
|
||||
this.sendController = new SendController(this.whatsappClient);
|
||||
this.statusController = new StatusController(this.whatsappClient);
|
||||
this.sessionController = new SessionController(this.whatsappClient);
|
||||
this.messagesController = new MessagesController();
|
||||
this.n8nController = new n8nController(this.whatsappClient);
|
||||
this.webhookController = new WebhookController(process.env.WEBHOOK_URL);
|
||||
|
||||
this.setupWhatsAppEvents();
|
||||
this.connectWhatsApp();
|
||||
this.setupWebSocketCommands();
|
||||
|
||||
// Send current state when new clients connect
|
||||
this.socketServer.onClientConnect = () => {
|
||||
const currentState = this.whatsappClient.getConnectionState();
|
||||
this.socketServer.sendStatus(currentState);
|
||||
};
|
||||
}
|
||||
|
||||
private setupWebSocketCommands(): void {
|
||||
// Handle WebSocket commands from Manager
|
||||
this.socketServer.onCommand = async (command: string, data?: any) => {
|
||||
logger.info(`Received WebSocket command: ${command}`);
|
||||
|
||||
switch (command) {
|
||||
case 'restart_session':
|
||||
await this.sessionController.restartSession({} as any, { json: () => {} } as any);
|
||||
break;
|
||||
case 'logout_session':
|
||||
await this.sessionController.logoutSession({} as any, { json: () => {} } as any);
|
||||
break;
|
||||
case 'generate_token':
|
||||
const tokenResponse = await this.sessionController.generateToken({} as any, { json: (data: any) => {
|
||||
this.socketServer.broadcast({
|
||||
type: 'token_generated',
|
||||
data: JSON.stringify(data)
|
||||
});
|
||||
} } as any);
|
||||
break;
|
||||
case 'get_recent_messages':
|
||||
await this.messagesController.getRecentMessages({} as any, { json: (data: any) => {
|
||||
this.socketServer.broadcast({
|
||||
type: 'status',
|
||||
data: JSON.stringify(data)
|
||||
});
|
||||
} } as any);
|
||||
break;
|
||||
default:
|
||||
logger.warn(`Unknown WebSocket command: ${command}`);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private setupWhatsAppEvents(): void {
|
||||
this.whatsappClient.onQR((qr: string) => {
|
||||
this.socketServer.sendQR(qr);
|
||||
});
|
||||
|
||||
this.whatsappClient.onStatus((status: string) => {
|
||||
this.socketServer.sendStatus(status);
|
||||
logger.info(`WhatsApp status: ${status}`);
|
||||
});
|
||||
|
||||
this.whatsappClient.onMessage(async (message: any) => {
|
||||
try {
|
||||
logger.info('Message received via WhatsApp');
|
||||
|
||||
if (!message || !message.key) {
|
||||
logger.warn('Invalid message structure received');
|
||||
return;
|
||||
}
|
||||
|
||||
// Store in recent messages
|
||||
this.messagesController.handleMessage(message);
|
||||
|
||||
// Forward to webhook
|
||||
await this.webhookController.receiveMessage({
|
||||
id: message.key.id || Date.now().toString(),
|
||||
from: message.key.remoteJid || 'unknown',
|
||||
content: message.message?.conversation || message.message?.extendedTextMessage?.text || '',
|
||||
type: message.message?.conversation ? 'text' : 'document',
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
// Notify Manager
|
||||
this.socketServer.broadcast({
|
||||
type: 'status',
|
||||
data: 'message_received'
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(`Failed to process message: ${error}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async connectWhatsApp(): Promise<void> {
|
||||
try {
|
||||
await this.whatsappClient.connect();
|
||||
logger.info('WhatsApp client initialized');
|
||||
} catch (error) {
|
||||
logger.error(`Failed to initialize WhatsApp client: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
private setupRoutes(): void {
|
||||
// Legacy API Routes (Manager)
|
||||
this.app.post('/api/send', this.sendController.sendMessage);
|
||||
this.app.post('/api/send/bulk', this.sendController.sendBulk);
|
||||
this.app.get('/api/status', this.statusController.getStatus);
|
||||
this.app.get('/api/health', this.statusController.getHealth);
|
||||
|
||||
// Session management (Manager)
|
||||
this.app.post('/api/session/restart', this.sessionController.restartSession);
|
||||
this.app.post('/api/session/logout', this.sessionController.logoutSession);
|
||||
this.app.post('/api/token', this.sessionController.generateToken);
|
||||
|
||||
// Messages (Manager)
|
||||
this.app.get('/api/messages', this.messagesController.getRecentMessages);
|
||||
this.app.delete('/api/messages', this.messagesController.clearMessages);
|
||||
|
||||
// n8n API Core (Component 3)
|
||||
this.app.post('/api/messages/send', AuthMiddleware.middleware('send'), this.n8nController.sendMessage);
|
||||
this.app.get('/api/groups', AuthMiddleware.middleware('messages'), this.n8nController.getGroups);
|
||||
this.app.get('/api/status', AuthMiddleware.middleware('status'), this.n8nController.getStatus);
|
||||
this.app.post('/api/n8n/token', AuthMiddleware.middleware('status'), this.n8nController.validateToken);
|
||||
|
||||
// Public n8n token generation (no auth required)
|
||||
this.app.post('/api/n8n/generate-token', this.n8nController.generateToken);
|
||||
|
||||
// Webhooks for n8n (receiving messages)
|
||||
this.app.post('/webhook/whatsapp', (req, res) => {
|
||||
// This endpoint is for n8n to receive messages FROM WhatsApp
|
||||
res.json({ success: true, message: 'Webhook endpoint active' });
|
||||
});
|
||||
|
||||
// Webhook configuration
|
||||
this.app.post('/api/webhook/configure', AuthMiddleware.middleware('messages'), this.webhookController.configureWebhook);
|
||||
this.app.get('/api/webhook/status', AuthMiddleware.middleware('messages'), this.webhookController.getWebhookStatus);
|
||||
this.app.post('/api/webhook/test', AuthMiddleware.middleware('messages'), this.webhookController.testWebhook);
|
||||
|
||||
// Root endpoint
|
||||
this.app.get('/', (req, res) => {
|
||||
res.json({
|
||||
name: 'WhatsApp Gateway',
|
||||
version: '1.0.0',
|
||||
status: 'running',
|
||||
endpoints: {
|
||||
// Manager endpoints
|
||||
send: 'POST /api/send',
|
||||
sendBulk: 'POST /api/send/bulk',
|
||||
status: 'GET /api/status',
|
||||
health: 'GET /api/health',
|
||||
sessionRestart: 'POST /api/session/restart',
|
||||
sessionLogout: 'POST /api/session/logout',
|
||||
token: 'POST /api/token',
|
||||
messages: 'GET /api/messages',
|
||||
websocket: 'ws://localhost:3003',
|
||||
|
||||
// n8n API Core endpoints
|
||||
n8nSend: 'POST /api/messages/send (Bearer auth required)',
|
||||
n8nStatus: 'GET /api/status (Bearer auth required)',
|
||||
n8nToken: 'POST /api/n8n/generate-token',
|
||||
webhook: 'POST /webhook/whatsapp',
|
||||
webhookConfig: 'POST /api/webhook/configure',
|
||||
webhookTest: 'POST /api/webhook/test'
|
||||
},
|
||||
authentication: {
|
||||
type: 'Bearer Token',
|
||||
header: 'Authorization: Bearer <token>',
|
||||
generate: 'POST /api/n8n/generate-token'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Error handling
|
||||
this.app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||
logger.error(`Unhandled error: ${err}`);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Internal server error',
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
const port = parseInt(process.env.PORT || '3001');
|
||||
|
||||
this.app.listen(port, () => {
|
||||
logger.info(`WhatsApp Gateway API running on port ${port}`);
|
||||
logger.info(`WebSocket server running on port 3003`);
|
||||
logger.info(`Manager Web should connect to: http://localhost:3002`);
|
||||
});
|
||||
}
|
||||
|
||||
async stop(): Promise<void> {
|
||||
await this.whatsappClient.disconnect();
|
||||
this.socketServer.close();
|
||||
logger.info('WhatsApp Gateway stopped');
|
||||
}
|
||||
}
|
||||
|
||||
// Start the gateway
|
||||
const gateway = new WhatsAppGateway();
|
||||
gateway.start().catch(error => {
|
||||
logger.error(`Failed to start gateway: ${error}`);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
// Graceful shutdown
|
||||
process.on('SIGINT', async () => {
|
||||
logger.info('Received SIGINT, shutting down gracefully...');
|
||||
await gateway.stop();
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
process.on('SIGTERM', async () => {
|
||||
logger.info('Received SIGTERM, shutting down gracefully...');
|
||||
await gateway.stop();
|
||||
process.exit(0);
|
||||
});
|
||||
Reference in New Issue
Block a user