| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- /* eslint-disable @typescript-eslint/no-explicit-any */
- import { WebSocketServer, WebSocket } from 'ws';
- import { Server } from 'http';
- import { ImportProgress } from './types';
- export class ImportProgressServer {
- private wss: WebSocketServer | null = null;
- private clients: Set<WebSocket> = new Set();
- private static instance: ImportProgressServer | null = null;
- private port: number = 8081;
- private isInitialized: boolean = false;
- private constructor() {
- // Private constructor for singleton pattern
- }
- public static getInstance(): ImportProgressServer {
- if (!ImportProgressServer.instance) {
- ImportProgressServer.instance = new ImportProgressServer();
- }
- return ImportProgressServer.instance;
- }
- public initialize(): void {
- if (this.isInitialized) {
- console.log('WebSocket server already initialized');
- return;
- }
- try {
- // Try to create WebSocket server on the specified port
- this.wss = new WebSocketServer({ port: this.port });
-
- this.setupWebSocketHandlers();
- this.isInitialized = true;
- console.log(`WebSocket server started on port ${this.port}`);
-
- } catch (error: any) {
- if (error.code === 'EADDRINUSE') {
- console.log(`Port ${this.port} is already in use, using existing server`);
- // Server is already running, we'll use the existing one
- this.isInitialized = true;
- } else {
- console.error('Failed to start WebSocket server:', error);
- throw error;
- }
- }
- }
- private setupWebSocketHandlers(): void {
- if (!this.wss) return;
- this.wss.on('connection', (ws: WebSocket) => {
- console.log('New WebSocket connection established');
- this.clients.add(ws);
- ws.on('close', () => {
- console.log('WebSocket connection closed');
- this.clients.delete(ws);
- });
- ws.on('error', (error) => {
- console.error('WebSocket error:', error);
- this.clients.delete(ws);
- });
- });
- }
- // Alternative method to attach to existing HTTP server
- attachToServer(server: Server): void {
- if (this.wss) {
- this.wss.close();
- }
- this.wss = new WebSocketServer({
- server,
- path: '/api/imports/progress'
- });
- this.wss.on('connection', (ws: WebSocket, request) => {
- console.log('New WebSocket connection on import progress endpoint');
- this.clients.add(ws);
- const url = new URL(request.url || '', `http://${request.headers.host}`);
- const importId = url.searchParams.get('importId');
-
- if (importId) {
- ws.send(JSON.stringify({
- type: 'connected',
- importId: parseInt(importId),
- message: 'Connected to import progress updates'
- }));
- }
- ws.on('close', () => {
- console.log('WebSocket connection closed');
- this.clients.delete(ws);
- });
- ws.on('error', (error) => {
- console.error('WebSocket error:', error);
- this.clients.delete(ws);
- });
- });
- }
- broadcastProgress(importId: number, progress: ImportProgress): void {
- const message = JSON.stringify({
- type: 'progress',
- importId,
- progress
- });
- this.clients.forEach(client => {
- if (client.readyState === WebSocket.OPEN) {
- client.send(message);
- }
- });
- }
- broadcastError(importId: number, error: string): void {
- const message = JSON.stringify({
- type: 'error',
- importId,
- error
- });
- this.clients.forEach(client => {
- if (client.readyState === WebSocket.OPEN) {
- client.send(message);
- }
- });
- }
- broadcastComplete(importId: number, result: any): void {
- const message = JSON.stringify({
- type: 'complete',
- importId,
- result
- });
- this.clients.forEach(client => {
- if (client.readyState === WebSocket.OPEN) {
- client.send(message);
- }
- });
- }
- close(): void {
- if (this.wss) {
- this.wss.close();
- this.clients.clear();
- this.isInitialized = false;
- }
- }
- isServerInitialized(): boolean {
- return this.isInitialized;
- }
- }
- // Export a singleton instance
- export const progressServer = ImportProgressServer.getInstance();
|