From 5ea32b2a3a8d9bbc38b51a7ed3c1b03054c74aeb Mon Sep 17 00:00:00 2001 From: andrei-mihnea-cerbu Date: Tue, 12 Nov 2024 14:00:30 +0200 Subject: [PATCH] overall v1 --- CEO/src/helpers/announcement_sender.ts | 84 -------- CEO/src/helpers/backup_manager.ts | 68 +++++-- CEO/src/helpers/backup_retrieval.ts | 27 ++- CEO/src/helpers/department_sharer.ts | 55 +++--- CEO/src/helpers/directory_watcher.ts | 58 ++++-- CEO/src/helpers/file_sharer.ts | 40 ++-- CEO/src/helpers/network_scanner.ts | 186 ++++++++++++++++++ CEO/src/helpers/users_info_fetcher.ts | 18 +- CEO/src/helpers/window_manager.ts | 43 ++++ CEO/src/helpers/worker_manager.ts | 43 +--- CEO/src/network/operation_codes.ts | 1 - .../user_to_user_operations.ts | 161 ++++++++++++++- .../tcp_client_communicator.ts | 118 ++++++----- .../tcp_server_communicator.ts | 93 ++++++--- CEO/src/network/tcp/tcp_client.ts | 10 +- CEO/src/network/tcp/tcp_server.ts | 15 +- CEO/src/network/udp/udp_server.ts | 4 +- CEO/src/workers/directories_watcher_worker.ts | 36 +--- CEO/src/workers/network_scanner_worker.ts | 89 +-------- .../workers/resource_coordinator_worker.ts | 40 +--- CEO/src/workers/send_announcement_worker.ts | 19 -- User/src/helpers/backup_manager.ts | 68 +++++-- User/src/helpers/backup_retrieval.ts | 27 ++- User/src/helpers/department_sharer.ts | 55 +++--- User/src/helpers/directory_watcher.ts | 58 ++++-- User/src/helpers/file_sharer.ts | 40 ++-- User/src/helpers/network_scanner.ts | 186 ++++++++++++++++++ User/src/helpers/users_info_fetcher.ts | 18 +- User/src/helpers/worker_manager.ts | 9 +- User/src/main/main.ts | 6 + User/src/main/preload.ts | 1 + .../src/workers/directories_watcher_worker.ts | 36 +--- User/src/workers/network_scanner_worker.ts | 160 +-------------- .../workers/resource_coordinator_worker.ts | 40 +--- 34 files changed, 1131 insertions(+), 781 deletions(-) delete mode 100644 CEO/src/helpers/announcement_sender.ts create mode 100644 CEO/src/helpers/network_scanner.ts delete mode 100644 CEO/src/workers/send_announcement_worker.ts create mode 100644 User/src/helpers/network_scanner.ts diff --git a/CEO/src/helpers/announcement_sender.ts b/CEO/src/helpers/announcement_sender.ts deleted file mode 100644 index c1f1fd5..0000000 --- a/CEO/src/helpers/announcement_sender.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { JsonManager } from './json_manager'; // Assuming this manages JSON configurations -import { TcpCommunicator } from "./tcp_communicator"; -import { operationCodes } from '../network/operation_codes'; // Assuming this holds operation codes -import { parentPort } from 'worker_threads'; -import {ParsedMessage} from "../network/message_handler"; - -export class AnnouncementSender { - private applicationInfo: JsonManager; - private readonly clientPort: number; - private message: string = ''; - private tcpCommunicator: TcpCommunicator | null = null; - - constructor(applicationInfoPath: string, clientPort: number) { - this.applicationInfo = new JsonManager(applicationInfoPath); - this.clientPort = clientPort; - } - - async start(message: string): Promise { - console.log('AnnouncementWorker started.'); - this.message = message; - try { - const activeUsersIp = await this.applicationInfo.readValue('users_ip'); - if (!activeUsersIp || !activeUsersIp.length) { - throw new Error('No active users found.'); - } - - for (const ip of activeUsersIp) { - const success = await this.sendAnnouncementToIp(ip); - if (!success) { - throw new Error(`Failed to send announcement to all users.`); - } - console.log(`Announcement sent and confirmed successfully from ${ip}`); - } - - parentPort?.postMessage({ success: true, message: 'Announcement sent to all active users successfully.' }); - } catch (error: any) { - console.error('Error in AnnouncementWorker:', error); - parentPort?.postMessage({ success: false, message: `A problem occurred: ${error.message}` }); - } - - console.log('AnnouncementWorker finished.'); - } - - private async sendAnnouncementToIp(ip: string): Promise { - this.tcpCommunicator = new TcpCommunicator(ip, this.clientPort); - if (!await this.tcpCommunicator.connect()) { - console.log(`Skipping user at IP ${ip} - unable to connect.`); - return true; - } - - // Prepare the message metadata - const metaInfo = { message: this.message }; - - // Send the announcement message - const messageSent = await this.tcpCommunicator.sendMessage(operationCodes.SEND_ANNOUNCEMENT, metaInfo); - if (!messageSent) { - await this.tcpCommunicator.disconnect(); - return false; - } - - // Await confirmation from the user - const response = await this.waitForResponse(); - if (response?.operationCode === operationCodes.OK) { - await this.tcpCommunicator.disconnect(); - return true; - } - - // If confirmation is not OK, disconnect and halt - await this.tcpCommunicator.disconnect(); - return false; - } - - 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()); - } - }, 100); - }); - } -} diff --git a/CEO/src/helpers/backup_manager.ts b/CEO/src/helpers/backup_manager.ts index 928f460..d868180 100644 --- a/CEO/src/helpers/backup_manager.ts +++ b/CEO/src/helpers/backup_manager.ts @@ -1,7 +1,6 @@ -import { JsonManager } from './json_manager'; // Assuming this manages JSON configurations +import { JsonManager } from './json_manager'; import { TcpCommunicator } from "./tcp_communicator"; -import { operationCodes } from '../network/operation_codes'; // Assuming this holds operation codes -import { parentPort } from 'worker_threads'; +import { operationCodes } from '../network/operation_codes'; import path from 'path'; import fs from 'fs'; import crypto from 'crypto'; @@ -15,15 +14,30 @@ export class BackupRetrievalWorker { private encryptionKey: Buffer | null = null; private iv: Buffer | null = null; private tcpCommunicator: TcpCommunicator | null = null; + private isBusy: boolean; + private lastProcessedUserIndex: number; constructor(userConfigPath: string, applicationInfoPath: string, clientPort: number, destinationPath: string) { this.userConfig = new JsonManager(userConfigPath); this.applicationInfo = new JsonManager(applicationInfoPath); this.clientPort = clientPort; this.destinationPath = destinationPath; + this.isBusy = false; + this.lastProcessedUserIndex = 0; } async start(): Promise { + setInterval(async () => { + if (!this.isBusy) { + this.log('Start successfully. Processing backup tasks.'); + await this.processBackupTasks(); + } + }, 10000); // Retry every 10 seconds if there's an error + } + + private async processBackupTasks(): Promise { + this.isBusy = true; + try { const userInfo = await this.userConfig.readValue('user_info'); if (!userInfo || !userInfo.name) { @@ -41,46 +55,50 @@ export class BackupRetrievalWorker { const activeUsersIp = await this.applicationInfo.readValue('users_ip'); if (!activeUsersIp || !activeUsersIp.length) { - parentPort?.postMessage({ success: false, message: 'No active users found.' }); - return; + this.isBusy = false; + throw new Error('No active users found.'); } + // Process each user, starting from the last processed index let backupSuccessful = true; - for (const ip of activeUsersIp) { + for (let i = this.lastProcessedUserIndex; i < activeUsersIp.length; i++) { + const ip = activeUsersIp[i]; const success = await this.processBackupForIp(ip, userName); if (!success) { backupSuccessful = false; - parentPort?.postMessage({ success: false, message: 'Backup could not be completed due to an internal error.' }); + this.lastProcessedUserIndex = i; // Remember where it stopped break; } } if (backupSuccessful) { - parentPort?.postMessage({ success: true, message: 'Backup successful.' }); + this.log('Backup retrieval completed successfully for all users.'); + this.lastProcessedUserIndex = 0; // Reset index to start from the beginning next cycle } } catch (error: any) { - console.error('Error in BackupRetrievalWorker:', error); - parentPort?.postMessage({ success: false, message: `Backup could not be completed due to an internal error: ${error.message}` }); + this.log(error.message, 'error'); } + + this.isBusy = false; } private async processBackupForIp(ip: string, userName: string): Promise { this.tcpCommunicator = new TcpCommunicator(ip, this.clientPort); if (!await this.tcpCommunicator.connect()) { - console.error(`Failed to connect to ${ip}`); + this.log(`Failed to connect to ${ip}`, 'error'); return false; } const backupExists = await this.checkIfBackupExists(userName); if (!backupExists) { - console.log(`No backup found for user ${userName} on IP ${ip}`); + this.log(`No backup found for user ${userName} on IP ${ip}`); await this.tcpCommunicator.disconnect(); return true; // Skip user if no backup found, do not mark as error } const backupStructure = await this.requestBackupStructure(userName); if (!backupStructure || Object.keys(backupStructure).length === 0) { - console.log(`No files found in backup structure for user ${userName} on IP ${ip}`); + this.log(`No files found in backup structure for user ${userName} on IP ${ip}`); await this.tcpCommunicator.disconnect(); return true; // Skip user if no files found, do not mark as error } @@ -88,7 +106,7 @@ export class BackupRetrievalWorker { for (const relativeFilePath of Object.keys(backupStructure)) { const fileRequestSuccess = await this.requestBackupFile(userName, relativeFilePath); if (!fileRequestSuccess) { - console.error(`Failed to retrieve file ${relativeFilePath} from backup for user ${userName} on IP ${ip}`); + this.log(`Failed to retrieve file ${relativeFilePath} from backup for user ${userName} on IP ${ip}`, 'error'); await this.tcpCommunicator.disconnect(); return false; // Stop if any file fails to be retrieved } @@ -133,7 +151,7 @@ export class BackupRetrievalWorker { private saveFile(relativeFilePath: string, fileContent: string): boolean { if (!this.encryptionKey || !this.iv) { - console.error('Encryption key or IV is not set.'); + this.log('Encryption key or IV is not set.', 'error'); return false; } @@ -141,7 +159,7 @@ export class BackupRetrievalWorker { try { encryptedBuffer = Buffer.from(fileContent, 'base64'); } catch (error) { - console.error('Error decoding base64 file content:', error); + this.log(`Error decoding base64 file content: ${error}`, 'error'); return false; } @@ -150,7 +168,7 @@ export class BackupRetrievalWorker { const decipher = crypto.createDecipheriv('aes-256-cbc', this.encryptionKey, this.iv); decryptedContent = Buffer.concat([decipher.update(encryptedBuffer), decipher.final()]); } catch (error) { - console.error('Error decrypting file:', error); + this.log(`Error decrypting file: ${error}`, 'error'); return false; } @@ -161,10 +179,10 @@ export class BackupRetrievalWorker { fs.mkdirSync(dirPath, { recursive: true }); } fs.writeFileSync(fullFilePath, decryptedContent); - console.log(`File saved successfully: ${fullFilePath}`); + this.log(`File saved successfully: ${fullFilePath}`); return true; } catch (error: any) { - console.error(`Error saving file ${relativeFilePath}: ${error.message}`); + this.log(`Error saving file ${relativeFilePath}: ${error.message}`, 'error'); return false; } } @@ -177,7 +195,17 @@ export class BackupRetrievalWorker { clearInterval(idResponseCheck); resolve(this.tcpCommunicator.getLastResult()); } - }, 100); + }, 100); // Check every 100 milliseconds }); } + + // Unified logging function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const prefix = '[BackupRetrievalWorker]'; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } } diff --git a/CEO/src/helpers/backup_retrieval.ts b/CEO/src/helpers/backup_retrieval.ts index c661e26..47bfd07 100644 --- a/CEO/src/helpers/backup_retrieval.ts +++ b/CEO/src/helpers/backup_retrieval.ts @@ -1,11 +1,11 @@ -import { JsonManager } from './json_manager'; // Assuming this manages JSON configurations +import { JsonManager } from './json_manager'; import { TcpCommunicator } from "./tcp_communicator"; -import { operationCodes } from '../network/operation_codes'; // Assuming this holds operation codes +import { operationCodes } from '../network/operation_codes'; import { parentPort } from 'worker_threads'; import path from 'path'; import fs from 'fs'; import crypto from 'crypto'; -import { ParsedMessage } from "../network/message_handler"; // Import the crypto module for encryption and decryption +import { ParsedMessage } from "../network/message_handler"; export class BackupRetrievalWorker { private userConfig: JsonManager; @@ -23,6 +23,16 @@ export class BackupRetrievalWorker { this.destinationPath = destinationPath; } + // Logging helper function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const prefix = '[BackupRetrievalWorker]'; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } + async start(): Promise { try { const userInfo = await this.userConfig.readValue('user_info'); @@ -49,12 +59,12 @@ export class BackupRetrievalWorker { if (!success) { throw new Error(`Failed to retrieve backup from ${ip}`); } - console.log(`Backup retrieved successfully from ${ip}`); + this.log(`Backup retrieved successfully from ${ip}`); } parentPort?.postMessage({ success: true, message: 'Backup retrieval completed successfully.' }); } catch (error: any) { - console.error('Error in BackupRetrievalWorker:', error); + this.log(`Error in BackupRetrievalWorker: ${error.message}`, 'error'); parentPort?.postMessage({ success: false, message: `A problem occurred: ${error.message}` }); } } @@ -62,19 +72,20 @@ export class BackupRetrievalWorker { private async processBackupForIp(ip: string, userName: string): Promise { this.tcpCommunicator = new TcpCommunicator(ip, this.clientPort); if (!await this.tcpCommunicator.connect()) { + this.log(`Failed to connect to ${ip}`, 'error'); return true; } const backupExists = await this.checkIfBackupExists(userName); if (!backupExists) { - console.log(`No backup found for user ${userName} on IP ${ip}`); + this.log(`No backup found for user ${userName} on IP ${ip}`); await this.tcpCommunicator.disconnect(); return true; } const backupStructure = await this.requestBackupStructure(userName); if (!backupStructure || Object.keys(backupStructure).length === 0) { - console.log(`No files found in backup structure for user ${userName} on IP ${ip}`); + this.log(`No files found in backup structure for user ${userName} on IP ${ip}`); await this.tcpCommunicator.disconnect(); return true; } @@ -151,7 +162,7 @@ export class BackupRetrievalWorker { fs.mkdirSync(dirPath, { recursive: true }); } fs.writeFileSync(fullFilePath, decryptedContent); - console.log(`File saved successfully: ${fullFilePath}`); + this.log(`File saved successfully: ${fullFilePath}`); return true; } catch (error: any) { throw new Error(`Error saving file ${relativeFilePath}: ${error.message}`); diff --git a/CEO/src/helpers/department_sharer.ts b/CEO/src/helpers/department_sharer.ts index 7c11662..47bad9e 100644 --- a/CEO/src/helpers/department_sharer.ts +++ b/CEO/src/helpers/department_sharer.ts @@ -1,19 +1,19 @@ import fs from 'fs'; import path from 'path'; -import { TcpCommunicator } from './tcp_communicator'; // Using TcpCommunicator instead of TcpClient +import { TcpCommunicator } from './tcp_communicator'; import { operationCodes } from '../network/operation_codes'; -import { JsonManager } from './json_manager'; // Manages JSON configurations -import { MemoryManager } from './memory_manager'; // Manages in-memory data structures +import { JsonManager } from './json_manager'; +import { MemoryManager } from './memory_manager'; import { ParsedMessage } from "../network/message_handler"; export class DepartmentSharer { private userConfig: JsonManager; private applicationInfo: JsonManager; - private memoryManager: MemoryManager; // To read the department files + private memoryManager: MemoryManager; private departmentDirectory: string | null; private readonly clientPort: number; - private isBusy: boolean = false; // Busy flag to prevent simultaneous sharing - private tcpCommunicator: TcpCommunicator | null = null; // For each user connection + private isBusy: boolean = false; + private tcpCommunicator: TcpCommunicator | null = null; constructor( userConfigPath: string, @@ -32,21 +32,20 @@ export class DepartmentSharer { async start(): Promise { setInterval(async () => { if (!this.isBusy) { - this.isBusy = true; + this.log('Start successfully. Sharing files with the department.'); await this.shareFilesWithDepartment(); - this.isBusy = false; } }, 10000); // 10-second interval for testing } // Share files with users in the same department private async shareFilesWithDepartment(): Promise { - console.log('\n\nStarting Department Share Process\n\n'); + this.isBusy = true; // Get the current user's department information const userInfo = await this.userConfig.readValue('user_info'); if (!userInfo || !userInfo.departmentId || !userInfo.name) { - console.error('User information or department ID is missing in the configuration.'); + this.log('User information or department ID is missing in the configuration.', 'error'); return; } @@ -56,27 +55,27 @@ export class DepartmentSharer { // Get the list of active users from applicationInfo const activeUsersId = await this.applicationInfo.readValue('active_users_info'); if (!activeUsersId) { - console.error('No active users found.'); + this.log('No active users found.', 'error'); return; } const activeUsers = await this.memoryManager.retrieveMetaInformation(activeUsersId); if (!activeUsers || activeUsers.length === 0) { - console.error('No active users found.'); + this.log('No active users found.', 'error'); return; } // Filter users who belong to the same department const departmentUsers = activeUsers.filter((user: any) => user.user_info.departmentId === departmentId); if (departmentUsers.length === 0) { - console.log('No users found in the same department.'); + this.log('No users found in the same department.', 'log'); return; } // Get department directory info const departmentData = await this.applicationInfo.readValue('departmentDirectory'); if (!departmentData || !departmentData.path || !departmentData.id) { - console.error('No department directory found.'); + this.log('No department directory found.', 'error'); return; } @@ -85,7 +84,7 @@ export class DepartmentSharer { // Read files from the MemoryManager related to this department const departmentFiles = await this.memoryManager.retrieveMetaInformation(departmentData.id); if (!departmentFiles || !departmentFiles.structure) { - console.error('No files found for this department in the memory manager.'); + this.log('No files found for this department in the memory manager.', 'error'); return; } @@ -114,7 +113,7 @@ export class DepartmentSharer { const response = await this.waitForResponse(); if (!response || response.operationCode !== operationCodes.OK){ - console.error('Failed to clear the department directory.'); + this.log('Failed to clear the department directory.', 'error'); return false; } @@ -124,14 +123,14 @@ export class DepartmentSharer { // Send the files to a user in the department private async sendFilesToUser(files: { [key: string]: string }, userName: string): Promise { if(!this.tcpCommunicator) return; - const unsentFiles = Object.keys(files); // Keep track of unsent files + const unsentFiles = Object.keys(files); for (const fileName of unsentFiles) { const filePath = files[fileName]; // Ensure the file exists before attempting to send if (!fs.existsSync(filePath)) { - console.error(`File not found: ${filePath}`); + this.log(`File not found: ${filePath}`, 'error'); continue; } @@ -144,8 +143,8 @@ export class DepartmentSharer { // Prepare the metaInfo (same structure as FileSharer) const metaInfo = { - userName, // Sender's username - relativeFilePath // Use the relative path to preserve directory structure + userName, + relativeFilePath }; // Send the file @@ -153,7 +152,7 @@ export class DepartmentSharer { const response = await this.waitForResponse(); if (!response || response.operationCode !== operationCodes.OK) { - console.error(`Failed to send file: ${fileName}`); + this.log(`Failed to send file: ${fileName}`, 'error'); return; } @@ -168,9 +167,19 @@ export class DepartmentSharer { if (!this.tcpCommunicator) return null; if (this.tcpCommunicator.hasResponseArrived()) { clearInterval(idResponseCheck); - resolve(this.tcpCommunicator.getLastResult()); // Resolve the response or null if not available + resolve(this.tcpCommunicator.getLastResult()); } - }, 100); // Check every 100 milliseconds if the response has arrived + }, 100); }); } + + // Unified logging function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const prefix = '[DepartmentSharer]'; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } } diff --git a/CEO/src/helpers/directory_watcher.ts b/CEO/src/helpers/directory_watcher.ts index b4404b9..a96beaf 100644 --- a/CEO/src/helpers/directory_watcher.ts +++ b/CEO/src/helpers/directory_watcher.ts @@ -10,8 +10,9 @@ export class DirectoryWatcher { private applicationInfo: JsonManager; private memoryManager: MemoryManager; private readonly sourceKey: string; - private directoryWatcher: FSWatcher | null; // To store the watcher reference - private totalSize: number; // To store total directory size + private directoryWatcher: FSWatcher | null; + private totalSize: number; + private isBusy: boolean; constructor(memoryManagerPath: string, applicationInfoPath: string, sourceKey: string) { this.sourceKey = sourceKey; @@ -19,14 +20,28 @@ export class DirectoryWatcher { this.memoryManager = new MemoryManager(memoryManagerPath); this.directoryMemoryId = ''; this.directoryPath = ''; - this.directoryWatcher = null; // Initialize with no watcher - this.totalSize = 0; // Initialize size with zero + this.directoryWatcher = null; + this.totalSize = 0; + this.isBusy = false; + } + + // Start the watcher with a busy flag to prevent overlapping operations + async start(): Promise { + setInterval(async () => { + if (!this.isBusy) { + this.isBusy = true; + const initialized = await this.initialize(); + if (initialized) this.log('Directory watcher started successfully.'); + this.isBusy = false; + } + }, 10000); // 10-second interval for testing } // Method to initialize and validate the backup directory async initialize(): Promise { const directoryData = await this.applicationInfo.readValue(this.sourceKey); if (!directoryData) { + this.log('Directory data not found in application info.', 'error'); return false; } @@ -34,7 +49,7 @@ export class DirectoryWatcher { this.directoryMemoryId = directoryData.id; if (!this.directoryMemoryId || !this.directoryPath) { - console.error('Components of entry in \'DirectoryWatcher\' not found.'); + this.log('Components of entry in \'DirectoryWatcher\' not found.', 'error'); await this.applicationInfo.removeValue(this.sourceKey); return false; } @@ -65,7 +80,7 @@ export class DirectoryWatcher { for (const item of items) { const fullPath = path.join(dirPath, item.name); - const stats = await fs.stat(fullPath); // Get stats for each item + const stats = await fs.stat(fullPath); if (item.isDirectory()) { // If it's a directory, recursively build its structure and accumulate size @@ -75,7 +90,7 @@ export class DirectoryWatcher { } else if (item.isFile()) { // If it's a file, store its full path and accumulate size directoryScheme[item.name] = fullPath; - totalSize += stats.size; // Add file size + totalSize += stats.size; } } @@ -85,8 +100,8 @@ export class DirectoryWatcher { // Restart the directory watcher, ensuring any previous watcher is closed private restartWatcher(): void { if (this.directoryWatcher) { - console.log('Stopping existing watcher...'); - this.directoryWatcher.close(); // Stop the existing watcher + this.log('Stopping existing watcher...'); + this.directoryWatcher.close(); } this.startDirectoryWatcher(); @@ -100,7 +115,7 @@ export class DirectoryWatcher { this.directoryWatcher = watch(this.directoryPath, { recursive: true }, async (eventType, filename) => { if (filename) { - console.log(`File change detected: ${eventType} - ${filename}`); + this.log(`File change detected: ${eventType} - ${filename}`); // Rebuild the directory scheme and update memory const result = await this.buildDirectoryScheme(this.directoryPath); this.directoryScheme = result.structure; @@ -111,19 +126,34 @@ export class DirectoryWatcher { totalSize: this.totalSize, }); - console.log('Directory structure and size updated in memory.'); + this.log('Directory structure and size updated in memory.'); } }); - console.log(`Watching for changes in: ${this.directoryPath}`); + this.log(`Watching for changes in: ${this.directoryPath}`); } // Close the directory watcher public closeWatcher(): void { if (this.directoryWatcher) { - console.log(`Stopping watcher for ${this.directoryPath}`); + this.log(`Stopping watcher for ${this.directoryPath}`); this.directoryWatcher.close(); - this.directoryWatcher = null; // Clear the reference after closing + this.directoryWatcher = null; } } + + // Unified logging function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const sourcePrefix = `[DirectoryWatcher] {${this.capitalize(this.sourceKey)}}`; + if (level === 'error') { + console.error(`${sourcePrefix} ${message}`); + } else { + console.log(`${sourcePrefix} ${message}`); + } + } + + // Capitalize the first letter of the sourceKey + private capitalize(str: string): string { + return str.charAt(0).toUpperCase() + str.slice(1); + } } diff --git a/CEO/src/helpers/file_sharer.ts b/CEO/src/helpers/file_sharer.ts index 435e021..68e254d 100644 --- a/CEO/src/helpers/file_sharer.ts +++ b/CEO/src/helpers/file_sharer.ts @@ -1,10 +1,10 @@ -import {QueueManager} from './queue_manager'; -import {TcpCommunicator} from "./tcp_communicator"; // Updated to use TcpCommunicator -import {operationCodes} from '../network/operation_codes'; import fs from "fs"; import path from "path"; -import {compareFnFileItemTask, FileItemTask} from "../interfaces/file_item_task"; -import {ParsedMessage} from "../network/message_handler"; +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; @@ -28,7 +28,9 @@ export class FileSharer { async start(): Promise { setInterval(async () => { if (!this.isBusy) { // Check if the queue is already being processed + this.log("Start successfully. Processing the queue."); await this.processQueue(); // Process the queue at regular intervals + this.log("Queue processing completed."); } }, 10000); // 10 seconds interval } @@ -36,7 +38,7 @@ export class FileSharer { // Method to process the queue private async processQueue(): Promise { if (this.isBusy) { - console.log("Queue is already being processed. Skipping this interval."); + this.log("Queue is already being processed. Skipping this interval."); return; } @@ -46,15 +48,15 @@ export class FileSharer { const task = this.queueManager.peek(); if (task) { - console.log(task); + this.log(`Processing task for file: ${task.path} to IP: ${task.ip}`); const success = await this.sendFile(task); if (!success) { - console.error(`Failed to send file: ${task.path} to IP: ${task.ip}. Re-adding to queue.`); + 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 { - console.log(`File sent successfully: ${task.path} to IP: ${task.ip}.`); + this.log(`File sent successfully: ${task.path} to IP: ${task.ip}`); this.queueManager.dequeue(); } } @@ -64,11 +66,11 @@ export class FileSharer { // Method to send the file to a specific IP using TcpCommunicator private async sendFile(task: FileSendTask): Promise { - const {ip, path: filePath, userName} = task; + const { ip, path: filePath, userName } = task; // Ensure the file exists before attempting to send if (!fs.existsSync(filePath)) { - console.error(`File not found: ${filePath}`); + this.log(`File not found: ${filePath}`, 'error'); return false; } @@ -86,17 +88,17 @@ export class FileSharer { this.tcpCommunicator = new TcpCommunicator(ip, this.clientPort); if (!await this.tcpCommunicator.connect()) { - console.error(`Failed to connect to IP: ${ip}`); + this.log(`Failed to connect to IP: ${ip}`, 'error'); return false; } - console.log(`Sending file: ${filePath} to IP: ${ip}`); + 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) { - console.error(`Failed to send file: ${filePath} to IP: ${ip}`); + this.log(`Failed to send file: ${filePath} to IP: ${ip}`, 'error'); return false; } @@ -115,4 +117,14 @@ export class FileSharer { }, 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}`); + } + } } diff --git a/CEO/src/helpers/network_scanner.ts b/CEO/src/helpers/network_scanner.ts new file mode 100644 index 0000000..238ef3c --- /dev/null +++ b/CEO/src/helpers/network_scanner.ts @@ -0,0 +1,186 @@ +import {JsonManager} from "./json_manager"; +import {UdpClient} from "../network/udp/udp_client"; +import {parentPort} from "worker_threads"; +import {TcpCommunicator} from "./tcp_communicator"; +import {operationCodes} from "../network/operation_codes"; +import {ParsedMessage} from "../network/message_handler"; + +export class NetworkScanner { + private applicationInfo: JsonManager; + private userConfig: JsonManager; + private readonly udpPort: number; + private readonly tcpPort: number; + private readonly okPage: string; + private readonly errorPage: string; + private readonly databaseResetPage: string; + private appStarted = false; + private intervalIds: NodeJS.Timeout[] = []; + + // Flags to prevent overlapping executions + private ucCheckBusy = false; + private ipLookupBusy = false; + private sendLoginBusy = false; + + constructor(applicationInfoPath: string, userConfigPath: string, udpPort: number, tcpPort: number, okPage: string, errorPage: string, databaseResetPage: string) { + this.applicationInfo = new JsonManager(applicationInfoPath); + this.userConfig = new JsonManager(userConfigPath); + this.udpPort = udpPort; + this.tcpPort = tcpPort; + this.okPage = okPage; + this.errorPage = errorPage; + this.databaseResetPage = databaseResetPage; + + // Start tasks + this.startUCCheck(); + this.startUserIPLookup(); + this.sendLoginRequest(); + } + + // Log helper function for consistent logging format + private log(message: string, level: 'log' | 'error' = 'log', methodName: string = ''): void { + const prefix = `[NetworkScanner${methodName ? `.${methodName}` : ''}]`; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } + + // UC Check Task + private startUCCheck(interval: number = 5000): void { + const intervalId = setInterval(async () => { + if (this.ucCheckBusy) return; + this.ucCheckBusy = true; + + try { + this.log('UC Check running...', 'log', 'startUCCheck'); + const udpClient = new UdpClient(this.udpPort); + const aliveClients = await udpClient.getAliveClients(); + const storedIp = await this.applicationInfo.readValue('serverIp'); + const foundClient = aliveClients.length > 0; + + if (foundClient) { + const ipAddress = aliveClients[0]; // Use the first alive client + + if (!storedIp || storedIp !== ipAddress) { + await this.applicationInfo.writeValue('serverIp', ipAddress); + if (!this.appStarted) { + parentPort?.postMessage({ type: 'changeContent', page: this.okPage }); + } + this.appStarted = true; + } else if (!this.appStarted) { + parentPort?.postMessage({ type: 'changeContent', page: this.okPage }); + this.appStarted = true; + } + } else { + parentPort?.postMessage({ type: 'changeContent', page: this.errorPage }); + } + } catch (err) { + this.log(`Error checking UC: ${err}`, 'error', 'startUCCheck'); + parentPort?.postMessage({ type: 'changeContent', page: this.errorPage }); + } finally { + this.ucCheckBusy = false; + } + }, interval); + + this.intervalIds.push(intervalId); + } + + // IP Lookup Task + private startUserIPLookup(interval: number = 10000): void { + const intervalId = setInterval(async () => { + if (this.ipLookupBusy) return; + this.ipLookupBusy = true; + + try { + this.log('IP Lookup running...', 'log', 'startUserIPLookup'); + const serverIp = await this.applicationInfo.readValue('serverIp'); + const udpClient = new UdpClient(this.udpPort); + const activeIPs = await udpClient.getAliveClients(); + const filteredIPs = activeIPs.filter(ip => ip !== serverIp); + + // Save the filtered IPs to 'users_ip' + await this.applicationInfo.writeValue('users_ip', filteredIPs); + } catch (err) { + this.log(`Error during user IP lookup: ${err}`, 'error', 'startUserIPLookup'); + } finally { + this.ipLookupBusy = false; + } + }, interval); + + this.intervalIds.push(intervalId); + } + + // Login Request Task + private sendLoginRequest(interval: number = 5000): void { + const intervalId = setInterval(async () => { + if (this.sendLoginBusy || this.appStarted) return; + this.sendLoginBusy = true; + + try { + const userInfo = await this.userConfig.readValue('user_info'); + if (!userInfo || !userInfo.email || !userInfo.password) { + this.log("Email or password not found in user config.", 'error', 'sendLoginRequest'); + return; + } + + const app_type = await this.userConfig.readValue('app_type'); + const email = userInfo.email; + const password = userInfo.password; + const serverIp = await this.applicationInfo.readValue('serverIp'); + + if (!serverIp) { + this.log("Server IP not found in application info.", 'error', 'sendLoginRequest'); + return; + } + + const tcpCommunicator = new TcpCommunicator(serverIp, this.tcpPort); + + if (!await tcpCommunicator.connect()) { + this.log("Failed to connect to the server.", 'error', 'sendLoginRequest'); + return; + } + + const metaInfo = { email, password, app_type }; + if (!await tcpCommunicator.sendMessage(operationCodes.LOGIN, metaInfo)) { + this.log("Failed to send login request.", 'error', 'sendLoginRequest'); + await tcpCommunicator.disconnect(); + return; + } + + const response = await this.waitForResponse(tcpCommunicator); + if (response?.operationCode !== operationCodes.OK) { + await this.userConfig.resetFile(); + await this.userConfig.writeValue('app_type', app_type); + parentPort?.postMessage({ type: 'changeContent', page: this.databaseResetPage }); + } + } catch (err) { + this.log(`Error during login request: ${err}`, 'error', 'sendLoginRequest'); + } finally { + this.sendLoginBusy = false; + } + }, interval); + + this.intervalIds.push(intervalId); + } + + // Helper function to wait for a response from the TCP communicator + private async waitForResponse(tcpCommunicator: TcpCommunicator): Promise { + return new Promise((resolve) => { + const checkInterval = setInterval(() => { + if (tcpCommunicator.hasResponseArrived()) { + clearInterval(checkInterval); + resolve(tcpCommunicator.getLastResult()); + } + }, 100); + }); + } + + // Method to stop all intervals (for cleanup if needed) + public stopAllIntervals(): void { + for (const id of this.intervalIds) { + clearInterval(id); + } + this.log("All intervals have been stopped.", 'log', 'stopAllIntervals'); + } +} \ No newline at end of file diff --git a/CEO/src/helpers/users_info_fetcher.ts b/CEO/src/helpers/users_info_fetcher.ts index d584152..20c0b24 100644 --- a/CEO/src/helpers/users_info_fetcher.ts +++ b/CEO/src/helpers/users_info_fetcher.ts @@ -2,7 +2,7 @@ import { JsonManager } from "./json_manager"; import { MemoryManager } from "./memory_manager"; import { operationCodes } from "../network/operation_codes"; import { TcpCommunicator } from "./tcp_communicator"; -import {ParsedMessage} from "../network/message_handler"; +import { ParsedMessage } from "../network/message_handler"; export class UsersInfoFetcher { private applicationInfo: JsonManager; @@ -32,7 +32,7 @@ export class UsersInfoFetcher { private async initialize() { const usersIps = await this.applicationInfo.readValue('users_ip'); if (!usersIps) { - console.error('No IP addresses found in users_ip'); + this.log('No IP addresses found in users_ip', 'error'); return; } @@ -54,13 +54,13 @@ export class UsersInfoFetcher { for (const ip of usersIps) { this.tcpCommunicator = new TcpCommunicator(ip, this.clientPort); if (!await this.tcpCommunicator.connect()) { - console.error(`Failed to open connection for IP: ${ip}`); + this.log(`Failed to open connection for IP: ${ip}`, 'error'); continue; } if(!await this.tcpCommunicator?.sendMessage(operationCodes.GET_USER_INFORMATION)){ await this.tcpCommunicator.disconnect(); - continue + continue; } // Wait for the response for 10 seconds @@ -96,4 +96,14 @@ export class UsersInfoFetcher { private async updateActiveUsers(userInfo: any[]) { await this.memoryManager.updateMetaInformation(this.memoryId, userInfo); // Update active users in memory } + + // Unified logging function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const prefix = '[UsersInfoFetcher]'; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } } diff --git a/CEO/src/helpers/window_manager.ts b/CEO/src/helpers/window_manager.ts index c950b4e..d661a05 100644 --- a/CEO/src/helpers/window_manager.ts +++ b/CEO/src/helpers/window_manager.ts @@ -5,6 +5,7 @@ import path from 'path'; export class WindowManager { private readonly mainWindow: BrowserWindow; private readonly pathToPagesDir: string; + private announcementWindow: BrowserWindow | null = null; constructor(mainWindow: BrowserWindow, pathToPagesDir: string) { this.pathToPagesDir = pathToPagesDir; @@ -89,4 +90,46 @@ export class WindowManager { return undefined; // Return undefined if no file was selected } } + + // Method to display an announcement in a new window + async displayAnnouncement(): Promise { + if (this.announcementWindow) { + // If the window is already open, focus it + this.announcementWindow.focus(); + return; + } + + const mainScreen = require('electron').screen.getPrimaryDisplay(); + const { width, height } = mainScreen.size; + + // Initialize the announcement window + this.announcementWindow = new BrowserWindow({ + width: width / 3, + height: height / 2, + resizable: false, + title: 'Announcement', + webPreferences: { + preload: path.join(__dirname, '..', 'main', 'preload.js'), + contextIsolation: true, + nodeIntegration: false, + }, + }); + + this.announcementWindow.removeMenu(); + + // Load the announcement page + const announcementPath = path.join(this.pathToPagesDir, 'announcement.html'); + await this.announcementWindow.loadFile(announcementPath); + + // Handle window close + this.announcementWindow.on('closed', () => { + this.announcementWindow = null; // Clean up the reference + }); + } + + async closeAnnouncementWindow(): Promise { + if (this.announcementWindow) { + this.announcementWindow.close(); + } + } } diff --git a/CEO/src/helpers/worker_manager.ts b/CEO/src/helpers/worker_manager.ts index 976136c..f53f43d 100644 --- a/CEO/src/helpers/worker_manager.ts +++ b/CEO/src/helpers/worker_manager.ts @@ -13,16 +13,15 @@ export class WorkerManager { this.workers = []; // Initialize the array to store workers } - async startNetworkScannerWorker(udpPort: number, okPage: string, errorPage: string, applicationInfoPath: string): Promise { + async startNetworkScannerWorker(udpPort: number, tcpPort: number, okPage: string, errorPage: string, databaseResetPage: string, userConfigPath: string, applicationInfoPath: string): Promise { return new Promise((resolve, reject) => { const worker = new Worker(path.join(this.pathToWorkerDir, 'network_scanner_worker.js'), { - workerData: { udpPort, okPage, errorPage, applicationInfoPath }, // Pass necessary data to the worker + workerData: { udpPort, tcpPort, okPage, errorPage, databaseResetPage, userConfigPath, applicationInfoPath }, // Pass necessary data to the worker }); this.workers.push(worker); // Store the worker reference worker.on('message', (data) => { - console.log(data); if (data.type === 'changeContent') { this.windowManager.changeContent(data.page); } @@ -43,7 +42,7 @@ export class WorkerManager { }); } - // Start the Connection Pool Worker + // Start the Directories Watcher Worker async startDirectoriesWatchersWorker(memoryManagerPath: string, applicationInfoPath: string): Promise { return new Promise((resolve, reject) => { const worker = new Worker(path.join(this.pathToWorkerDir, 'directories_watcher_worker.js'), { @@ -53,18 +52,18 @@ export class WorkerManager { this.workers.push(worker); // Store the worker reference worker.on('message', (data) => { - console.log('Connection Pool Worker message:', data); + console.log('DirectoriesWatcher message:', data); }); worker.on('error', (err) => { - console.error('Connection Pool Worker error:', err); + console.error('DirectoriesWatcher error:', err); worker.terminate(); this.removeWorker(worker); reject(err); // Reject the promise if there's an error }); worker.on('exit', (code) => { - console.log(`Connection Pool Worker exited with code ${code}`); + console.log(`DirectoriesWatcher exited with code ${code}`); this.removeWorker(worker); // Remove worker reference when it exits resolve(); // Resolve when the worker exits cleanly }); @@ -169,36 +168,6 @@ export class WorkerManager { }); } - // Method to start the Announcement Worker - async startAnnouncementWorker(applicationInfoPath: string, clientPort: number, message: string): Promise { - return new Promise((resolve, reject) => { - const worker = new Worker(path.join(this.pathToWorkerDir, 'send_announcement_worker.js'), { - workerData: { applicationInfoPath, clientPort, message }, // Pass necessary data to the worker - }); - - this.workers.push(worker); // Store the worker reference - - worker.on('message', async (data) => { - await new Promise((resolve) => setTimeout(resolve, 3000)); // Wait for 1 second - this.windowManager.changeContent('main_menu'); - this.windowManager.showAlert(`${data.message}`) - }); - - worker.on('error', (err) => { - console.error('Announcement Worker error:', err); - worker.terminate(); - this.removeWorker(worker); - reject(err); // Reject the promise if there's an error - }); - - worker.on('exit', (code) => { - console.log(`Announcement Worker exited with code ${code}`); - this.removeWorker(worker); // Remove worker reference when it exits - resolve(); // Resolve when the worker exits cleanly - }); - }); - } - // Close all running workers closeAllWorkers(): void { console.log('Terminating all running workers...'); diff --git a/CEO/src/network/operation_codes.ts b/CEO/src/network/operation_codes.ts index 1bd466f..7f6edb1 100644 --- a/CEO/src/network/operation_codes.ts +++ b/CEO/src/network/operation_codes.ts @@ -25,7 +25,6 @@ export let operationCodes = { GET_USERS: 'GET_USERS', FIND_KEY_BY_USER_ID: 'FIND_KEY_BY_USER_ID', - DELETE_USER: 'DELETE_USER', SEND_ANNOUNCEMENT: 'SEND_ANNOUNCEMENT', GET_USER_INFORMATION: 'GET_USER_INFORMATION', diff --git a/CEO/src/network/operations_custom/user_to_user_operations.ts b/CEO/src/network/operations_custom/user_to_user_operations.ts index 9bf7b88..3e5c214 100644 --- a/CEO/src/network/operations_custom/user_to_user_operations.ts +++ b/CEO/src/network/operations_custom/user_to_user_operations.ts @@ -2,15 +2,17 @@ import { ParsedMessage } from '../message_handler'; import { OperationBase } from '../operations_base/operation_base'; import { OperationHandler } from '../operations_base/operation_handler'; import path from 'path'; +import { execSync } from 'child_process'; import fs from 'fs'; -import { FileEncryptor } from '../../helpers/file_encryptor'; const LOCK_FILE_EXTENSION = '.lock'; export class UserToUserOperations extends OperationBase { public static readonly operationCodes = { ...OperationBase.operationCodes, // Inherit common operation codes (OK, ERR, END) + SEND_ANNOUNCEMENT: 'SEND_ANNOUNCEMENT', GET_USER_INFORMATION: 'GET_USER_INFORMATION', + RESET_DATABASE: 'RESET_DATABASE', BACKUP_FILE: 'BACKUP_FILE', CLEAR_BACKUP: 'CLEAR_BACKUP', SHARE_FILE: 'SHARE_FILE', @@ -32,7 +34,7 @@ export class UserToUserOperations extends OperationBase { // Read JSON file with a lock mechanism static readJsonSync(filePath: string): any { - const lockFilePath = `${filePath}${LOCK_FILE_EXTENSION}`; + const lockFilePath = `${filePath}.${LOCK_FILE_EXTENSION}`; const absolutePath = path.resolve(filePath); try { @@ -65,6 +67,146 @@ export class UserToUserOperations extends OperationBase { } } + static writeJsonSync(filePath: string, data: any): boolean { + const lockFilePath = `${filePath}.${LOCK_FILE_EXTENSION}`; + const absolutePath = path.resolve(filePath); + + try { + // Loop until the lock file is removed by another process + while (fs.existsSync(lockFilePath)) { + console.log(`Waiting for lock file to be released: ${lockFilePath}`); + UserToUserOperations.sleep(100); // Use the sleep utility to pause + } + + // Create lock file to signal this process is working on the file + fs.writeFileSync(lockFilePath, ''); // Create the lock file + + // Write the data to the JSON file + fs.writeFileSync(absolutePath, JSON.stringify(data, null, 2), 'utf-8'); + console.log(`Data written successfully to ${absolutePath}`); + + // Once processing is done, delete the lock file + fs.unlinkSync(lockFilePath); // Remove the lock file + + return true; // Indicate successful write + } catch (error) { + console.error(`Error writing JSON to ${filePath}:`, error); + + // Ensure the lock file is removed even in case of an error + if (fs.existsSync(lockFilePath)) { + fs.unlinkSync(lockFilePath); + } + + return false; // Indicate failure + } + } + + private static hasEnoughDiskSpace(directory: string, requiredPercentage: number): boolean { + try { + let availableSpace = 0; + let totalSpace = 0; + + if (process.platform === 'win32') { + // Windows + const output = execSync(`wmic logicaldisk where "DeviceID='${directory[0]}:'" get FreeSpace,Size`).toString(); + const lines = output.trim().split('\n'); + const [freeSpaceStr, totalSpaceStr] = lines[1].trim().split(/\s+/); + availableSpace = parseInt(freeSpaceStr, 10); // Available space in bytes + totalSpace = parseInt(totalSpaceStr, 10); // Total space in bytes + } else { + // Unix-based (Linux/macOS) + const output = execSync(`df -k "${directory}"`).toString(); + const lines = output.trim().split('\n'); + const parts = lines[lines.length - 1].split(/\s+/); + const availableSpaceInKb = parseInt(parts[3], 10); // Available space in KB + const totalSpaceInKb = parseInt(parts[1], 10); // Total space in KB + availableSpace = availableSpaceInKb * 1024; + totalSpace = totalSpaceInKb * 1024; + } + + // Calculate available space as a percentage of the total space + const availablePercentage = (availableSpace / totalSpace) * 100; + + // Return true if the available percentage is greater than or equal to the required percentage + return availablePercentage >= requiredPercentage; + } catch (error) { + console.error(`Error checking disk space: ${error}`); + return false; // Return false if there's an error + } + } + + public static handleResetDatabase(parsedMessage: ParsedMessage): ParsedMessage { + // Path to the application.json file + const pathToApplicationJson = path.join(__dirname, '..', '..', 'json_files', 'application.json'); + + try { + // Read the existing data from application.json + const appData = UserToUserOperations.readJsonSync(pathToApplicationJson) || {}; + + // Update the reset_application_preferences field to true + appData.reset_application_preferences = true; + + // Write the updated data back to application.json + const success = UserToUserOperations.writeJsonSync(pathToApplicationJson, appData); + + if (success) { + console.log(`Application preferences reset successfully.`); + return { + operationCode: UserToUserOperations.operationCodes.OK, + metaInfo: { message: 'Application preferences reset successfully.' }, + }; + } else { + throw new Error("Failed to write to application.json"); + } + } catch (error: any) { + console.error(`Error resetting application preferences: ${error.message}`); + return { + operationCode: UserToUserOperations.operationCodes.ERR, + metaInfo: { message: `Error resetting application preferences: ${error.message}` }, + }; + } + } + + + public static handleSendAnnouncement(parsedMessage: ParsedMessage): ParsedMessage { + // Ensure the message is available in metaInfo + if (!parsedMessage.metaInfo || !parsedMessage.metaInfo.message) { + return { + operationCode: UserToUserOperations.operationCodes.ERR, + metaInfo: { message: 'Missing announcement message in meta information.' }, + }; + } + + const announcementMessage = parsedMessage.metaInfo.message; + + // Path to the application.json file + const pathToApplicationJson = path.join(__dirname, '..', '..', 'json_files', 'application.json'); + + try { + // Read the existing data from application.json + const appData = UserToUserOperations.readJsonSync(pathToApplicationJson) || {}; + + // Update the announcement field with the new message + appData.announcement = announcementMessage; + + // Write the updated data back to application.json + fs.writeFileSync(pathToApplicationJson, JSON.stringify(appData, null, 2), 'utf-8'); + + console.log(`Announcement message saved successfully: ${announcementMessage}`); + + return { + operationCode: UserToUserOperations.operationCodes.OK, + metaInfo: { message: 'Announcement message saved successfully.' }, + }; + } catch (error: any) { + console.error(`Error saving announcement message: ${error.message}`); + return { + operationCode: UserToUserOperations.operationCodes.ERR, + metaInfo: { message: `Error saving announcement message: ${error.message}` }, + }; + } + } + // Handle user information retrieval public static handleGetUserInformation(parsedMessage: ParsedMessage): ParsedMessage { const pathToUserJson = path.join(__dirname, '..', '..', 'json_files', 'userConfig.json'); @@ -109,6 +251,15 @@ export class UserToUserOperations extends OperationBase { const fullFilePath = path.join(baseBackupDir, userName, relativeFilePath); try { + // Check if there is enough disk space + const requiredPercentage = 25; + if (!UserToUserOperations.hasEnoughDiskSpace(baseBackupDir, requiredPercentage)) { + return { + operationCode: UserToUserOperations.operationCodes.ERR, + metaInfo: { message: 'Insufficient disk space for backup.' }, + }; + } + // Ensure the directory structure exists (create directories if they don't exist) const dirPath = path.dirname(fullFilePath); if (!fs.existsSync(dirPath)) { @@ -262,7 +413,7 @@ export class UserToUserOperations extends OperationBase { // Get the share directory path const baseDepartmentDir = appInfo.departmentDirectory.path; - const userDepartmentDir = path.join(baseDepartmentDir, userName); + const userDepartmentDir = path.join(baseDepartmentDir, '..', 'DEPARTMENT_FILES', userName); try { // Check if the user's backup directory exists @@ -325,7 +476,7 @@ export class UserToUserOperations extends OperationBase { const departmentDirectory = appInfo.departmentDirectory.path; // Full path where the file will be stored (under the user's directory in the shared folder) - const fullFilePath = path.join(departmentDirectory, userName, relativeFilePath); + const fullFilePath = path.join(departmentDirectory, '..', 'DEPARTMENT_FILES', userName, relativeFilePath); try { // Ensure the directory structure exists (create directories if they don't exist) @@ -484,6 +635,8 @@ export class UserToUserOperations extends OperationBase { // Register user-to-user operations with the OperationHandler public register(operationHandler: OperationHandler): void { // Register specific handlers for user-to-user operations + operationHandler.registerHandler(UserToUserOperations.operationCodes.RESET_DATABASE, UserToUserOperations.handleResetDatabase); + operationHandler.registerHandler(UserToUserOperations.operationCodes.SEND_ANNOUNCEMENT, UserToUserOperations.handleSendAnnouncement); operationHandler.registerHandler(UserToUserOperations.operationCodes.GET_USER_INFORMATION, UserToUserOperations.handleGetUserInformation); operationHandler.registerHandler(UserToUserOperations.operationCodes.BACKUP_FILE, UserToUserOperations.handleBackupFile); operationHandler.registerHandler(UserToUserOperations.operationCodes.CLEAR_BACKUP, UserToUserOperations.handleClearBackup); diff --git a/CEO/src/network/socket_communicator/tcp_client_communicator.ts b/CEO/src/network/socket_communicator/tcp_client_communicator.ts index 6d78dd2..6bf2aa2 100644 --- a/CEO/src/network/socket_communicator/tcp_client_communicator.ts +++ b/CEO/src/network/socket_communicator/tcp_client_communicator.ts @@ -1,12 +1,12 @@ import { Socket } from 'net'; -import { createCipheriv, createDecipheriv } from 'crypto'; -import { MessageHandler, ParsedMessage } from '../message_handler'; +import { createCipheriv, createDecipheriv, constants, publicDecrypt } from 'crypto'; +import {MessageHandler, ParsedMessage} from '../message_handler'; import { SocketCommunicatorBase } from './socket_communicator_base'; import { OperationHandler } from '../operations_base/operation_handler'; -import {constants, publicDecrypt} from "node:crypto"; -import {operationCodes} from "../operation_codes"; +import { operationCodes } from '../operation_codes'; -const END_OF_MESSAGE = ''; // Define a unique marker for end of message +const END_OF_MESSAGE = ''; // Unique marker for the end of message +const CHUNK_SIZE = 1024; // Define chunk size export class TcpClientCommunicator extends SocketCommunicatorBase { private readonly socket: Socket; @@ -15,30 +15,28 @@ export class TcpClientCommunicator extends SocketCommunicatorBase { private messageBuffer: string; private serverPublicKey: string | null; private isAesKeySetFlag: boolean; + private chunkBuffers: { [messageId: string]: string[] }; // Buffer for reassembling chunks constructor(socket: Socket, ip: string, port: number, operationHandler: OperationHandler) { - super(ip, port, operationHandler); + super(ip, port, operationHandler); // Call parent constructor this.socket = socket; this.aesKey = null; this.aesIv = null; this.serverPublicKey = null; this.messageBuffer = ''; // Buffer for message reassembly this.isAesKeySetFlag = false; + this.chunkBuffers = {}; // Initialize chunk buffer for reassembling messages } setServerPublicKey(publicKey: string): void { this.serverPublicKey = publicKey; - console.log('Server public key set.'); } - // Set the AES key when received setAesKey(aesKey: string, aesIv: string): void { this.aesKey = Buffer.from(aesKey, 'base64'); this.aesIv = Buffer.from(aesIv, 'base64'); - console.log('AES key set.'); } - // Encrypt a message with AES private encryptWithAes(message: string): string { if (!this.aesKey || !this.aesIv) { throw new Error('AES key or IV is not set.'); @@ -65,62 +63,48 @@ export class TcpClientCommunicator extends SocketCommunicatorBase { } try { const encryptedMessage = Buffer.from(message.toString(), 'base64'); - // Decrypt the message using the server's public key const decrypted = publicDecrypt( { key: this.serverPublicKey, - padding: constants.RSA_PKCS1_PADDING, // Matching padding for decryption + padding: constants.RSA_PKCS1_PADDING, }, encryptedMessage ); return decrypted.toString('utf-8'); } catch (error) { - console.error('RSA decryption failed:', error); throw new Error('Failed to decrypt RSA message.'); } } - // Handle incoming chunks of data - async handleIncomingChunk(data: Buffer): Promise { - const incomingMessage = data.toString(); - this.messageBuffer += incomingMessage; - - // Check if the message ends with END_OF_MESSAGE - if (this.messageBuffer.endsWith(END_OF_MESSAGE)) { - // Remove the END_OF_MESSAGE marker and process the message - const completeMessage = this.messageBuffer.slice(0, -END_OF_MESSAGE.length); - - this.handleIncomingMessage(completeMessage); - - // Clear the message buffer after processing - this.messageBuffer = ''; - } - } - - // Send a chunked message over the socket async sendChunkedMessage(operationCode: string, metaInfo?: { [key: string]: any }, fileContent?: Buffer): Promise { const message = MessageHandler.formatMessage(operationCode, metaInfo, fileContent); - let outgoingMessage: string; + const outgoingMessage = this.encryptWithAes(message); - // Encrypt the message with AES if available - if (this.aesKey && this.aesIv) { - outgoingMessage = this.encryptWithAes(message); - } else { - outgoingMessage = message // Send plain text if AES is not set + const totalChunks = Math.ceil(outgoingMessage.length / CHUNK_SIZE); + const messageId = Date.now().toString(); + + for (let i = 0; i < totalChunks; i++) { + const chunk = outgoingMessage.slice(i * CHUNK_SIZE, (i + 1) * CHUNK_SIZE); + const chunkHeader = JSON.stringify({ + messageId, + sequenceNumber: i, + totalChunks, + }); + + const chunkWithHeader = `${chunkHeader}|${chunk}`; + + await this.writeToSocket(chunkWithHeader); + + if (i === totalChunks - 1) { + await this.writeToSocket(END_OF_MESSAGE); + } } - - // Append the end marker to the message - outgoingMessage += END_OF_MESSAGE; - - await this.writeToSocket(outgoingMessage); } - // Write message to socket private writeToSocket(message: string): Promise { return new Promise((resolve, reject) => { this.socket.write(message, (err: any) => { if (err) { - console.error('Error sending message over TCP:', err); return reject(err); } resolve(); @@ -128,37 +112,69 @@ export class TcpClientCommunicator extends SocketCommunicatorBase { }); } - // Handle incoming message (decrypted if AES is set) + async handleIncomingChunk(data: Buffer): Promise { + const incomingMessage = data.toString(); + this.messageBuffer += incomingMessage; + + if (this.messageBuffer.includes(END_OF_MESSAGE)) { + const messages = this.messageBuffer.split(END_OF_MESSAGE); + + for (let i = 0; i < messages.length - 1; i++) { + const completeMessage = messages[i]; + if (completeMessage) { + this.processCompleteMessage(completeMessage); + } + } + + this.messageBuffer = messages[messages.length - 1]; + } + } + + private processCompleteMessage(completeMessage: string): void { + const [headerJson, chunkContent] = completeMessage.split('|'); + const header = JSON.parse(headerJson); + + if (!this.chunkBuffers[header.messageId]) { + this.chunkBuffers[header.messageId] = new Array(header.totalChunks); + } + + this.chunkBuffers[header.messageId][header.sequenceNumber] = chunkContent; + + if (this.chunkBuffers[header.messageId].every((chunk) => chunk !== undefined)) { + const fullMessage = this.chunkBuffers[header.messageId].join(''); + this.handleIncomingMessage(fullMessage); + delete this.chunkBuffers[header.messageId]; + } + } + handleIncomingMessage(incomingMessage: string): void { let messageToProcess = incomingMessage; if (this.aesKey && this.aesIv) { messageToProcess = this.decryptWithAes(incomingMessage); - }else if(this.serverPublicKey){ + } else if (this.serverPublicKey) { messageToProcess = this.decryptWithRsa(incomingMessage); } const result = this.operationHandler.handleOperation(messageToProcess); - if(result.operationCode === operationCodes.SET_AES_KEY){ + if (result.operationCode === operationCodes.SET_AES_KEY) { this.isAesKeySetFlag = true; this.setAesKey(result.metaInfo?.aesKey, result.metaInfo?.aesIv); return; } - if(result.operationCode === operationCodes.SET_PUBLIC_KEY) { + if (result.operationCode === operationCodes.SET_PUBLIC_KEY) { this.setServerPublicKey(result.metaInfo?.publicKey); return; } - this.handlerResult = result + this.handlerResult = result; } - // Check if AES key is set isAesKeySet(): boolean { return this.isAesKeySetFlag; } - // Get handler result for operation handling getHandlerResult(): ParsedMessage | null { return this.handlerResult; } diff --git a/CEO/src/network/socket_communicator/tcp_server_communicator.ts b/CEO/src/network/socket_communicator/tcp_server_communicator.ts index 8f57dba..61840ef 100644 --- a/CEO/src/network/socket_communicator/tcp_server_communicator.ts +++ b/CEO/src/network/socket_communicator/tcp_server_communicator.ts @@ -1,11 +1,11 @@ import { Socket } from 'net'; -import { privateEncrypt, privateDecrypt, generateKeyPairSync, createCipheriv, createDecipheriv, randomBytes } from 'crypto'; -import { MessageHandler, ParsedMessage } from '../message_handler'; +import { privateEncrypt, generateKeyPairSync, createCipheriv, createDecipheriv, randomBytes, constants } from 'crypto'; +import { MessageHandler } from '../message_handler'; import { SocketCommunicatorBase } from './socket_communicator_base'; import { OperationHandler } from '../operations_base/operation_handler'; -import {constants} from "node:crypto"; const END_OF_MESSAGE = ''; // Define a unique marker for end of message +const CHUNK_SIZE = 1024; // Define chunk size export class TcpServerCommunicator extends SocketCommunicatorBase { private readonly socket: Socket; @@ -14,6 +14,7 @@ export class TcpServerCommunicator extends SocketCommunicatorBase { private aesKey: Buffer | null; private aesIv: Buffer | null; private messageBuffer: string; + private chunkBuffers: { [messageId: string]: string[] }; // Buffer for reassembling chunks constructor(socket: Socket, ip: string, port: number, operationHandler: OperationHandler) { super(ip, port, operationHandler); @@ -23,6 +24,7 @@ export class TcpServerCommunicator extends SocketCommunicatorBase { this.aesKey = null; this.aesIv = null; this.messageBuffer = ''; // Initialize the message buffer + this.chunkBuffers = {}; // Buffer for reassembling incoming messages this.generateKeyPair(); // Generate RSA key pair for encryption } @@ -35,7 +37,6 @@ export class TcpServerCommunicator extends SocketCommunicatorBase { }); this.privateKey = privateKey; this.publicKey = publicKey; - console.log('RSA key pair generated.'); } // Send the server's public key to the client @@ -44,9 +45,7 @@ export class TcpServerCommunicator extends SocketCommunicatorBase { throw new Error('Public key is not available. Please generate RSA key pair.'); } - const message = MessageHandler.formatMessage('SET_PUBLIC_KEY', { publicKey: this.publicKey }); - await this.writeToSocket(message + END_OF_MESSAGE); - console.log('Public key sent to client.'); + await this.sendChunkedMessage('SET_PUBLIC_KEY', { publicKey: this.publicKey }); } // Generate AES key and IV, then send them to the client @@ -57,16 +56,11 @@ export class TcpServerCommunicator extends SocketCommunicatorBase { const aesKeyBase64 = this.aesKey.toString('base64'); const aesIvBase64 = this.aesIv.toString('base64'); - const formattedMessage = MessageHandler.formatMessage('SET_AES_KEY', { aesKey: aesKeyBase64, aesIv: aesIvBase64 }); - const encryptedMessage = this.encryptWithRsa(Buffer.from(formattedMessage)).toString('base64'); - - await this.writeToSocket(encryptedMessage + END_OF_MESSAGE); - console.log('AES key and IV sent to client.'); + await this.sendChunkedMessage('SET_AES_KEY', { aesKey: aesKeyBase64, aesIv: aesIvBase64 }); } // Encrypt a message with the server's private key (RSA encryption) - private encryptWithRsa(message: Buffer): Buffer { - const bufferMessage = Buffer.isBuffer(message) ? message : Buffer.from(message); + private encryptWithRsa(message: string): string { if (!this.privateKey) throw new Error('Server private key not set.'); return privateEncrypt( @@ -74,8 +68,8 @@ export class TcpServerCommunicator extends SocketCommunicatorBase { key: this.privateKey, padding: constants.RSA_PKCS1_PADDING, // PKCS1 padding }, - bufferMessage - ); + Buffer.from(message) + ).toString('base64'); } // Decrypt AES-encrypted messages @@ -106,17 +100,34 @@ export class TcpServerCommunicator extends SocketCommunicatorBase { const incomingMessage = data.toString(); this.messageBuffer += incomingMessage; - // Check if the message ends with END_OF_MESSAGE - if (this.messageBuffer.endsWith(END_OF_MESSAGE)) { - // Remove the END_OF_MESSAGE marker and process the message - const completeMessage = this.messageBuffer.slice(0, -END_OF_MESSAGE.length); + if (this.messageBuffer.includes(END_OF_MESSAGE)) { + const messages = this.messageBuffer.split(END_OF_MESSAGE); - console.log(`\n\nComplete Message:\n${completeMessage}\n\n`); + for (let i = 0; i < messages.length - 1; i++) { + const completeMessage = messages[i]; + if (completeMessage) { + this.processCompleteMessage(completeMessage); + } + } - this.handleIncomingMessage(completeMessage); + this.messageBuffer = messages[messages.length - 1]; + } + } - // Clear the message buffer after processing - this.messageBuffer = ''; + private processCompleteMessage(completeMessage: string): void { + const [headerJson, chunkContent] = completeMessage.split('|'); + const header = JSON.parse(headerJson); + + if (!this.chunkBuffers[header.messageId]) { + this.chunkBuffers[header.messageId] = new Array(header.totalChunks); + } + + this.chunkBuffers[header.messageId][header.sequenceNumber] = chunkContent; + + if (this.chunkBuffers[header.messageId].every((chunk) => chunk !== undefined)) { + const fullMessage = this.chunkBuffers[header.messageId].join(''); + this.handleIncomingMessage(fullMessage); + delete this.chunkBuffers[header.messageId]; } } @@ -125,14 +136,36 @@ export class TcpServerCommunicator extends SocketCommunicatorBase { const message = MessageHandler.formatMessage(operationCode, metaInfo, fileContent); let outgoingMessage: string; - if (this.aesKey && this.aesIv) { - outgoingMessage = this.encryptWithAes(message); - } else { - outgoingMessage = message; + switch(operationCode) { + case 'SET_PUBLIC_KEY': + outgoingMessage = message; + break; + case 'SET_AES_KEY': + outgoingMessage = this.encryptWithRsa(message); + break; + default: + outgoingMessage = this.encryptWithAes(message); } - outgoingMessage += END_OF_MESSAGE; // Append end-of-message marker - await this.writeToSocket(outgoingMessage); + const totalChunks = Math.ceil(outgoingMessage.length / CHUNK_SIZE); + const messageId = Date.now().toString(); + + for (let i = 0; i < totalChunks; i++) { + const chunk = outgoingMessage.slice(i * CHUNK_SIZE, (i + 1) * CHUNK_SIZE); + const chunkHeader = JSON.stringify({ + messageId, + sequenceNumber: i, + totalChunks, + }); + + const chunkWithHeader = `${chunkHeader}|${chunk}`; + + await this.writeToSocket(chunkWithHeader); + + if (i === totalChunks - 1) { + await this.writeToSocket(END_OF_MESSAGE); + } + } } // Handle incoming message (decrypt with AES if available) diff --git a/CEO/src/network/tcp/tcp_client.ts b/CEO/src/network/tcp/tcp_client.ts index e6d5d62..7ad64f3 100644 --- a/CEO/src/network/tcp/tcp_client.ts +++ b/CEO/src/network/tcp/tcp_client.ts @@ -29,12 +29,12 @@ export class TcpClient { this.socket = new net.Socket(); this.socket.connect(this.tcp_port, ip, () => { - console.log(`Client connected to server at ${ip}:${this.tcp_port}`); + //console.log(`Client connected to server at ${ip}:${this.tcp_port}`); this.communicator = new TcpClientCommunicator(this.socket as Socket, ip, this.tcp_port, this.operationHandler); }); this.socket.on('error', (err) => { - console.error(`Connection error to server at ${ip}:${this.tcp_port}: ${err.message}`); + //console.error(`Connection error to server at ${ip}:${this.tcp_port}: ${err.message}`); }); this.socket.on('data', async (data: Buffer) => { @@ -45,7 +45,7 @@ export class TcpClient { }); this.socket.on('close', () => { - console.log(`Connection closed: ${ip}:${this.tcp_port}`); + //console.log(`Connection closed: ${ip}:${this.tcp_port}`); this.lastResult = null; // Clear the last result on socket close }); } @@ -57,14 +57,14 @@ export class TcpClient { this.socket = null; this.communicator = null; this.lastResult = null; // Clear the last result on close - console.log('Client socket connection closed.'); + //console.log('Client socket connection closed.'); } } // Send a message with operationCode, metaInfo, and fileContent in chunks async sendMessage(operationCode: string, metaInfo?: { [key: string]: any }, fileContent?: Buffer): Promise { if (!this.communicator || !this.isAesKeySet()) { - console.error('Communicator not initialized or AES key not set.'); + //console.error('Communicator not initialized or AES key not set.'); return false; } diff --git a/CEO/src/network/tcp/tcp_server.ts b/CEO/src/network/tcp/tcp_server.ts index 98d1504..e0e66ab 100644 --- a/CEO/src/network/tcp/tcp_server.ts +++ b/CEO/src/network/tcp/tcp_server.ts @@ -35,7 +35,7 @@ export class TcpServer { const port = socket.remotePort || 0; const clientId = `${ip}:${port}`; // Use IP and port to identify the client - console.log(`Client connected: ${clientId}`); + //console.log(`Client connected: ${clientId}`); const tcpCommunicator = new TcpServerCommunicator(socket, ip, port, this.operationHandler); this.connectionManager.addConnection(ip, port, tcpCommunicator); @@ -44,9 +44,8 @@ export class TcpServer { tcpCommunicator.generateKeyPair(); tcpCommunicator.sendPublicKey() .then(() => tcpCommunicator.sendAesKey()) - .then(() => console.log('Public key and AES key sent successfully.')) .catch(err => { - console.error(`Error during key exchange with client ${clientId}:`, err); + //console.error(`Error during key exchange with client ${clientId}:`, err); socket.end(); // Close the connection in case of any error }); @@ -57,13 +56,13 @@ export class TcpServer { // Handle client disconnect socket.on('end', () => { - console.log(`Client disconnected: ${clientId}`); + //console.log(`Client disconnected: ${clientId}`); this.connectionManager.removeCommunicator(ip, port); }); // Handle socket errors socket.on('error', (err: Error) => { - console.error(`Error from client ${clientId}: ${err.message}`); + //console.error(`Error from client ${clientId}: ${err.message}`); this.connectionManager.removeCommunicator(ip, port); }); }); @@ -86,7 +85,7 @@ export class TcpServer { // Retrieve the communicator associated with this connection const communicator = this.connectionManager.getCommunicator(ip, port) as TcpServerCommunicator; if (!communicator) { - console.error(`No communicator found for ${clientId}`); + //console.error(`No communicator found for ${clientId}`); return; } @@ -102,9 +101,9 @@ export class TcpServer { handlerResult.metaInfo, handlerResult.fileContent ); - console.log(`Response sent to ${clientId}`); + //console.log(`Response sent to ${clientId}`); } catch (err) { - console.error(`Failed to send response to ${clientId}:`, err); + //console.error(`Failed to send response to ${clientId}:`, err); } } } diff --git a/CEO/src/network/udp/udp_server.ts b/CEO/src/network/udp/udp_server.ts index b87b82f..3c66550 100644 --- a/CEO/src/network/udp/udp_server.ts +++ b/CEO/src/network/udp/udp_server.ts @@ -34,7 +34,7 @@ export class UdpServer { const ip = rinfo.address; const port = rinfo.port; - console.log(`Received message from ${ip}:${port}`); + //console.log(`Received message from ${ip}:${port}`); // Create a temporary communicator for the incoming message const communicator = new UdpSocketCommunicator(this.udpServer, ip, port, this.operationHandler); @@ -46,8 +46,6 @@ export class UdpServer { if (communicatorResult) { // Send response back to the client using the temporary communicator await communicator.sendMessage(communicatorResult.operationCode, communicatorResult.metaInfo); - } else { - console.error(`No handler result for ${ip}:${port}`); } } diff --git a/CEO/src/workers/directories_watcher_worker.ts b/CEO/src/workers/directories_watcher_worker.ts index 9e0138f..a5ba517 100644 --- a/CEO/src/workers/directories_watcher_worker.ts +++ b/CEO/src/workers/directories_watcher_worker.ts @@ -7,37 +7,11 @@ const { } = workerData; const backupDirectoryManager = new DirectoryWatcher(memoryManagerPath, applicationInfoPath, 'backupDirectory'); +backupDirectoryManager.start(); + const departmentShareManager = new DirectoryWatcher(memoryManagerPath, applicationInfoPath, 'departmentDirectory'); +departmentShareManager.start(); + const shareFileManager = new DirectoryWatcher(memoryManagerPath, applicationInfoPath, 'shareDirectory'); - -// Backup directory manager check loop -const backupIntervalId = setInterval(async () => { - if (await backupDirectoryManager.initialize()) { - clearInterval(backupIntervalId); // Stop the loop once initialized - console.log('BackupDirectoryManager successfully initialized.'); - } else { - console.log('Retrying BackupDirectoryManager initialization...'); - } -}, 10000); // Check every 60 seconds - - -// Department share manager check loop -const departmentIntervalId = setInterval(async () => { - if (await departmentShareManager.initialize()) { - clearInterval(departmentIntervalId); // Stop the loop once initialized - console.log('DepartmentShareManager successfully initialized.'); - } else { - console.log('Retrying DepartmentShareManager initialization...'); - } -}, 10000); // Check every 60 seconds - -// Department share manager check loop -const shareIntervalId = setInterval(async () => { - if (await shareFileManager.initialize()) { - clearInterval(shareIntervalId); // Stop the loop once initialized - console.log('DepartmentShareManager successfully initialized.'); - } else { - console.log('Retrying DepartmentShareManager initialization...'); - } -}, 10000); // Check every 60 seconds +shareFileManager.start(); diff --git a/CEO/src/workers/network_scanner_worker.ts b/CEO/src/workers/network_scanner_worker.ts index ede8aa5..c22db64 100644 --- a/CEO/src/workers/network_scanner_worker.ts +++ b/CEO/src/workers/network_scanner_worker.ts @@ -1,94 +1,19 @@ import { parentPort, workerData } from 'worker_threads'; -import { JsonManager } from '../helpers/json_manager'; -import { UdpClient } from '../network/udp/udp_client'; +import { NetworkScanner } from '../helpers/network_scanner'; // Define the structure of workerData interface WorkerData { udpPort: number; + tcpPort: number; okPage: string; errorPage: string; + databaseResetPage: string; + userConfigPath: string; applicationInfoPath: string; } // Extract the data passed to the worker -const { udpPort, okPage, errorPage, applicationInfoPath }: WorkerData = workerData; +const { udpPort, tcpPort, okPage, errorPage, databaseResetPage, userConfigPath, applicationInfoPath }: WorkerData = workerData; -// Create a JsonManager instance for application info -const applicationInfo = new JsonManager(applicationInfoPath); -let appStarted = false; -let intervalIds: NodeJS.Timeout[] = []; // Store interval IDs for future clearing - -// Flags to prevent overlapping executions -let ucCheckBusy = false; -let ipLookupBusy = false; - -// Function to schedule the UC check task with dynamic UDP client creation -function startUCCheck(udpPort: number, okPage: string, errorPage: string, interval: number = 5000): void { - const intervalId = setInterval(async () => { - if (ucCheckBusy) return; // If already running, skip this iteration - ucCheckBusy = true; // Mark as busy - - try { - console.log('UC Check running...'); - const udpClient = new UdpClient(udpPort); // Create UdpClient with the provided port - const aliveClients = await udpClient.getAliveClients(); - const storedIp = await applicationInfo.readValue('serverIp'); - const foundClient = aliveClients.length > 0; - - if (foundClient) { - const ipAddress = aliveClients[0]; // Just using the first alive client - - if (!storedIp || storedIp !== ipAddress) { - await applicationInfo.writeValue('serverIp', ipAddress); - if (!appStarted) { - parentPort?.postMessage({ type: 'changeContent', page: okPage }); - } - appStarted = true; - } else if (!appStarted) { - parentPort?.postMessage({ type: 'changeContent', page: okPage }); - appStarted = true; - } - } else { - parentPort?.postMessage({ type: 'changeContent', page: errorPage }); - } - } catch (err) { - console.error('Error checking UC:', err); - parentPort?.postMessage({ type: 'changeContent', page: errorPage }); - } finally { - ucCheckBusy = false; // Mark as not busy - } - }, interval); - - intervalIds.push(intervalId); -} - -// Function to schedule the IP lookup task, storing the active addresses in memory -function startUserIPLookup(udpPort: number, interval: number = 10000): void { - const intervalId = setInterval(async () => { - if (ipLookupBusy) return; // If already running, skip this iteration - ipLookupBusy = true; // Mark as busy - - try { - console.log('IP Lookup running...'); - const serverIp = await applicationInfo.readValue('serverIp'); - const udpClient = new UdpClient(udpPort); // Create a UDP client with the provided port - const activeIPs = await udpClient.getAliveClients(); // Get the list of active IPs - - // Filter out the serverIp from the list of active clients - const filteredIPs = activeIPs.filter(ip => ip !== serverIp); - - // Save the filtered IPs to 'users_ip' - await applicationInfo.writeValue('users_ip', filteredIPs); - } catch (err) { - console.error('Error during user IP lookup:', err); - } finally { - ipLookupBusy = false; // Mark as not busy - } - }, interval); - - intervalIds.push(intervalId); -} - -// Start the UC Check and User IP Lookup tasks -startUCCheck(udpPort, okPage, errorPage); -startUserIPLookup(udpPort); +// Start the NetworkScanner instance +const networkScanner = new NetworkScanner(applicationInfoPath, userConfigPath, udpPort, tcpPort, okPage, errorPage, databaseResetPage); diff --git a/CEO/src/workers/resource_coordinator_worker.ts b/CEO/src/workers/resource_coordinator_worker.ts index c92c215..922c59b 100644 --- a/CEO/src/workers/resource_coordinator_worker.ts +++ b/CEO/src/workers/resource_coordinator_worker.ts @@ -8,45 +8,15 @@ import {DepartmentSharer} from "../helpers/department_sharer"; const { usersConfigPath, applicationInfoPath, memoryManagerPath, queueManagerPath, tcpPort } = workerData; const usersInfoFetcher = new UsersInfoFetcher(applicationInfoPath, memoryManagerPath, tcpPort); -usersInfoFetcher.start() - .then(() => { - console.log('Users Info Fetcher started successfully'); - }) - .catch((error: any) => { - console.error('Error starting Users Info Fetcher:', error); - }); +usersInfoFetcher.start(); -const backupManager = new BackupRetrievalWorker( - usersConfigPath, - applicationInfoPath, - memoryManagerPath, - tcpPort -); - -backupManager.start() - .then(() => { - console.log('Backup Manager started successfully'); - }) - .catch((error: any) => { - console.error('Error starting Backup Manager:', error); - }); +const backupManager = new BackupRetrievalWorker(usersConfigPath, applicationInfoPath, memoryManagerPath, tcpPort); +backupManager.start(); const fileSharer = new FileSharer(queueManagerPath, tcpPort); -fileSharer.start() - .then(() => { - console.log('File Sharer started successfully'); - }) - .catch((error: any) => { - console.error('Error starting File Sharer:', error); - }); +fileSharer.start(); const departmentSharer = new DepartmentSharer(usersConfigPath, applicationInfoPath, memoryManagerPath, tcpPort); -departmentSharer.start() - .then(() => { - console.log('Department Sharer started successfully'); - }) - .catch((error: any) => { - console.error('Error starting Department Sharer:', error); - }); +departmentSharer.start(); diff --git a/CEO/src/workers/send_announcement_worker.ts b/CEO/src/workers/send_announcement_worker.ts deleted file mode 100644 index 816b6e7..0000000 --- a/CEO/src/workers/send_announcement_worker.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { workerData } from 'worker_threads'; -import { AnnouncementSender} from "../helpers/announcement_sender"; - -// Destructure data passed from the main thread -const { - applicationInfoPath, - clientPort, - message -}: { - applicationInfoPath: string, - clientPort: number, - message: string -} = workerData; - -// Initialize the AnnouncementWorker -const announcementWorker = new AnnouncementSender(applicationInfoPath, clientPort); - -// Start the announcement process and handle results -announcementWorker.start(message); diff --git a/User/src/helpers/backup_manager.ts b/User/src/helpers/backup_manager.ts index 928f460..d868180 100644 --- a/User/src/helpers/backup_manager.ts +++ b/User/src/helpers/backup_manager.ts @@ -1,7 +1,6 @@ -import { JsonManager } from './json_manager'; // Assuming this manages JSON configurations +import { JsonManager } from './json_manager'; import { TcpCommunicator } from "./tcp_communicator"; -import { operationCodes } from '../network/operation_codes'; // Assuming this holds operation codes -import { parentPort } from 'worker_threads'; +import { operationCodes } from '../network/operation_codes'; import path from 'path'; import fs from 'fs'; import crypto from 'crypto'; @@ -15,15 +14,30 @@ export class BackupRetrievalWorker { private encryptionKey: Buffer | null = null; private iv: Buffer | null = null; private tcpCommunicator: TcpCommunicator | null = null; + private isBusy: boolean; + private lastProcessedUserIndex: number; constructor(userConfigPath: string, applicationInfoPath: string, clientPort: number, destinationPath: string) { this.userConfig = new JsonManager(userConfigPath); this.applicationInfo = new JsonManager(applicationInfoPath); this.clientPort = clientPort; this.destinationPath = destinationPath; + this.isBusy = false; + this.lastProcessedUserIndex = 0; } async start(): Promise { + setInterval(async () => { + if (!this.isBusy) { + this.log('Start successfully. Processing backup tasks.'); + await this.processBackupTasks(); + } + }, 10000); // Retry every 10 seconds if there's an error + } + + private async processBackupTasks(): Promise { + this.isBusy = true; + try { const userInfo = await this.userConfig.readValue('user_info'); if (!userInfo || !userInfo.name) { @@ -41,46 +55,50 @@ export class BackupRetrievalWorker { const activeUsersIp = await this.applicationInfo.readValue('users_ip'); if (!activeUsersIp || !activeUsersIp.length) { - parentPort?.postMessage({ success: false, message: 'No active users found.' }); - return; + this.isBusy = false; + throw new Error('No active users found.'); } + // Process each user, starting from the last processed index let backupSuccessful = true; - for (const ip of activeUsersIp) { + for (let i = this.lastProcessedUserIndex; i < activeUsersIp.length; i++) { + const ip = activeUsersIp[i]; const success = await this.processBackupForIp(ip, userName); if (!success) { backupSuccessful = false; - parentPort?.postMessage({ success: false, message: 'Backup could not be completed due to an internal error.' }); + this.lastProcessedUserIndex = i; // Remember where it stopped break; } } if (backupSuccessful) { - parentPort?.postMessage({ success: true, message: 'Backup successful.' }); + this.log('Backup retrieval completed successfully for all users.'); + this.lastProcessedUserIndex = 0; // Reset index to start from the beginning next cycle } } catch (error: any) { - console.error('Error in BackupRetrievalWorker:', error); - parentPort?.postMessage({ success: false, message: `Backup could not be completed due to an internal error: ${error.message}` }); + this.log(error.message, 'error'); } + + this.isBusy = false; } private async processBackupForIp(ip: string, userName: string): Promise { this.tcpCommunicator = new TcpCommunicator(ip, this.clientPort); if (!await this.tcpCommunicator.connect()) { - console.error(`Failed to connect to ${ip}`); + this.log(`Failed to connect to ${ip}`, 'error'); return false; } const backupExists = await this.checkIfBackupExists(userName); if (!backupExists) { - console.log(`No backup found for user ${userName} on IP ${ip}`); + this.log(`No backup found for user ${userName} on IP ${ip}`); await this.tcpCommunicator.disconnect(); return true; // Skip user if no backup found, do not mark as error } const backupStructure = await this.requestBackupStructure(userName); if (!backupStructure || Object.keys(backupStructure).length === 0) { - console.log(`No files found in backup structure for user ${userName} on IP ${ip}`); + this.log(`No files found in backup structure for user ${userName} on IP ${ip}`); await this.tcpCommunicator.disconnect(); return true; // Skip user if no files found, do not mark as error } @@ -88,7 +106,7 @@ export class BackupRetrievalWorker { for (const relativeFilePath of Object.keys(backupStructure)) { const fileRequestSuccess = await this.requestBackupFile(userName, relativeFilePath); if (!fileRequestSuccess) { - console.error(`Failed to retrieve file ${relativeFilePath} from backup for user ${userName} on IP ${ip}`); + this.log(`Failed to retrieve file ${relativeFilePath} from backup for user ${userName} on IP ${ip}`, 'error'); await this.tcpCommunicator.disconnect(); return false; // Stop if any file fails to be retrieved } @@ -133,7 +151,7 @@ export class BackupRetrievalWorker { private saveFile(relativeFilePath: string, fileContent: string): boolean { if (!this.encryptionKey || !this.iv) { - console.error('Encryption key or IV is not set.'); + this.log('Encryption key or IV is not set.', 'error'); return false; } @@ -141,7 +159,7 @@ export class BackupRetrievalWorker { try { encryptedBuffer = Buffer.from(fileContent, 'base64'); } catch (error) { - console.error('Error decoding base64 file content:', error); + this.log(`Error decoding base64 file content: ${error}`, 'error'); return false; } @@ -150,7 +168,7 @@ export class BackupRetrievalWorker { const decipher = crypto.createDecipheriv('aes-256-cbc', this.encryptionKey, this.iv); decryptedContent = Buffer.concat([decipher.update(encryptedBuffer), decipher.final()]); } catch (error) { - console.error('Error decrypting file:', error); + this.log(`Error decrypting file: ${error}`, 'error'); return false; } @@ -161,10 +179,10 @@ export class BackupRetrievalWorker { fs.mkdirSync(dirPath, { recursive: true }); } fs.writeFileSync(fullFilePath, decryptedContent); - console.log(`File saved successfully: ${fullFilePath}`); + this.log(`File saved successfully: ${fullFilePath}`); return true; } catch (error: any) { - console.error(`Error saving file ${relativeFilePath}: ${error.message}`); + this.log(`Error saving file ${relativeFilePath}: ${error.message}`, 'error'); return false; } } @@ -177,7 +195,17 @@ export class BackupRetrievalWorker { clearInterval(idResponseCheck); resolve(this.tcpCommunicator.getLastResult()); } - }, 100); + }, 100); // Check every 100 milliseconds }); } + + // Unified logging function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const prefix = '[BackupRetrievalWorker]'; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } } diff --git a/User/src/helpers/backup_retrieval.ts b/User/src/helpers/backup_retrieval.ts index c661e26..47bfd07 100644 --- a/User/src/helpers/backup_retrieval.ts +++ b/User/src/helpers/backup_retrieval.ts @@ -1,11 +1,11 @@ -import { JsonManager } from './json_manager'; // Assuming this manages JSON configurations +import { JsonManager } from './json_manager'; import { TcpCommunicator } from "./tcp_communicator"; -import { operationCodes } from '../network/operation_codes'; // Assuming this holds operation codes +import { operationCodes } from '../network/operation_codes'; import { parentPort } from 'worker_threads'; import path from 'path'; import fs from 'fs'; import crypto from 'crypto'; -import { ParsedMessage } from "../network/message_handler"; // Import the crypto module for encryption and decryption +import { ParsedMessage } from "../network/message_handler"; export class BackupRetrievalWorker { private userConfig: JsonManager; @@ -23,6 +23,16 @@ export class BackupRetrievalWorker { this.destinationPath = destinationPath; } + // Logging helper function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const prefix = '[BackupRetrievalWorker]'; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } + async start(): Promise { try { const userInfo = await this.userConfig.readValue('user_info'); @@ -49,12 +59,12 @@ export class BackupRetrievalWorker { if (!success) { throw new Error(`Failed to retrieve backup from ${ip}`); } - console.log(`Backup retrieved successfully from ${ip}`); + this.log(`Backup retrieved successfully from ${ip}`); } parentPort?.postMessage({ success: true, message: 'Backup retrieval completed successfully.' }); } catch (error: any) { - console.error('Error in BackupRetrievalWorker:', error); + this.log(`Error in BackupRetrievalWorker: ${error.message}`, 'error'); parentPort?.postMessage({ success: false, message: `A problem occurred: ${error.message}` }); } } @@ -62,19 +72,20 @@ export class BackupRetrievalWorker { private async processBackupForIp(ip: string, userName: string): Promise { this.tcpCommunicator = new TcpCommunicator(ip, this.clientPort); if (!await this.tcpCommunicator.connect()) { + this.log(`Failed to connect to ${ip}`, 'error'); return true; } const backupExists = await this.checkIfBackupExists(userName); if (!backupExists) { - console.log(`No backup found for user ${userName} on IP ${ip}`); + this.log(`No backup found for user ${userName} on IP ${ip}`); await this.tcpCommunicator.disconnect(); return true; } const backupStructure = await this.requestBackupStructure(userName); if (!backupStructure || Object.keys(backupStructure).length === 0) { - console.log(`No files found in backup structure for user ${userName} on IP ${ip}`); + this.log(`No files found in backup structure for user ${userName} on IP ${ip}`); await this.tcpCommunicator.disconnect(); return true; } @@ -151,7 +162,7 @@ export class BackupRetrievalWorker { fs.mkdirSync(dirPath, { recursive: true }); } fs.writeFileSync(fullFilePath, decryptedContent); - console.log(`File saved successfully: ${fullFilePath}`); + this.log(`File saved successfully: ${fullFilePath}`); return true; } catch (error: any) { throw new Error(`Error saving file ${relativeFilePath}: ${error.message}`); diff --git a/User/src/helpers/department_sharer.ts b/User/src/helpers/department_sharer.ts index 7c11662..47bad9e 100644 --- a/User/src/helpers/department_sharer.ts +++ b/User/src/helpers/department_sharer.ts @@ -1,19 +1,19 @@ import fs from 'fs'; import path from 'path'; -import { TcpCommunicator } from './tcp_communicator'; // Using TcpCommunicator instead of TcpClient +import { TcpCommunicator } from './tcp_communicator'; import { operationCodes } from '../network/operation_codes'; -import { JsonManager } from './json_manager'; // Manages JSON configurations -import { MemoryManager } from './memory_manager'; // Manages in-memory data structures +import { JsonManager } from './json_manager'; +import { MemoryManager } from './memory_manager'; import { ParsedMessage } from "../network/message_handler"; export class DepartmentSharer { private userConfig: JsonManager; private applicationInfo: JsonManager; - private memoryManager: MemoryManager; // To read the department files + private memoryManager: MemoryManager; private departmentDirectory: string | null; private readonly clientPort: number; - private isBusy: boolean = false; // Busy flag to prevent simultaneous sharing - private tcpCommunicator: TcpCommunicator | null = null; // For each user connection + private isBusy: boolean = false; + private tcpCommunicator: TcpCommunicator | null = null; constructor( userConfigPath: string, @@ -32,21 +32,20 @@ export class DepartmentSharer { async start(): Promise { setInterval(async () => { if (!this.isBusy) { - this.isBusy = true; + this.log('Start successfully. Sharing files with the department.'); await this.shareFilesWithDepartment(); - this.isBusy = false; } }, 10000); // 10-second interval for testing } // Share files with users in the same department private async shareFilesWithDepartment(): Promise { - console.log('\n\nStarting Department Share Process\n\n'); + this.isBusy = true; // Get the current user's department information const userInfo = await this.userConfig.readValue('user_info'); if (!userInfo || !userInfo.departmentId || !userInfo.name) { - console.error('User information or department ID is missing in the configuration.'); + this.log('User information or department ID is missing in the configuration.', 'error'); return; } @@ -56,27 +55,27 @@ export class DepartmentSharer { // Get the list of active users from applicationInfo const activeUsersId = await this.applicationInfo.readValue('active_users_info'); if (!activeUsersId) { - console.error('No active users found.'); + this.log('No active users found.', 'error'); return; } const activeUsers = await this.memoryManager.retrieveMetaInformation(activeUsersId); if (!activeUsers || activeUsers.length === 0) { - console.error('No active users found.'); + this.log('No active users found.', 'error'); return; } // Filter users who belong to the same department const departmentUsers = activeUsers.filter((user: any) => user.user_info.departmentId === departmentId); if (departmentUsers.length === 0) { - console.log('No users found in the same department.'); + this.log('No users found in the same department.', 'log'); return; } // Get department directory info const departmentData = await this.applicationInfo.readValue('departmentDirectory'); if (!departmentData || !departmentData.path || !departmentData.id) { - console.error('No department directory found.'); + this.log('No department directory found.', 'error'); return; } @@ -85,7 +84,7 @@ export class DepartmentSharer { // Read files from the MemoryManager related to this department const departmentFiles = await this.memoryManager.retrieveMetaInformation(departmentData.id); if (!departmentFiles || !departmentFiles.structure) { - console.error('No files found for this department in the memory manager.'); + this.log('No files found for this department in the memory manager.', 'error'); return; } @@ -114,7 +113,7 @@ export class DepartmentSharer { const response = await this.waitForResponse(); if (!response || response.operationCode !== operationCodes.OK){ - console.error('Failed to clear the department directory.'); + this.log('Failed to clear the department directory.', 'error'); return false; } @@ -124,14 +123,14 @@ export class DepartmentSharer { // Send the files to a user in the department private async sendFilesToUser(files: { [key: string]: string }, userName: string): Promise { if(!this.tcpCommunicator) return; - const unsentFiles = Object.keys(files); // Keep track of unsent files + const unsentFiles = Object.keys(files); for (const fileName of unsentFiles) { const filePath = files[fileName]; // Ensure the file exists before attempting to send if (!fs.existsSync(filePath)) { - console.error(`File not found: ${filePath}`); + this.log(`File not found: ${filePath}`, 'error'); continue; } @@ -144,8 +143,8 @@ export class DepartmentSharer { // Prepare the metaInfo (same structure as FileSharer) const metaInfo = { - userName, // Sender's username - relativeFilePath // Use the relative path to preserve directory structure + userName, + relativeFilePath }; // Send the file @@ -153,7 +152,7 @@ export class DepartmentSharer { const response = await this.waitForResponse(); if (!response || response.operationCode !== operationCodes.OK) { - console.error(`Failed to send file: ${fileName}`); + this.log(`Failed to send file: ${fileName}`, 'error'); return; } @@ -168,9 +167,19 @@ export class DepartmentSharer { if (!this.tcpCommunicator) return null; if (this.tcpCommunicator.hasResponseArrived()) { clearInterval(idResponseCheck); - resolve(this.tcpCommunicator.getLastResult()); // Resolve the response or null if not available + resolve(this.tcpCommunicator.getLastResult()); } - }, 100); // Check every 100 milliseconds if the response has arrived + }, 100); }); } + + // Unified logging function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const prefix = '[DepartmentSharer]'; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } } diff --git a/User/src/helpers/directory_watcher.ts b/User/src/helpers/directory_watcher.ts index b4404b9..a96beaf 100644 --- a/User/src/helpers/directory_watcher.ts +++ b/User/src/helpers/directory_watcher.ts @@ -10,8 +10,9 @@ export class DirectoryWatcher { private applicationInfo: JsonManager; private memoryManager: MemoryManager; private readonly sourceKey: string; - private directoryWatcher: FSWatcher | null; // To store the watcher reference - private totalSize: number; // To store total directory size + private directoryWatcher: FSWatcher | null; + private totalSize: number; + private isBusy: boolean; constructor(memoryManagerPath: string, applicationInfoPath: string, sourceKey: string) { this.sourceKey = sourceKey; @@ -19,14 +20,28 @@ export class DirectoryWatcher { this.memoryManager = new MemoryManager(memoryManagerPath); this.directoryMemoryId = ''; this.directoryPath = ''; - this.directoryWatcher = null; // Initialize with no watcher - this.totalSize = 0; // Initialize size with zero + this.directoryWatcher = null; + this.totalSize = 0; + this.isBusy = false; + } + + // Start the watcher with a busy flag to prevent overlapping operations + async start(): Promise { + setInterval(async () => { + if (!this.isBusy) { + this.isBusy = true; + const initialized = await this.initialize(); + if (initialized) this.log('Directory watcher started successfully.'); + this.isBusy = false; + } + }, 10000); // 10-second interval for testing } // Method to initialize and validate the backup directory async initialize(): Promise { const directoryData = await this.applicationInfo.readValue(this.sourceKey); if (!directoryData) { + this.log('Directory data not found in application info.', 'error'); return false; } @@ -34,7 +49,7 @@ export class DirectoryWatcher { this.directoryMemoryId = directoryData.id; if (!this.directoryMemoryId || !this.directoryPath) { - console.error('Components of entry in \'DirectoryWatcher\' not found.'); + this.log('Components of entry in \'DirectoryWatcher\' not found.', 'error'); await this.applicationInfo.removeValue(this.sourceKey); return false; } @@ -65,7 +80,7 @@ export class DirectoryWatcher { for (const item of items) { const fullPath = path.join(dirPath, item.name); - const stats = await fs.stat(fullPath); // Get stats for each item + const stats = await fs.stat(fullPath); if (item.isDirectory()) { // If it's a directory, recursively build its structure and accumulate size @@ -75,7 +90,7 @@ export class DirectoryWatcher { } else if (item.isFile()) { // If it's a file, store its full path and accumulate size directoryScheme[item.name] = fullPath; - totalSize += stats.size; // Add file size + totalSize += stats.size; } } @@ -85,8 +100,8 @@ export class DirectoryWatcher { // Restart the directory watcher, ensuring any previous watcher is closed private restartWatcher(): void { if (this.directoryWatcher) { - console.log('Stopping existing watcher...'); - this.directoryWatcher.close(); // Stop the existing watcher + this.log('Stopping existing watcher...'); + this.directoryWatcher.close(); } this.startDirectoryWatcher(); @@ -100,7 +115,7 @@ export class DirectoryWatcher { this.directoryWatcher = watch(this.directoryPath, { recursive: true }, async (eventType, filename) => { if (filename) { - console.log(`File change detected: ${eventType} - ${filename}`); + this.log(`File change detected: ${eventType} - ${filename}`); // Rebuild the directory scheme and update memory const result = await this.buildDirectoryScheme(this.directoryPath); this.directoryScheme = result.structure; @@ -111,19 +126,34 @@ export class DirectoryWatcher { totalSize: this.totalSize, }); - console.log('Directory structure and size updated in memory.'); + this.log('Directory structure and size updated in memory.'); } }); - console.log(`Watching for changes in: ${this.directoryPath}`); + this.log(`Watching for changes in: ${this.directoryPath}`); } // Close the directory watcher public closeWatcher(): void { if (this.directoryWatcher) { - console.log(`Stopping watcher for ${this.directoryPath}`); + this.log(`Stopping watcher for ${this.directoryPath}`); this.directoryWatcher.close(); - this.directoryWatcher = null; // Clear the reference after closing + this.directoryWatcher = null; } } + + // Unified logging function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const sourcePrefix = `[DirectoryWatcher] {${this.capitalize(this.sourceKey)}}`; + if (level === 'error') { + console.error(`${sourcePrefix} ${message}`); + } else { + console.log(`${sourcePrefix} ${message}`); + } + } + + // Capitalize the first letter of the sourceKey + private capitalize(str: string): string { + return str.charAt(0).toUpperCase() + str.slice(1); + } } diff --git a/User/src/helpers/file_sharer.ts b/User/src/helpers/file_sharer.ts index 435e021..68e254d 100644 --- a/User/src/helpers/file_sharer.ts +++ b/User/src/helpers/file_sharer.ts @@ -1,10 +1,10 @@ -import {QueueManager} from './queue_manager'; -import {TcpCommunicator} from "./tcp_communicator"; // Updated to use TcpCommunicator -import {operationCodes} from '../network/operation_codes'; import fs from "fs"; import path from "path"; -import {compareFnFileItemTask, FileItemTask} from "../interfaces/file_item_task"; -import {ParsedMessage} from "../network/message_handler"; +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; @@ -28,7 +28,9 @@ export class FileSharer { async start(): Promise { setInterval(async () => { if (!this.isBusy) { // Check if the queue is already being processed + this.log("Start successfully. Processing the queue."); await this.processQueue(); // Process the queue at regular intervals + this.log("Queue processing completed."); } }, 10000); // 10 seconds interval } @@ -36,7 +38,7 @@ export class FileSharer { // Method to process the queue private async processQueue(): Promise { if (this.isBusy) { - console.log("Queue is already being processed. Skipping this interval."); + this.log("Queue is already being processed. Skipping this interval."); return; } @@ -46,15 +48,15 @@ export class FileSharer { const task = this.queueManager.peek(); if (task) { - console.log(task); + this.log(`Processing task for file: ${task.path} to IP: ${task.ip}`); const success = await this.sendFile(task); if (!success) { - console.error(`Failed to send file: ${task.path} to IP: ${task.ip}. Re-adding to queue.`); + 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 { - console.log(`File sent successfully: ${task.path} to IP: ${task.ip}.`); + this.log(`File sent successfully: ${task.path} to IP: ${task.ip}`); this.queueManager.dequeue(); } } @@ -64,11 +66,11 @@ export class FileSharer { // Method to send the file to a specific IP using TcpCommunicator private async sendFile(task: FileSendTask): Promise { - const {ip, path: filePath, userName} = task; + const { ip, path: filePath, userName } = task; // Ensure the file exists before attempting to send if (!fs.existsSync(filePath)) { - console.error(`File not found: ${filePath}`); + this.log(`File not found: ${filePath}`, 'error'); return false; } @@ -86,17 +88,17 @@ export class FileSharer { this.tcpCommunicator = new TcpCommunicator(ip, this.clientPort); if (!await this.tcpCommunicator.connect()) { - console.error(`Failed to connect to IP: ${ip}`); + this.log(`Failed to connect to IP: ${ip}`, 'error'); return false; } - console.log(`Sending file: ${filePath} to IP: ${ip}`); + 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) { - console.error(`Failed to send file: ${filePath} to IP: ${ip}`); + this.log(`Failed to send file: ${filePath} to IP: ${ip}`, 'error'); return false; } @@ -115,4 +117,14 @@ export class FileSharer { }, 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}`); + } + } } diff --git a/User/src/helpers/network_scanner.ts b/User/src/helpers/network_scanner.ts new file mode 100644 index 0000000..238ef3c --- /dev/null +++ b/User/src/helpers/network_scanner.ts @@ -0,0 +1,186 @@ +import {JsonManager} from "./json_manager"; +import {UdpClient} from "../network/udp/udp_client"; +import {parentPort} from "worker_threads"; +import {TcpCommunicator} from "./tcp_communicator"; +import {operationCodes} from "../network/operation_codes"; +import {ParsedMessage} from "../network/message_handler"; + +export class NetworkScanner { + private applicationInfo: JsonManager; + private userConfig: JsonManager; + private readonly udpPort: number; + private readonly tcpPort: number; + private readonly okPage: string; + private readonly errorPage: string; + private readonly databaseResetPage: string; + private appStarted = false; + private intervalIds: NodeJS.Timeout[] = []; + + // Flags to prevent overlapping executions + private ucCheckBusy = false; + private ipLookupBusy = false; + private sendLoginBusy = false; + + constructor(applicationInfoPath: string, userConfigPath: string, udpPort: number, tcpPort: number, okPage: string, errorPage: string, databaseResetPage: string) { + this.applicationInfo = new JsonManager(applicationInfoPath); + this.userConfig = new JsonManager(userConfigPath); + this.udpPort = udpPort; + this.tcpPort = tcpPort; + this.okPage = okPage; + this.errorPage = errorPage; + this.databaseResetPage = databaseResetPage; + + // Start tasks + this.startUCCheck(); + this.startUserIPLookup(); + this.sendLoginRequest(); + } + + // Log helper function for consistent logging format + private log(message: string, level: 'log' | 'error' = 'log', methodName: string = ''): void { + const prefix = `[NetworkScanner${methodName ? `.${methodName}` : ''}]`; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } + + // UC Check Task + private startUCCheck(interval: number = 5000): void { + const intervalId = setInterval(async () => { + if (this.ucCheckBusy) return; + this.ucCheckBusy = true; + + try { + this.log('UC Check running...', 'log', 'startUCCheck'); + const udpClient = new UdpClient(this.udpPort); + const aliveClients = await udpClient.getAliveClients(); + const storedIp = await this.applicationInfo.readValue('serverIp'); + const foundClient = aliveClients.length > 0; + + if (foundClient) { + const ipAddress = aliveClients[0]; // Use the first alive client + + if (!storedIp || storedIp !== ipAddress) { + await this.applicationInfo.writeValue('serverIp', ipAddress); + if (!this.appStarted) { + parentPort?.postMessage({ type: 'changeContent', page: this.okPage }); + } + this.appStarted = true; + } else if (!this.appStarted) { + parentPort?.postMessage({ type: 'changeContent', page: this.okPage }); + this.appStarted = true; + } + } else { + parentPort?.postMessage({ type: 'changeContent', page: this.errorPage }); + } + } catch (err) { + this.log(`Error checking UC: ${err}`, 'error', 'startUCCheck'); + parentPort?.postMessage({ type: 'changeContent', page: this.errorPage }); + } finally { + this.ucCheckBusy = false; + } + }, interval); + + this.intervalIds.push(intervalId); + } + + // IP Lookup Task + private startUserIPLookup(interval: number = 10000): void { + const intervalId = setInterval(async () => { + if (this.ipLookupBusy) return; + this.ipLookupBusy = true; + + try { + this.log('IP Lookup running...', 'log', 'startUserIPLookup'); + const serverIp = await this.applicationInfo.readValue('serverIp'); + const udpClient = new UdpClient(this.udpPort); + const activeIPs = await udpClient.getAliveClients(); + const filteredIPs = activeIPs.filter(ip => ip !== serverIp); + + // Save the filtered IPs to 'users_ip' + await this.applicationInfo.writeValue('users_ip', filteredIPs); + } catch (err) { + this.log(`Error during user IP lookup: ${err}`, 'error', 'startUserIPLookup'); + } finally { + this.ipLookupBusy = false; + } + }, interval); + + this.intervalIds.push(intervalId); + } + + // Login Request Task + private sendLoginRequest(interval: number = 5000): void { + const intervalId = setInterval(async () => { + if (this.sendLoginBusy || this.appStarted) return; + this.sendLoginBusy = true; + + try { + const userInfo = await this.userConfig.readValue('user_info'); + if (!userInfo || !userInfo.email || !userInfo.password) { + this.log("Email or password not found in user config.", 'error', 'sendLoginRequest'); + return; + } + + const app_type = await this.userConfig.readValue('app_type'); + const email = userInfo.email; + const password = userInfo.password; + const serverIp = await this.applicationInfo.readValue('serverIp'); + + if (!serverIp) { + this.log("Server IP not found in application info.", 'error', 'sendLoginRequest'); + return; + } + + const tcpCommunicator = new TcpCommunicator(serverIp, this.tcpPort); + + if (!await tcpCommunicator.connect()) { + this.log("Failed to connect to the server.", 'error', 'sendLoginRequest'); + return; + } + + const metaInfo = { email, password, app_type }; + if (!await tcpCommunicator.sendMessage(operationCodes.LOGIN, metaInfo)) { + this.log("Failed to send login request.", 'error', 'sendLoginRequest'); + await tcpCommunicator.disconnect(); + return; + } + + const response = await this.waitForResponse(tcpCommunicator); + if (response?.operationCode !== operationCodes.OK) { + await this.userConfig.resetFile(); + await this.userConfig.writeValue('app_type', app_type); + parentPort?.postMessage({ type: 'changeContent', page: this.databaseResetPage }); + } + } catch (err) { + this.log(`Error during login request: ${err}`, 'error', 'sendLoginRequest'); + } finally { + this.sendLoginBusy = false; + } + }, interval); + + this.intervalIds.push(intervalId); + } + + // Helper function to wait for a response from the TCP communicator + private async waitForResponse(tcpCommunicator: TcpCommunicator): Promise { + return new Promise((resolve) => { + const checkInterval = setInterval(() => { + if (tcpCommunicator.hasResponseArrived()) { + clearInterval(checkInterval); + resolve(tcpCommunicator.getLastResult()); + } + }, 100); + }); + } + + // Method to stop all intervals (for cleanup if needed) + public stopAllIntervals(): void { + for (const id of this.intervalIds) { + clearInterval(id); + } + this.log("All intervals have been stopped.", 'log', 'stopAllIntervals'); + } +} \ No newline at end of file diff --git a/User/src/helpers/users_info_fetcher.ts b/User/src/helpers/users_info_fetcher.ts index d584152..20c0b24 100644 --- a/User/src/helpers/users_info_fetcher.ts +++ b/User/src/helpers/users_info_fetcher.ts @@ -2,7 +2,7 @@ import { JsonManager } from "./json_manager"; import { MemoryManager } from "./memory_manager"; import { operationCodes } from "../network/operation_codes"; import { TcpCommunicator } from "./tcp_communicator"; -import {ParsedMessage} from "../network/message_handler"; +import { ParsedMessage } from "../network/message_handler"; export class UsersInfoFetcher { private applicationInfo: JsonManager; @@ -32,7 +32,7 @@ export class UsersInfoFetcher { private async initialize() { const usersIps = await this.applicationInfo.readValue('users_ip'); if (!usersIps) { - console.error('No IP addresses found in users_ip'); + this.log('No IP addresses found in users_ip', 'error'); return; } @@ -54,13 +54,13 @@ export class UsersInfoFetcher { for (const ip of usersIps) { this.tcpCommunicator = new TcpCommunicator(ip, this.clientPort); if (!await this.tcpCommunicator.connect()) { - console.error(`Failed to open connection for IP: ${ip}`); + this.log(`Failed to open connection for IP: ${ip}`, 'error'); continue; } if(!await this.tcpCommunicator?.sendMessage(operationCodes.GET_USER_INFORMATION)){ await this.tcpCommunicator.disconnect(); - continue + continue; } // Wait for the response for 10 seconds @@ -96,4 +96,14 @@ export class UsersInfoFetcher { private async updateActiveUsers(userInfo: any[]) { await this.memoryManager.updateMetaInformation(this.memoryId, userInfo); // Update active users in memory } + + // Unified logging function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const prefix = '[UsersInfoFetcher]'; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } } diff --git a/User/src/helpers/worker_manager.ts b/User/src/helpers/worker_manager.ts index ebfd105..f53f43d 100644 --- a/User/src/helpers/worker_manager.ts +++ b/User/src/helpers/worker_manager.ts @@ -22,7 +22,6 @@ export class WorkerManager { this.workers.push(worker); // Store the worker reference worker.on('message', (data) => { - console.log(data); if (data.type === 'changeContent') { this.windowManager.changeContent(data.page); } @@ -43,7 +42,7 @@ export class WorkerManager { }); } - // Start the Connection Pool Worker + // Start the Directories Watcher Worker async startDirectoriesWatchersWorker(memoryManagerPath: string, applicationInfoPath: string): Promise { return new Promise((resolve, reject) => { const worker = new Worker(path.join(this.pathToWorkerDir, 'directories_watcher_worker.js'), { @@ -53,18 +52,18 @@ export class WorkerManager { this.workers.push(worker); // Store the worker reference worker.on('message', (data) => { - console.log('Connection Pool Worker message:', data); + console.log('DirectoriesWatcher message:', data); }); worker.on('error', (err) => { - console.error('Connection Pool Worker error:', err); + console.error('DirectoriesWatcher error:', err); worker.terminate(); this.removeWorker(worker); reject(err); // Reject the promise if there's an error }); worker.on('exit', (code) => { - console.log(`Connection Pool Worker exited with code ${code}`); + console.log(`DirectoriesWatcher exited with code ${code}`); this.removeWorker(worker); // Remove worker reference when it exits resolve(); // Resolve when the worker exits cleanly }); diff --git a/User/src/main/main.ts b/User/src/main/main.ts index 55151f7..02ea963 100644 --- a/User/src/main/main.ts +++ b/User/src/main/main.ts @@ -162,6 +162,7 @@ app.whenReady().then(async () => { workerManager.startNetworkScannerWorker(UDP_PORT, TCP_PORT, 'login', 'uc_not_found', 'reset_database', path.join(pathToJsons, 'userConfig.json'), path.join(pathToJsons, 'application.json')); workerManager.startDirectoriesWatchersWorker(path.join(pathToJsons, 'memory.json'), path.join(pathToJsons, 'application.json')); workerManager.startServersWorker(HOST, UDP_PORT, TCP_PORT); + workerManager.startResourceCoordinatorWorker( path.join(pathToJsons, 'userConfig.json'), path.join(pathToJsons, 'application.json'), @@ -219,6 +220,11 @@ function registerIPCHandlers() { return await windowManager.showFileInExplorer(path); }); + ipcMain.handle('close-announcement-window', async (_event: IpcMainInvokeEvent) => { + if (!windowManager) throw new Error('WindowManager is not initialized.'); + return await windowManager.closeAnnouncementWindow(); + }); + // TcpMethods IPC Handlers ipcMain.handle('open-socket', async (_event: IpcMainInvokeEvent) => { if (!applicationInfo) throw new Error('TcpMethods is not initialized.'); diff --git a/User/src/main/preload.ts b/User/src/main/preload.ts index dae2a06..6437ed7 100644 --- a/User/src/main/preload.ts +++ b/User/src/main/preload.ts @@ -35,6 +35,7 @@ contextBridge.exposeInMainWorld('electronAPI', { selectDirectory: (): Promise => ipcRenderer.invoke('select-directory'), selectFile: (): Promise => ipcRenderer.invoke('select-file'), showFileInExplorer: (path: string): Promise => ipcRenderer.invoke('show-file-in-explorer', path), + closeAnnouncementWindow: (): Promise => ipcRenderer.invoke('close-announcement-window'), // Queue methods addTaskToSendFileQueue: (task: FileItemTask): Promise => ipcRenderer.invoke('add-task-to-send-file-queue', task), diff --git a/User/src/workers/directories_watcher_worker.ts b/User/src/workers/directories_watcher_worker.ts index 9e0138f..a5ba517 100644 --- a/User/src/workers/directories_watcher_worker.ts +++ b/User/src/workers/directories_watcher_worker.ts @@ -7,37 +7,11 @@ const { } = workerData; const backupDirectoryManager = new DirectoryWatcher(memoryManagerPath, applicationInfoPath, 'backupDirectory'); +backupDirectoryManager.start(); + const departmentShareManager = new DirectoryWatcher(memoryManagerPath, applicationInfoPath, 'departmentDirectory'); +departmentShareManager.start(); + const shareFileManager = new DirectoryWatcher(memoryManagerPath, applicationInfoPath, 'shareDirectory'); - -// Backup directory manager check loop -const backupIntervalId = setInterval(async () => { - if (await backupDirectoryManager.initialize()) { - clearInterval(backupIntervalId); // Stop the loop once initialized - console.log('BackupDirectoryManager successfully initialized.'); - } else { - console.log('Retrying BackupDirectoryManager initialization...'); - } -}, 10000); // Check every 60 seconds - - -// Department share manager check loop -const departmentIntervalId = setInterval(async () => { - if (await departmentShareManager.initialize()) { - clearInterval(departmentIntervalId); // Stop the loop once initialized - console.log('DepartmentShareManager successfully initialized.'); - } else { - console.log('Retrying DepartmentShareManager initialization...'); - } -}, 10000); // Check every 60 seconds - -// Department share manager check loop -const shareIntervalId = setInterval(async () => { - if (await shareFileManager.initialize()) { - clearInterval(shareIntervalId); // Stop the loop once initialized - console.log('DepartmentShareManager successfully initialized.'); - } else { - console.log('Retrying DepartmentShareManager initialization...'); - } -}, 10000); // Check every 60 seconds +shareFileManager.start(); diff --git a/User/src/workers/network_scanner_worker.ts b/User/src/workers/network_scanner_worker.ts index f86d115..c22db64 100644 --- a/User/src/workers/network_scanner_worker.ts +++ b/User/src/workers/network_scanner_worker.ts @@ -1,14 +1,10 @@ -import {parentPort, workerData} from 'worker_threads'; -import {JsonManager} from '../helpers/json_manager'; -import {UdpClient} from '../network/udp/udp_client'; -import {TcpCommunicator} from "../helpers/tcp_communicator"; -import {operationCodes} from "../network/operation_codes"; -import {ParsedMessage} from "../network/message_handler"; +import { parentPort, workerData } from 'worker_threads'; +import { NetworkScanner } from '../helpers/network_scanner'; // Define the structure of workerData interface WorkerData { udpPort: number; - tcpPort: number + tcpPort: number; okPage: string; errorPage: string; databaseResetPage: string; @@ -17,151 +13,7 @@ interface WorkerData { } // Extract the data passed to the worker -const {udpPort, tcpPort, okPage, errorPage, databaseResetPage, userConfigPath, applicationInfoPath}: WorkerData = workerData; +const { udpPort, tcpPort, okPage, errorPage, databaseResetPage, userConfigPath, applicationInfoPath }: WorkerData = workerData; -// Create a JsonManager instance for application info -const applicationInfo = new JsonManager(applicationInfoPath); -const userConfig = new JsonManager(userConfigPath); - -let appStarted = false; -let intervalIds: NodeJS.Timeout[] = []; // Store interval IDs for future clearing - -// Flags to prevent overlapping executions -let ucCheckBusy = false; -let ipLookupBusy = false; -let sendLoginBusy = false; - -// Function to schedule the UC check task with dynamic UDP client creation -function startUCCheck(udpPort: number, okPage: string, errorPage: string, interval: number = 5000): void { - const intervalId = setInterval(async () => { - if (ucCheckBusy) return; // If already running, skip this iteration - ucCheckBusy = true; // Mark as busy - - try { - console.log('UC Check running...'); - const udpClient = new UdpClient(udpPort); // Create UdpClient with the provided port - const aliveClients = await udpClient.getAliveClients(); - const storedIp = await applicationInfo.readValue('serverIp'); - const foundClient = aliveClients.length > 0; - - if (foundClient) { - const ipAddress = aliveClients[0]; // Just using the first alive client - - if (!storedIp || storedIp !== ipAddress) { - await applicationInfo.writeValue('serverIp', ipAddress); - if (!appStarted) { - parentPort?.postMessage({type: 'changeContent', page: okPage}); - } - appStarted = true; - } else if (!appStarted) { - parentPort?.postMessage({type: 'changeContent', page: okPage}); - appStarted = true; - } - } else { - parentPort?.postMessage({type: 'changeContent', page: errorPage}); - } - } catch (err) { - console.error('Error checking UC:', err); - parentPort?.postMessage({type: 'changeContent', page: errorPage}); - } finally { - ucCheckBusy = false; // Mark as not busy - } - }, interval); - - intervalIds.push(intervalId); -} - -// Function to schedule the IP lookup task, storing the active addresses in memory -function startUserIPLookup(udpPort: number, interval: number = 10000): void { - const intervalId = setInterval(async () => { - if (ipLookupBusy) return; // If already running, skip this iteration - ipLookupBusy = true; // Mark as busy - - try { - console.log('IP Lookup running...'); - const serverIp = await applicationInfo.readValue('serverIp'); - const udpClient = new UdpClient(udpPort); // Create a UDP client with the provided port - const activeIPs = await udpClient.getAliveClients(); // Get the list of active IPs - - // Filter out the serverIp from the list of active clients - const filteredIPs = activeIPs.filter(ip => ip !== serverIp); - - // Save the filtered IPs to 'users_ip' - await applicationInfo.writeValue('users_ip', filteredIPs); - } catch (err) { - console.error('Error during user IP lookup:', err); - } finally { - ipLookupBusy = false; // Mark as not busy - } - }, interval); - - intervalIds.push(intervalId); -} - -function sendLoginRequest(databaseResetPage: string, interval: number = 5000): void { - // Read user_info from userConfig for email and password - const intervalId = setInterval(async () => { - if (sendLoginBusy && !appStarted) return; - sendLoginBusy = true; - - const userInfo = await userConfig.readValue('user_info'); - if (!userInfo || !userInfo.email || !userInfo.password) { - console.error("Email or password not found in user config."); - return; - } - - const app_type = await userConfig.readValue('app_type'); - - const email = userInfo.email; - const password = userInfo.password; - - // Initialize the TCP communicator with the server IP from applicationInfo - const serverIp = await applicationInfo.readValue('serverIp'); - if (!serverIp) { - console.error("Server IP not found in application info."); - return; - } - - const tcpCommunicator = new TcpCommunicator(serverIp, tcpPort); - - if (!await tcpCommunicator.connect()) { - console.error("Failed to connect to the server."); - return; - } - - // Prepare the login request data - const metaInfo = {email, password, app_type}; - if (!await tcpCommunicator.sendMessage(operationCodes.LOGIN, metaInfo)) { - console.error("Failed to send login request."); - await tcpCommunicator.disconnect(); - return; - } - - // Await and process the response - const response = await waitForResponse(tcpCommunicator); - if (response?.operationCode !== operationCodes.OK) { - await userConfig.resetFile(); - await userConfig.writeValue('app_type', app_type); - parentPort?.postMessage({type: 'changeContent', page: databaseResetPage}); - return; - } - }, interval) - intervalIds.push(intervalId); // Store the interval ID for later clearing if needed -} - -// Helper function to wait for a response -async function waitForResponse(tcpCommunicator: TcpCommunicator): Promise { - return new Promise((resolve) => { - const checkInterval = setInterval(() => { - if (tcpCommunicator.hasResponseArrived()) { - clearInterval(checkInterval); - resolve(tcpCommunicator.getLastResult()); - } - }, 100); - }); -} - -// Start the UC Check and User IP Lookup tasks -startUCCheck(udpPort, okPage, errorPage); -startUserIPLookup(udpPort); -sendLoginRequest(databaseResetPage); +// Start the NetworkScanner instance +const networkScanner = new NetworkScanner(applicationInfoPath, userConfigPath, udpPort, tcpPort, okPage, errorPage, databaseResetPage); diff --git a/User/src/workers/resource_coordinator_worker.ts b/User/src/workers/resource_coordinator_worker.ts index c92c215..922c59b 100644 --- a/User/src/workers/resource_coordinator_worker.ts +++ b/User/src/workers/resource_coordinator_worker.ts @@ -8,45 +8,15 @@ import {DepartmentSharer} from "../helpers/department_sharer"; const { usersConfigPath, applicationInfoPath, memoryManagerPath, queueManagerPath, tcpPort } = workerData; const usersInfoFetcher = new UsersInfoFetcher(applicationInfoPath, memoryManagerPath, tcpPort); -usersInfoFetcher.start() - .then(() => { - console.log('Users Info Fetcher started successfully'); - }) - .catch((error: any) => { - console.error('Error starting Users Info Fetcher:', error); - }); +usersInfoFetcher.start(); -const backupManager = new BackupRetrievalWorker( - usersConfigPath, - applicationInfoPath, - memoryManagerPath, - tcpPort -); - -backupManager.start() - .then(() => { - console.log('Backup Manager started successfully'); - }) - .catch((error: any) => { - console.error('Error starting Backup Manager:', error); - }); +const backupManager = new BackupRetrievalWorker(usersConfigPath, applicationInfoPath, memoryManagerPath, tcpPort); +backupManager.start(); const fileSharer = new FileSharer(queueManagerPath, tcpPort); -fileSharer.start() - .then(() => { - console.log('File Sharer started successfully'); - }) - .catch((error: any) => { - console.error('Error starting File Sharer:', error); - }); +fileSharer.start(); const departmentSharer = new DepartmentSharer(usersConfigPath, applicationInfoPath, memoryManagerPath, tcpPort); -departmentSharer.start() - .then(() => { - console.log('Department Sharer started successfully'); - }) - .catch((error: any) => { - console.error('Error starting Department Sharer:', error); - }); +departmentSharer.start();