diff --git a/User/package.json b/User/package.json index 2af95d9..f4192bb 100644 --- a/User/package.json +++ b/User/package.json @@ -6,10 +6,10 @@ "scripts": { "clean": "del-cli dist && del-cli out", "build-dist": "tsc && copyfiles -u 1 'src/**/*' dist", - "start-dev": "tsc && copyfiles -u 1 'src/**/*' dist && electron dist/main/main.js", - "start": "npm run clean && npm run build-dist && electron-forge start", - "package": "npm run clean && npm run build-dist && electron-forge package", - "make": "npm run clean && npm run build-dist && electron-forge make" + "start-dev": "tsc && copyfiles -u 1 'src/**/*' dist && electron dist/main/main.js -- --expose-gc", + "start": "npm run clean && npm run build-dist && electron-forge start -- --expose-gc", + "package": "npm run clean && npm run build-dist && electron-forge package -- --expose-gc", + "make": "npm run clean && npm run build-dist && electron-forge make -- --expose-gc" }, "main": "dist/main/main.js", "author": "Cerbu Andrei - Mihnea", diff --git a/User/src/helpers/backup_manager.ts b/User/src/helpers/backup_manager.ts index d5ae720..0868cf5 100644 --- a/User/src/helpers/backup_manager.ts +++ b/User/src/helpers/backup_manager.ts @@ -5,7 +5,6 @@ import { MemoryManager } from './memory_manager'; import { JsonManager } from './json_manager'; import { TcpCommunicator } from './tcp_communicator'; import { operationCodes } from '../network/operation_codes'; -import { parentPort } from 'worker_threads'; import { ParsedMessage } from "../network/message_handler"; export class BackupManager { @@ -143,9 +142,9 @@ export class BackupManager { } if (unsentFiles.length > 0) { - parentPort?.postMessage({ success: false, message: 'Backup could not be completed for all files', unsentFiles }); + process.send?.({type: 'log', message: 'Backup could not be completed for all files'}); } else { - parentPort?.postMessage({ success: true, message: 'Backup completed successfully' }); + process.send?.({type: 'log', message: 'Backup completed successfully' }); } } diff --git a/User/src/helpers/backup_retrieval.ts b/User/src/helpers/backup_retrieval.ts index f06945d..43ef3d1 100644 --- a/User/src/helpers/backup_retrieval.ts +++ b/User/src/helpers/backup_retrieval.ts @@ -1,7 +1,6 @@ import { JsonManager } from './json_manager'; import { TcpCommunicator } from "./tcp_communicator"; import { operationCodes } from '../network/operation_codes'; -import { parentPort } from 'worker_threads'; import path from 'path'; import fs from 'fs'; import crypto from 'crypto'; @@ -62,10 +61,10 @@ export class BackupRetrievalWorker { this.log(`Backup retrieved successfully from ${ip}`); } - parentPort?.postMessage({ success: true, message: 'Backup retrieval completed successfully.' }); + process.send?.({ type: 'log', message: 'Backup retrieval completed successfully.' }); } catch (error: any) { this.log(`Error in BackupRetrievalWorker: ${error.message}`, 'error'); - parentPort?.postMessage({ success: false, message: `A problem occurred: ${error.message}` }); + process.send?.({ type: 'log', message: `A problem occurred: ${error.message}` }); } if (global.gc) { diff --git a/User/src/helpers/network_scanner.ts b/User/src/helpers/network_scanner.ts index 238ef3c..926f274 100644 --- a/User/src/helpers/network_scanner.ts +++ b/User/src/helpers/network_scanner.ts @@ -1,6 +1,5 @@ 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"; @@ -65,19 +64,19 @@ export class NetworkScanner { if (!storedIp || storedIp !== ipAddress) { await this.applicationInfo.writeValue('serverIp', ipAddress); if (!this.appStarted) { - parentPort?.postMessage({ type: 'changeContent', page: this.okPage }); + process.send?.({ type: 'changeContent', page: this.okPage }); } this.appStarted = true; } else if (!this.appStarted) { - parentPort?.postMessage({ type: 'changeContent', page: this.okPage }); + process.send?.({ type: 'changeContent', page: this.okPage }); this.appStarted = true; } } else { - parentPort?.postMessage({ type: 'changeContent', page: this.errorPage }); + process.send?.({ type: 'changeContent', page: this.errorPage }); } } catch (err) { this.log(`Error checking UC: ${err}`, 'error', 'startUCCheck'); - parentPort?.postMessage({ type: 'changeContent', page: this.errorPage }); + process.send?.({ type: 'changeContent', page: this.errorPage }); } finally { this.ucCheckBusy = false; } @@ -152,7 +151,7 @@ export class NetworkScanner { if (response?.operationCode !== operationCodes.OK) { await this.userConfig.resetFile(); await this.userConfig.writeValue('app_type', app_type); - parentPort?.postMessage({ type: 'changeContent', page: this.databaseResetPage }); + process.send?.({ type: 'changeContent', page: this.databaseResetPage }); } } catch (err) { this.log(`Error during login request: ${err}`, 'error', 'sendLoginRequest'); diff --git a/User/src/helpers/worker_manager.ts b/User/src/helpers/worker_manager.ts index 3e0095e..3f5e066 100644 --- a/User/src/helpers/worker_manager.ts +++ b/User/src/helpers/worker_manager.ts @@ -1,174 +1,97 @@ -import { Worker } from 'worker_threads'; +import { fork, ChildProcess } from 'child_process'; import path from 'path'; -import {WindowManager} from "./window_manager"; +import { WindowManager } from "./window_manager"; export class WorkerManager { private readonly pathToWorkerDir: string; - private windowManager: WindowManager - private workers: Worker[]; // Array to store running workers + private windowManager: WindowManager; + private workers: ChildProcess[]; // Array to store running child processes constructor(pathToWorkerDir: string, windowManager: WindowManager) { this.pathToWorkerDir = pathToWorkerDir; this.windowManager = windowManager; - this.workers = []; // Initialize the array to store workers + this.workers = []; // Initialize the array to store child processes } async startNetworkScannerWorker(udpPort: number, tcpPort: number, okPage: string, errorPage: string, databaseResetPage: string, userConfigPath: string, applicationInfoPath: string): Promise { + return this.startForkedWorker('network_scanner_worker.js', { + UDP_PORT: udpPort.toString(), + TCP_PORT: tcpPort.toString(), + OK_PAGE: okPage, + ERROR_PAGE: errorPage, + DATABASE_RESET_PAGE: databaseResetPage, + USER_CONFIG_PATH: userConfigPath, + APPLICATION_INFO_PATH: applicationInfoPath + }); + } + + async startDirectoriesWatchersWorker(memoryManagerPath: string, applicationInfoPath: string): Promise { + return this.startForkedWorker('directories_watcher_worker.js', { + MEMORY_MANAGER_PATH: memoryManagerPath, + APPLICATION_INFO_PATH: applicationInfoPath + }); + } + + async startServersWorker(host: string, udpPort: number, tcpPort: number): Promise { + return this.startForkedWorker('servers_worker.js', { + HOST: host, + USER_UDP_PORT: udpPort.toString(), + USER_TCP_PORT: tcpPort.toString() + }); + } + + async startResourceCoordinatorWorker(usersConfigPath: string, applicationInfoPath: string, memoryManagerPath: string, queueManagerPath: string, tcpPort: number): Promise { + return this.startForkedWorker('resource_coordinator_worker.js', { + USERS_CONFIG_PATH: usersConfigPath, + APPLICATION_INFO_PATH: applicationInfoPath, + MEMORY_MANAGER_PATH: memoryManagerPath, + QUEUE_MANAGER_PATH: queueManagerPath, + TCP_PORT: tcpPort.toString() + }); + } + + async startBackupRetrievalWorker(userConfigPath: string, applicationInfoPath: string, clientPort: number, destinationPath: string): Promise { + return this.startForkedWorker('backup_retrieval_worker.js', { + USER_CONFIG_PATH: userConfigPath, + APPLICATION_INFO_PATH: applicationInfoPath, + CLIENT_PORT: clientPort.toString(), + DESTINATION_PATH: destinationPath + }); + } + + private async startForkedWorker(scriptName: string, envData: { [key: string]: string }): Promise { return new Promise((resolve, reject) => { - const worker = new Worker(path.join(this.pathToWorkerDir, 'network_scanner_worker.js', ), { - execArgv: ['--max-old-space-size=4096'], - workerData: { udpPort, tcpPort, okPage, errorPage, databaseResetPage, userConfigPath, applicationInfoPath }, // Pass necessary data to the worker + const worker = fork(path.join(this.pathToWorkerDir, scriptName), { + execArgv: ['--max-old-space-size=4096'], // Set memory limit for the forked process + env: { ...process.env, ...envData } // Merge environment variables }); this.workers.push(worker); // Store the worker reference - worker.on('message', (data) => { - if (data.type === 'changeContent') { - this.windowManager.changeContent(data.page); + worker.on('message', (data: unknown) => { + const message = data as { type: string, page?: string, message?: string }; // Type casting for message + + if (message.type === 'changeContent' && message.page) { + this.windowManager.changeContent(message.page); + } else if (message.type === 'showAlert' && message.message) { + this.windowManager.showAlert(message.message); + } else { + console.log(`${scriptName} message:`, message); } }); worker.on('error', (err) => { - console.error('Network Scanner Worker error:', err); - worker.terminate(); + console.error(`${scriptName} error:`, err); + worker.kill(); this.removeWorker(worker); - reject(err); // Reject the promise if there's an error + reject(err); }); worker.on('exit', (code) => { - console.log(`Network Scanner Worker exited with code ${code}`); - this.removeWorker(worker); // Remove worker reference when it exits - resolve(); // Resolve when the worker exits cleanly - }); - }); - } - - // 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'), { - execArgv: ['--max-old-space-size=4096'], - workerData: { memoryManagerPath, applicationInfoPath }, // Pass the port to the worker - }); - - this.workers.push(worker); // Store the worker reference - - worker.on('message', (data) => { - console.log('DirectoriesWatcher message:', data); - }); - - worker.on('error', (err) => { - console.error('DirectoriesWatcher error:', err); - worker.terminate(); + console.log(`${scriptName} exited with code ${code}`); this.removeWorker(worker); - reject(err); // Reject the promise if there's an error - }); - - worker.on('exit', (code) => { - console.log(`DirectoriesWatcher exited with code ${code}`); - this.removeWorker(worker); // Remove worker reference when it exits - resolve(); // Resolve when the worker exits cleanly - }); - }); - } - - // Start the Servers Worker (UDP and TCP servers) - async startServersWorker(host: string, udpPort: number, tcpPort: number): Promise { - return new Promise((resolve, reject) => { - const worker = new Worker(path.join(this.pathToWorkerDir, 'servers_worker.js'), { - execArgv: ['--max-old-space-size=4096'], - workerData: { HOST: host, USER_UDP_PORT: udpPort, USER_TCP_PORT: tcpPort }, // Pass host and ports to the worker - }); - - this.workers.push(worker); // Store the worker reference - - worker.on('message', (data) => { - console.log('Servers Worker message:', data); - }); - - worker.on('error', (err) => { - console.error('Servers Worker error:', err); - worker.terminate(); - this.removeWorker(worker); - reject(err); // Reject the promise if there's an error - }); - - worker.on('exit', (code) => { - console.log(`Servers Worker exited with code ${code}`); - this.removeWorker(worker); // Remove worker reference when it exits - resolve(); // Resolve when the worker exits cleanly - }); - }); - } - - // Start the Users Info Worker - async startResourceCoordinatorWorker(usersConfigPath: string, applicationInfoPath: string, memoryManagerPath: string, queueManagerPath: string, tcpPort: number): Promise { - return new Promise((resolve, reject) => { - const worker = new Worker(path.join(this.pathToWorkerDir, 'resource_coordinator_worker.js'), { - execArgv: ['--max-old-space-size=4096'], - workerData: { - usersConfigPath, - applicationInfoPath, - memoryManagerPath, - queueManagerPath, - tcpPort - }, // Pass necessary parameters to the worker - }); - - this.workers.push(worker); // Store the worker reference - - worker.on('message', (data) => { - console.log('Users Info Worker message:', data); - }); - - worker.on('error', (err) => { - console.error('Users Info Worker error:', err); - worker.terminate(); - this.removeWorker(worker); - reject(err); // Reject the promise if there's an error - }); - - worker.on('exit', (code) => { - console.log(`Users Info Worker exited with code ${code}`); - this.removeWorker(worker); // Remove worker reference when it exits - resolve(); // Resolve when the worker exits cleanly - }); - }); - } - - // Start the Backup Retrieval Worker - async startBackupRetrievalWorker( - userConfigPath: string, - applicationInfoPath: string, - clientPort: number, - destinationPath: string - ): Promise { - return new Promise(async (resolve, reject) => { - const worker = new Worker(path.join(this.pathToWorkerDir, 'backup_retrieval_worker.js'), { - execArgv: ['--max-old-space-size=4096'], - workerData: { userConfigPath, applicationInfoPath, clientPort, destinationPath }, // Pass parameters to the worker - }); - - this.workers.push(worker); // Store the worker reference - - worker.on('message', async (data) => { - console.log('Backup Retrieval Worker message:', data); - await new Promise((resolve) => setTimeout(resolve, 3000)); // Wait for 1 second - await this.windowManager.changeContent('main_menu'); - await this.windowManager.showAlert(data.message); - }); - - worker.on('error', (err) => { - console.error('Backup Retrieval Worker error:', err); - worker.terminate(); - this.removeWorker(worker); - reject(err); // Reject the promise if there's an error - }); - - worker.on('exit', (code) => { - console.log(`Backup Retrieval Worker exited with code ${code}`); - this.removeWorker(worker); // Remove worker reference when it exits - resolve(); // Resolve when the worker exits cleanly + if (code === 0) resolve(); + else reject(new Error(`${scriptName} exited with code ${code}`)); }); }); } @@ -176,15 +99,15 @@ export class WorkerManager { // Close all running workers closeAllWorkers(): void { console.log('Terminating all running workers...'); - this.workers.forEach(worker => worker.terminate()); // Terminate each worker - this.workers = []; // Clear the array after terminating all workers + this.workers.forEach(worker => worker.kill()); + this.workers = []; } // Helper method to remove a worker from the workers array when it exits - private removeWorker(worker: Worker): void { + private removeWorker(worker: ChildProcess): void { const index = this.workers.indexOf(worker); if (index > -1) { - this.workers.splice(index, 1); // Remove the worker from the array + this.workers.splice(index, 1); } } } diff --git a/User/src/interfaces/worker_message.ts b/User/src/interfaces/worker_message.ts new file mode 100644 index 0000000..b72d132 --- /dev/null +++ b/User/src/interfaces/worker_message.ts @@ -0,0 +1,6 @@ +// Define a type for the message structure +interface WorkerMessage { + type: 'changeContent' | 'showAlert' | 'log'; + page?: string; + message?: string; +} diff --git a/User/src/workers/backup_retrieval_worker.ts b/User/src/workers/backup_retrieval_worker.ts index 337a4a6..fa58038 100644 --- a/User/src/workers/backup_retrieval_worker.ts +++ b/User/src/workers/backup_retrieval_worker.ts @@ -1,18 +1,20 @@ -import { workerData, parentPort } from 'worker_threads'; -import { BackupRetrievalWorker} from '../helpers/backup_retrieval'; // Assuming the class is in the same folder +import { BackupRetrievalWorker } from '../helpers/backup_retrieval'; +import dotenv from 'dotenv'; -// Destructure the data passed from the WorkerManager -const { - userConfigPath, - applicationInfoPath, - clientPort, - destinationPath -}: { - userConfigPath: string, - applicationInfoPath: string, - clientPort: number, - destinationPath: string -} = workerData; +// Load environment variables from .env file if it exists +dotenv.config(); + +// Retrieve configuration from environment variables +const userConfigPath = process.env.USER_CONFIG_PATH as string; +const applicationInfoPath = process.env.APPLICATION_INFO_PATH as string; +const clientPort = Number(process.env.CLIENT_PORT); +const destinationPath = process.env.DESTINATION_PATH as string; + +// Validate that all required environment variables are present +if (!userConfigPath || !applicationInfoPath || !clientPort || !destinationPath) { + console.error('Error: Missing required environment variables.'); + process.exit(1); +} // Initialize the BackupRetrievalWorker const backupRetrievalWorker = new BackupRetrievalWorker( diff --git a/User/src/workers/directories_watcher_worker.ts b/User/src/workers/directories_watcher_worker.ts index a5ba517..288dd5c 100644 --- a/User/src/workers/directories_watcher_worker.ts +++ b/User/src/workers/directories_watcher_worker.ts @@ -1,11 +1,20 @@ -import {DirectoryWatcher} from "../helpers/directory_watcher"; -import {workerData} from "worker_threads"; +import { DirectoryWatcher } from "../helpers/directory_watcher"; +import dotenv from 'dotenv'; -const { - memoryManagerPath, - applicationInfoPath, -} = workerData; +// Load environment variables from .env file if it exists +dotenv.config(); +// Retrieve configuration from environment variables +const memoryManagerPath = process.env.MEMORY_MANAGER_PATH as string; +const applicationInfoPath = process.env.APPLICATION_INFO_PATH as string; + +// Validate that all required environment variables are present +if (!memoryManagerPath || !applicationInfoPath) { + console.error('Error: Missing required environment variables.'); + process.exit(1); +} + +// Initialize and start DirectoryWatcher instances const backupDirectoryManager = new DirectoryWatcher(memoryManagerPath, applicationInfoPath, 'backupDirectory'); backupDirectoryManager.start(); @@ -14,4 +23,3 @@ departmentShareManager.start(); const shareFileManager = new DirectoryWatcher(memoryManagerPath, applicationInfoPath, 'shareDirectory'); shareFileManager.start(); - diff --git a/User/src/workers/network_scanner_worker.ts b/User/src/workers/network_scanner_worker.ts index c22db64..ee86577 100644 --- a/User/src/workers/network_scanner_worker.ts +++ b/User/src/workers/network_scanner_worker.ts @@ -1,19 +1,22 @@ -import { parentPort, workerData } from 'worker_threads'; +import { parentPort } from 'worker_threads'; 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, tcpPort, okPage, errorPage, databaseResetPage, userConfigPath, applicationInfoPath }: WorkerData = workerData; +// Extract data from environment variables +const udpPort = parseInt(process.env.UDP_PORT || '0', 10); +const tcpPort = parseInt(process.env.TCP_PORT || '0', 10); +const okPage = process.env.OK_PAGE || ''; +const errorPage = process.env.ERROR_PAGE || ''; +const databaseResetPage = process.env.DATABASE_RESET_PAGE || ''; +const userConfigPath = process.env.USER_CONFIG_PATH || ''; +const applicationInfoPath = process.env.APPLICATION_INFO_PATH || ''; // Start the NetworkScanner instance -const networkScanner = new NetworkScanner(applicationInfoPath, userConfigPath, udpPort, tcpPort, okPage, errorPage, databaseResetPage); +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 1760ff0..036d79e 100644 --- a/User/src/workers/resource_coordinator_worker.ts +++ b/User/src/workers/resource_coordinator_worker.ts @@ -1,11 +1,14 @@ -import { workerData } from 'worker_threads'; import { UsersInfoFetcher } from '../helpers/users_info_fetcher'; -import {BackupManager} from "../helpers/backup_manager"; -import {FileSharer} from "../helpers/file_sharer"; -import {DepartmentSharer} from "../helpers/department_sharer"; +import { BackupManager } from '../helpers/backup_manager'; +import { FileSharer } from '../helpers/file_sharer'; +import { DepartmentSharer } from '../helpers/department_sharer'; -// Destructure the required information from workerData -const { usersConfigPath, applicationInfoPath, memoryManagerPath, queueManagerPath, tcpPort } = workerData; +// Retrieve data from environment variables +const usersConfigPath = process.env.USERS_CONFIG_PATH || ''; +const applicationInfoPath = process.env.APPLICATION_INFO_PATH || ''; +const memoryManagerPath = process.env.MEMORY_MANAGER_PATH || ''; +const queueManagerPath = process.env.QUEUE_MANAGER_PATH || ''; +const tcpPort = parseInt(process.env.TCP_PORT || '0', 10); const usersInfoFetcher = new UsersInfoFetcher(applicationInfoPath, memoryManagerPath, tcpPort); usersInfoFetcher.start(); @@ -16,7 +19,5 @@ backupManager.start(); const fileSharer = new FileSharer(queueManagerPath, tcpPort); fileSharer.start(); - const departmentSharer = new DepartmentSharer(usersConfigPath, applicationInfoPath, memoryManagerPath, tcpPort); departmentSharer.start(); - diff --git a/User/src/workers/servers_worker.ts b/User/src/workers/servers_worker.ts index 4e6f4b6..40bb6e7 100644 --- a/User/src/workers/servers_worker.ts +++ b/User/src/workers/servers_worker.ts @@ -1,14 +1,17 @@ -import {UdpServer} from "../network/udp/udp_server"; -import {TcpServer} from "../network/tcp/tcp_server"; -import {workerData} from "worker_threads"; +import { UdpServer } from "../network/udp/udp_server"; +import { TcpServer } from "../network/tcp/tcp_server"; let udpServer: UdpServer | null = null; let tcpServer: TcpServer | null = null; -const {USER_UDP_PORT, USER_TCP_PORT, HOST} = workerData; +// Retrieve data from environment variables +const USER_UDP_PORT = parseInt(process.env.USER_UDP_PORT || '0', 10); +const USER_TCP_PORT = parseInt(process.env.USER_TCP_PORT || '0', 10); +const HOST = process.env.HOST || ''; +// Initialize and start the servers udpServer = new UdpServer(HOST, USER_UDP_PORT); udpServer.start(); tcpServer = new TcpServer(HOST, USER_TCP_PORT); -tcpServer.start(); \ No newline at end of file +tcpServer.start();