import fs from "fs"; import path from "path"; import { QueueManager } from './queue_manager'; import { TcpCommunicator } from "./tcp_communicator"; import { operationCodes } from '../network/operation_codes'; import { compareFnFileItemTask, FileItemTask } from "../interfaces/file_item_task"; import { ParsedMessage } from "../network/message_handler"; interface FileSendTask { ip: string; path: string; userName: string; } export class FileSharer { private queueManager: QueueManager; private readonly clientPort: number; private isBusy: boolean; private tcpCommunicator: TcpCommunicator | null = null; private stopRequested: boolean = false; private intervalId: NodeJS.Timeout | null = null; constructor(queueFilePath: string, clientPort: number) { this.queueManager = new QueueManager(queueFilePath, compareFnFileItemTask); this.clientPort = clientPort; this.isBusy = false; // Initialize the busy flag } // Start processing the file queue async start(): Promise { this.intervalId = setInterval(async () => { if (!this.isBusy || !this.stopRequested) { // Check if the queue is already being processed this.isBusy = true; // Set busy flag to true before starting this.log("Start successfully. Processing the queue."); await this.processQueue(); } if (global.gc) { global.gc(); } }, 10000); // 10 seconds interval } // Method to process the queue private async processQueue(): Promise { while (!this.queueManager.isEmpty()) { const task = this.queueManager.peek(); this.log('trimiti fisier'); if (task) { this.log(`Processing task for file: ${task.path} to IP: ${task.ip}`); const success = await this.sendFile(task); if (!success) { this.log(`Failed to send file: ${task.path} to IP: ${task.ip}. Re-adding to queue.`, 'error'); this.queueManager.dequeue(); this.queueManager.enqueue(task); // Re-add to queue if failed } else { this.log(`File sent successfully: ${task.path} to IP: ${task.ip}`); this.queueManager.dequeue(); } } } this.isBusy = false; // Reset busy flag after the queue is processed } // Method to send the file to a specific IP using TcpCommunicator private async sendFile(task: FileSendTask): Promise { const { ip, path: filePath, userName } = task; // Ensure the file exists before attempting to send if (!fs.existsSync(filePath)) { this.log(`File not found: ${filePath}`, 'error'); return false; } // Read the file contents const fileContent = fs.readFileSync(filePath); // Extract the file name from the file path using path.basename const fileName = path.basename(filePath); const metaInfo = { userName, // Sender's username relativeFilePath: fileName, // Use the file name instead of the full path }; this.tcpCommunicator = new TcpCommunicator(ip, this.clientPort); if (!await this.tcpCommunicator.connect()) { this.log(`Failed to connect to IP: ${ip}`, 'error'); return false; } this.log(`Sending file: ${filePath} to IP: ${ip}`); if (!await this.tcpCommunicator.sendMessage(operationCodes.SHARE_FILE, metaInfo, fileContent)) return false; const response = await this.waitForResponse(); if (!response || response.operationCode !== operationCodes.OK) { this.log(`Failed to send file: ${filePath} to IP: ${ip}`, 'error'); return false; } await this.tcpCommunicator.disconnect(); return true; } async stop(): Promise { this.stopRequested = true; // Signal that stop is requested if (this.intervalId) { clearInterval(this.intervalId); this.intervalId = null; } // Wait for any ongoing process to complete if busy while (this.isBusy) { await new Promise((resolve) => setTimeout(resolve, 100)); } console.log("[BackupManager] Stopped successfully."); } private async waitForResponse(): Promise { return new Promise((resolve) => { const idResponseCheck = setInterval(async () => { if (!this.tcpCommunicator) return null; if (this.tcpCommunicator.hasResponseArrived()) { clearInterval(idResponseCheck); resolve(this.tcpCommunicator.getLastResult()); // Resolve the response or null if not available } }, 100); // Check every 100 milliseconds if the response has arrived }); } // Unified logging function private log(message: string, level: 'log' | 'error' = 'log'): void { const prefix = '[FileSharer]'; if (level === 'error') { console.error(`${prefix} ${message}`); } else { console.log(`${prefix} ${message}`); } } }