network chunk v20

This commit is contained in:
andrei-mihnea-cerbu
2024-11-13 17:23:21 +02:00
parent f95b67f93d
commit 9baec7a7cb
41 changed files with 714 additions and 392 deletions
+11
View File
@@ -23,6 +23,7 @@
"@types/ping": "^0.4.4",
"@types/proper-lockfile": "^4.1.4",
"@types/uuid": "^10.0.0",
"check-disk-space": "^3.4.0",
"copyfiles": "^2.4.1",
"del-cli": "^5.0.0",
"electron": "^33.0.2",
@@ -1489,6 +1490,16 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/check-disk-space": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/check-disk-space/-/check-disk-space-3.4.0.tgz",
"integrity": "sha512-drVkSqfwA+TvuEhFipiR1OC9boEGZL5RrWvVsOthdcvQNXyCCuKkEiTOTXZ7qxSf/GLwq4GvzfrQD/Wz325hgw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=16"
}
},
"node_modules/chownr": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+1
View File
@@ -29,6 +29,7 @@
"@types/ping": "^0.4.4",
"@types/proper-lockfile": "^4.1.4",
"@types/uuid": "^10.0.0",
"check-disk-space": "^3.4.0",
"copyfiles": "^2.4.1",
"del-cli": "^5.0.0",
"electron": "^33.0.2",
+26 -4
View File
@@ -2,13 +2,14 @@ import { JsonManager } from './json_manager'; // Assuming this manages JSON conf
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";
import { ParsedMessage } from "../network/message_handler";
export class AnnouncementSender {
private applicationInfo: JsonManager;
private readonly clientPort: number;
private message: string = '';
private tcpCommunicator: TcpCommunicator | null = null;
private stopRequested: boolean = false;
constructor(applicationInfoPath: string, clientPort: number) {
this.applicationInfo = new JsonManager(applicationInfoPath);
@@ -18,6 +19,8 @@ export class AnnouncementSender {
async start(message: string): Promise<void> {
console.log('AnnouncementWorker started.');
this.message = message;
this.stopRequested = false;
try {
const activeUsersIp = await this.applicationInfo.readValue('users_ip');
if (!activeUsersIp || !activeUsersIp.length) {
@@ -25,6 +28,11 @@ export class AnnouncementSender {
}
for (const ip of activeUsersIp) {
if (this.stopRequested) {
console.log('AnnouncementWorker stopped.');
break;
}
const success = await this.sendAnnouncementToIp(ip);
if (!success) {
throw new Error(`Failed to send announcement to all users.`);
@@ -32,15 +40,24 @@ export class AnnouncementSender {
console.log(`Announcement sent and confirmed successfully from ${ip}`);
}
parentPort?.postMessage({ success: true, message: 'Announcement sent to all active users successfully.' });
process.send?.({ type: 'showAlert', 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}` });
process.send?.({ type: 'shotAlert', message: `A problem occurred: ${error.message}` });
}
console.log('AnnouncementWorker finished.');
}
async stop(): Promise<void> {
console.log('Stopping AnnouncementWorker...');
this.stopRequested = true;
if (this.tcpCommunicator) {
await this.tcpCommunicator.disconnect();
}
console.log('AnnouncementWorker stopped.');
}
private async sendAnnouncementToIp(ip: string): Promise<boolean> {
this.tcpCommunicator = new TcpCommunicator(ip, this.clientPort);
if (!await this.tcpCommunicator.connect()) {
@@ -73,7 +90,12 @@ export class AnnouncementSender {
private async waitForResponse(): Promise<ParsedMessage | null> {
return new Promise((resolve) => {
const idResponseCheck = setInterval(async () => {
if (!this.tcpCommunicator) return null;
if (this.stopRequested || !this.tcpCommunicator) {
clearInterval(idResponseCheck);
resolve(null);
return;
}
if (this.tcpCommunicator.hasResponseArrived()) {
clearInterval(idResponseCheck);
resolve(this.tcpCommunicator.getLastResult());
+26 -5
View File
@@ -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 {
@@ -15,6 +14,8 @@ export class BackupManager {
private userConfig: JsonManager;
private readonly clientPort: number;
private isBusy: boolean = false;
private intervalId: NodeJS.Timeout | null = null;
private stopRequested: boolean = false;
constructor(userConfigPath: string, applicationInfoPath: string, memoryManagerPath: string, clientPort: number) {
this.applicationInfo = new JsonManager(applicationInfoPath);
@@ -24,12 +25,16 @@ export class BackupManager {
}
async start(): Promise<void> {
setInterval(async () => {
if (!this.isBusy) {
this.intervalId = setInterval(async () => {
if (!this.isBusy || !this.stopRequested) {
this.isBusy = true;
this.log('Start successfully. Backup files to users.');
await this.initialize();
}
if (global.gc) {
global.gc();
}
}, 10000); // 10-second interval for testing
}
@@ -139,9 +144,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' });
}
}
@@ -157,6 +162,22 @@ export class BackupManager {
});
}
async stop(): Promise<void> {
this.stopRequested = true; // Signal that stop is requested
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
// Wait for any ongoing process to complete if busy
while (this.isBusy) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
console.log("[BackupManager] Stopped successfully.");
}
// Unified logging function
private log(message: string, level: 'log' | 'error' | 'warn' = 'log'): void {
const prefix = '[BackupManager]';
+24 -4
View File
@@ -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';
@@ -15,6 +14,8 @@ export class BackupRetrievalWorker {
private encryptionKey: Buffer | null = null;
private iv: Buffer | null = null;
private tcpCommunicator: TcpCommunicator | null = null;
private stopRequested: boolean = false;
private isBusy: boolean = false;
constructor(userConfigPath: string, applicationInfoPath: string, clientPort: number, destinationPath: string) {
this.userConfig = new JsonManager(userConfigPath);
@@ -34,6 +35,8 @@ export class BackupRetrievalWorker {
}
async start(): Promise<void> {
if(!this.stopRequested) return;
this.isBusy = true;
try {
const userInfo = await this.userConfig.readValue('user_info');
if (!userInfo || !userInfo.name) {
@@ -62,13 +65,19 @@ export class BackupRetrievalWorker {
this.log(`Backup retrieved successfully from ${ip}`);
}
parentPort?.postMessage({ success: true, message: 'Backup retrieval completed successfully.' });
process.send?.({ type: 'showAlert', message: 'Backup retrieval completed successfully.' });
process.send?.({ type: 'changeContent', page: 'main_menu' });
} catch (error: any) {
this.log(`Error in BackupRetrievalWorker: ${error.message}`, 'error');
parentPort?.postMessage({ success: false, message: `A problem occurred: ${error.message}` });
process.send?.({ type: 'showAlert', message: `A problem occurred: ${error.message}` });
process.send?.({ type: 'changeContent', page: 'main_menu' });
}
finally {
this.isBusy = false;
}
finally{
if (global.gc) {
global.gc();
}
}
@@ -172,6 +181,17 @@ export class BackupRetrievalWorker {
}
}
async stop(): Promise<void> {
this.stopRequested = true; // Signal that stop is requested
// Wait for any ongoing process to complete if busy
while (this.isBusy) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
console.log("[BackupManager] Stopped successfully.");
}
private async waitForResponse(): Promise<ParsedMessage | null> {
return new Promise((resolve) => {
const idResponseCheck = setInterval(async () => {
+35 -8
View File
@@ -14,6 +14,8 @@ export class DepartmentSharer {
private readonly clientPort: number;
private isBusy: boolean = false;
private tcpCommunicator: TcpCommunicator | null = null;
private stopRequested: boolean = false;
private intervalId: NodeJS.Timeout | null = null;
constructor(
userConfigPath: string,
@@ -30,12 +32,16 @@ export class DepartmentSharer {
// Start sharing files with the department every minute
async start(): Promise<void> {
setInterval(async () => {
if (!this.isBusy) {
this.intervalId = setInterval(async () => {
if (!this.isBusy || !this.stopRequested) {
this.isBusy = true;
this.log('Start successfully. Sharing files with the department.');
await this.shareFilesWithDepartment();
}
if (global.gc) {
global.gc();
}
}, 10000); // 10-second interval for testing
}
@@ -87,11 +93,10 @@ export class DepartmentSharer {
const userIp = user.ip;
this.tcpCommunicator = new TcpCommunicator(userIp, this.clientPort);
if (await this.tcpCommunicator.connect()) continue;
if (!await this.tcpCommunicator.connect()) continue;
// First clear the department directory
const clearSuccess = await this.clearDepartmentDirectory();
if (clearSuccess) {
// First clear the department directory;
if (await this.clearDepartmentDirectory(userName)) {
await this.sendFilesToUser(departmentFiles.structure, userName);
}
@@ -108,10 +113,10 @@ export class DepartmentSharer {
}
// Clear the department directory for a user
private async clearDepartmentDirectory(): Promise<boolean> {
private async clearDepartmentDirectory(userName: string): Promise<boolean> {
if(!this.tcpCommunicator) return false;
if (!await this.tcpCommunicator.sendMessage(operationCodes.CLEAR_DEPARTMENT)) return false;
if (!await this.tcpCommunicator.sendMessage(operationCodes.CLEAR_DEPARTMENT, {userName: userName})) return false;
const response = await this.waitForResponse();
if (!response || response.operationCode !== operationCodes.OK){
@@ -127,6 +132,8 @@ export class DepartmentSharer {
if(!this.tcpCommunicator) return;
const unsentFiles = Object.keys(files);
console.log(`\n\n${unsentFiles}\n\n`);
for (const fileName of unsentFiles) {
const filePath = files[fileName];
@@ -152,17 +159,37 @@ export class DepartmentSharer {
// Send the file
if (!await this.tcpCommunicator.sendMessage(operationCodes.DEPARTMENT_FILE, metaInfo, Buffer.from(fileContent))) return;
console.log(`\n\nSending file: ${fileName} to ${userName}\n\n`);
const response = await this.waitForResponse();
if (!response || response.operationCode !== operationCodes.OK) {
this.log(`Failed to send file: ${fileName}`, 'error');
return;
}
this.log(`File sent successfully: ${fileName} to ${userName}`);
unsentFiles.splice(unsentFiles.indexOf(fileName), 1);
await this.tcpCommunicator.disconnect();
}
}
async stop(): Promise<void> {
this.stopRequested = true; // Signal that stop is requested
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
// Wait for any ongoing process to complete if busy
while (this.isBusy) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
console.log("[BackupManager] Stopped successfully.");
}
private async waitForResponse(): Promise<ParsedMessage | null> {
return new Promise((resolve) => {
const idResponseCheck = setInterval(async () => {
+4
View File
@@ -140,6 +140,10 @@ export class DirectoryWatcher {
this.directoryWatcher.close();
this.directoryWatcher = null;
}
if (global.gc) {
global.gc();
}
}
// Unified logging function
+27 -11
View File
@@ -17,6 +17,8 @@ export class FileSharer {
private readonly clientPort: number;
private isBusy: boolean;
private tcpCommunicator: TcpCommunicator | null = null;
private stopRequested: boolean = false;
private intervalId: NodeJS.Timeout | null = null;
constructor(queueFilePath: string, clientPort: number) {
this.queueManager = new QueueManager<FileItemTask>(queueFilePath, compareFnFileItemTask);
@@ -26,26 +28,24 @@ export class FileSharer {
// Start processing the file queue
async start(): Promise<void> {
setInterval(async () => {
if (!this.isBusy) { // Check if the queue is already being processed
this.intervalId = setInterval(async () => {
if (!this.isBusy || !this.stopRequested) { // Check if the queue is already being processed
this.isBusy = true; // Set busy flag to true before starting
this.log("Start successfully. Processing the queue.");
await this.processQueue(); // Process the queue at regular intervals
this.log("Queue processing completed.");
await this.processQueue();
}
if (global.gc) {
global.gc();
}
}, 10000); // 10 seconds interval
}
// Method to process the queue
private async processQueue(): Promise<void> {
if (this.isBusy) {
this.log("Queue is already being processed. Skipping this interval.");
return;
}
this.isBusy = true; // Set busy flag to true before starting
while (!this.queueManager.isEmpty()) {
const task = this.queueManager.peek();
this.log('trimiti fisier');
if (task) {
this.log(`Processing task for file: ${task.path} to IP: ${task.ip}`);
@@ -106,6 +106,22 @@ export class FileSharer {
return true;
}
async stop(): Promise<void> {
this.stopRequested = true; // Signal that stop is requested
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
// Wait for any ongoing process to complete if busy
while (this.isBusy) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
console.log("[BackupManager] Stopped successfully.");
}
private async waitForResponse(): Promise<ParsedMessage | null> {
return new Promise((resolve) => {
const idResponseCheck = setInterval(async () => {
+25 -24
View File
@@ -1,46 +1,47 @@
import fs from 'fs';
import * as lockfile from 'proper-lockfile';
import path from 'path';
export class JsonManager {
private readonly filePath: string;
private readonly lockFilePath: string;
constructor(filePath: string) {
const dir = path.dirname(filePath);
// Check if the directory exists, throw an error if it doesn't
// Check if the directory exists, throw error if it doesn't
if (!fs.existsSync(dir)) {
throw new Error(`The directory does not exist: ${dir}`);
}
this.filePath = filePath;
this.lockFilePath = `${filePath}.lock`; // Define the lock file path
// If the file doesn't exist, create it with an empty JSON object
// If the file doesn't exist, create it
if (!fs.existsSync(filePath)) {
fs.writeFileSync(filePath, JSON.stringify({}, null, 2), 'utf8');
}
}
// Method to acquire a lock with retries
private async acquireLock(): Promise<() => Promise<void>> {
return lockfile.lock(this.filePath, {
retries: {
retries: 20, // Retry up to 10 times
factor: 1, // Retry factor
minTimeout: 100, // Minimum delay between retries in ms
maxTimeout: 200 // Maximum delay between retries in ms
}
});
// Method to acquire a lock (create .lock file)
private async acquireLock(): Promise<void> {
while (fs.existsSync(this.lockFilePath)) {
// Wait until the lock file is released
await new Promise(resolve => setTimeout(resolve, 100)); // 100ms delay before retrying
}
// Create the lock file
fs.writeFileSync(this.lockFilePath, '');
}
// Method to release the lock
private async releaseLock(release: () => Promise<void>): Promise<void> {
await release();
// Method to release the lock (delete .lock file)
private releaseLock(): void {
if (fs.existsSync(this.lockFilePath)) {
fs.unlinkSync(this.lockFilePath);
}
}
// Read a value by key from the JSON file with a lock
public async readValue(key: string): Promise<any | null> {
const release = await this.acquireLock();
await this.acquireLock(); // Acquire the lock
try {
if (!fs.existsSync(this.filePath)) return null;
@@ -51,13 +52,13 @@ export class JsonManager {
console.error(`Error reading from JSON file: ${err.message}`);
return null;
} finally {
await this.releaseLock(release); // Always release the lock after the operation
this.releaseLock(); // Always release the lock after the operation
}
}
// Write a key-value pair to the JSON file with a lock
public async writeValue(key: string, value: any): Promise<boolean> {
const release = await this.acquireLock();
await this.acquireLock(); // Acquire the lock
try {
let data: { [key: string]: any } = {};
@@ -75,13 +76,13 @@ export class JsonManager {
console.error(`Error writing to JSON file: ${err.message}`);
return false;
} finally {
await this.releaseLock(release); // Always release the lock after the operation
this.releaseLock(); // Always release the lock after the operation
}
}
// Remove a key-value pair from the JSON file with a lock
public async removeValue(key: string): Promise<boolean> {
const release = await this.acquireLock();
await this.acquireLock(); // Acquire the lock
try {
if (!fs.existsSync(this.filePath)) return false;
@@ -97,13 +98,13 @@ export class JsonManager {
console.error(`Error removing key from JSON file: ${err.message}`);
return false;
} finally {
await this.releaseLock(release); // Always release the lock after the operation
this.releaseLock(); // Always release the lock after the operation
}
}
// Reset the JSON file by clearing all data with a lock
public async resetFile(): Promise<boolean> {
const release = await this.acquireLock();
await this.acquireLock(); // Acquire the lock
try {
fs.writeFileSync(this.filePath, JSON.stringify({}, null, 2), 'utf8');
@@ -112,7 +113,7 @@ export class JsonManager {
console.error(`Error resetting JSON file: ${err.message}`);
return false;
} finally {
await this.releaseLock(release); // Always release the lock after the operation
this.releaseLock(); // Always release the lock after the operation
}
}
}
+7 -8
View File
@@ -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";
@@ -55,7 +54,7 @@ export class NetworkScanner {
try {
this.log('UC Check running...', 'log', 'startUCCheck');
const udpClient = new UdpClient(this.udpPort);
const aliveClients = await udpClient.getAliveClients();
const aliveClients = await udpClient.getTargetClients(operationCodes.ARE_YOU_UC);
const storedIp = await this.applicationInfo.readValue('serverIp');
const foundClient = aliveClients.length > 0;
@@ -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;
}
@@ -96,7 +95,7 @@ export class NetworkScanner {
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 activeIPs = await udpClient.getTargetClients(operationCodes.ARE_YOU_HUMAN);
const filteredIPs = activeIPs.filter(ip => ip !== serverIp);
// Save the filtered IPs to 'users_ip'
@@ -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');
+5
View File
@@ -43,6 +43,11 @@ export class TcpCommunicator {
getLastResult(): ParsedMessage | null {
const message = this.lastResult;
this.lastResult = null;
if (global.gc) {
global.gc();
}
return message;
}
+15 -2
View File
@@ -11,6 +11,7 @@ export class UsersInfoFetcher {
private readonly clientPort: number;
private memoryId: string;
private readonly activeUsersKey: string;
private intervalId: NodeJS.Timeout | null = null;
constructor(applicationInfoPath: string, memoryManagerPath: string, clientPort: number) {
this.applicationInfo = new JsonManager(applicationInfoPath);
@@ -23,9 +24,13 @@ export class UsersInfoFetcher {
// Method to start checking user info periodically (every minute)
async start(): Promise<void> {
setInterval(async () => {
this.intervalId = setInterval(async () => {
await this.initialize(); // Re-run every minute
}, 5000); // 1 minute interval
if (global.gc) {
global.gc();
}
}, 5000); // 5-second interval for testing
}
// Initialize and fetch user IPs and process users info
@@ -97,6 +102,14 @@ export class UsersInfoFetcher {
await this.memoryManager.updateMetaInformation(this.memoryId, userInfo); // Update active users in memory
}
stop(): void {
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
console.log("[UsersInfoFetcher] Stopped successfully.");
}
}
// Unified logging function
private log(message: string, level: 'log' | 'error' = 'log'): void {
const prefix = '[UsersInfoFetcher]';
+75 -161
View File
@@ -1,214 +1,128 @@
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[];
private cleanupInProgress: boolean = false;
constructor(pathToWorkerDir: string, windowManager: WindowManager) {
this.pathToWorkerDir = pathToWorkerDir;
this.windowManager = windowManager;
this.workers = []; // Initialize the array to store workers
this.workers = [];
}
async startNetworkScannerWorker(udpPort: number, tcpPort: number, okPage: string, errorPage: string, databaseResetPage: string, userConfigPath: string, applicationInfoPath: string): Promise<void> {
return new Promise((resolve, reject) => {
const worker = new Worker(path.join(this.pathToWorkerDir, 'network_scanner_worker.js'), {
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) => {
if (data.type === 'changeContent') {
this.windowManager.changeContent(data.page);
}
});
worker.on('error', (err) => {
console.error('Network Scanner Worker error:', err);
worker.terminate();
this.removeWorker(worker);
reject(err); // Reject the promise if there's an error
});
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
});
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
});
}
// Start the Directories Watcher Worker
async startDirectoriesWatchersWorker(memoryManagerPath: string, applicationInfoPath: string): Promise<void> {
return new Promise((resolve, reject) => {
const worker = new Worker(path.join(this.pathToWorkerDir, 'directories_watcher_worker.js'), {
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();
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
});
return this.startForkedWorker('directories_watcher_worker.js', {
MEMORY_MANAGER_PATH: memoryManagerPath,
APPLICATION_INFO_PATH: applicationInfoPath
});
}
// Start the Servers Worker (UDP and TCP servers)
async startServersWorker(host: string, udpPort: number, tcpPort: number): Promise<void> {
return new Promise((resolve, reject) => {
const worker = new Worker(path.join(this.pathToWorkerDir, 'servers_worker.js'), {
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
});
return this.startForkedWorker('servers_worker.js', {
HOST: host,
USER_UDP_PORT: udpPort.toString(),
USER_TCP_PORT: tcpPort.toString()
});
}
// Start the Users Info Worker
async startResourceCoordinatorWorker(usersConfigPath: string, applicationInfoPath: string, memoryManagerPath: string, queueManagerPath: string, tcpPort: number): Promise<void> {
return new Promise((resolve, reject) => {
const worker = new Worker(path.join(this.pathToWorkerDir, 'resource_coordinator_worker.js'), {
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
});
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()
});
}
// Start the Backup Retrieval Worker
async startBackupRetrievalWorker(
userConfigPath: string,
applicationInfoPath: string,
clientPort: number,
destinationPath: string
): Promise<void> {
return new Promise(async (resolve, reject) => {
const worker = new Worker(path.join(this.pathToWorkerDir, 'backup_retrieval_worker.js'), {
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
});
async startBackupRetrievalWorker(userConfigPath: string, applicationInfoPath: string, clientPort: number, destinationPath: string): Promise<void> {
return this.startForkedWorker('backup_retrieval_worker.js', {
USER_CONFIG_PATH: userConfigPath,
APPLICATION_INFO_PATH: applicationInfoPath,
CLIENT_PORT: clientPort.toString(),
DESTINATION_PATH: destinationPath
});
}
async startAnnouncementWorker(applicationInfoPath: string, clientPort: number, message: string): Promise<void> {
return this.startForkedWorker('send_announcement_worker.js', {
APPLICATION_INFO_PATH: applicationInfoPath,
CLIENT_PORT: clientPort.toString(),
MESSAGE: message
});
}
private async startForkedWorker(scriptName: string, envData: { [key: string]: string }): Promise<void> {
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
const worker = fork(path.join(this.pathToWorkerDir, scriptName), {
execArgv: ['--max-old-space-size=4096'],
env: { ...process.env, ...envData }
});
this.workers.push(worker); // Store the worker reference
this.workers.push(worker);
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('message', (data: unknown) => {
const message = data as { type: string, page?: string, message?: string };
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('Announcement 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(`Announcement Worker exited with code ${code}`);
this.removeWorker(worker); // Remove worker reference when it exits
resolve(); // Resolve when the worker exits cleanly
worker.on('exit', (code, signal) => {
this.removeWorker(worker);
if (code === 0) {
console.log(`${scriptName} exited successfully`);
resolve();
} else if (signal) {
console.log(`${scriptName} was killed with signal: ${signal}`);
} else {
console.error(`${scriptName} exited with code: ${code}`);
}
});
});
}
// Close all running workers
closeAllWorkers(): void {
if (this.cleanupInProgress) return;
this.cleanupInProgress = true;
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);
}
}
}
+2 -1
View File
@@ -1,6 +1,7 @@
export let operationCodes = {
// General Operations
HEARTBEAT: 'HEARTBEAT',
ARE_YOU_HUMAN: 'ARE_YOU_HUMAN',
ARE_YOU_UC: 'ARE_YOU_UC',
ALIVE: 'ALIVE',
SET_PUBLIC_KEY: 'SET_PUBLIC_KEY',
SET_AES_KEY: 'SET_AES_KEY',
@@ -7,14 +7,14 @@ export class GeneralOperations implements OperationPlugin {
public static readonly operationCodes = {
OK: 'OK',
ERR: 'ERR',
HEARTBEAT: 'HEARTBEAT',
ARE_YOU_HUMAN: 'ARE_YOU_HUMAN',
ALIVE: 'ALIVE',
SET_PUBLIC_KEY: 'SET_PUBLIC_KEY',
SET_AES_KEY: 'SET_AES_KEY',
};
// Handle heartbeat operation asynchronously
public static async handleHeartbeat(): Promise<ParsedMessage> {
public static async handleAreYouHuman(): Promise<ParsedMessage> {
const networkInterfaces = os.networkInterfaces();
let ipAddress = 'Unknown';
@@ -79,7 +79,7 @@ export class GeneralOperations implements OperationPlugin {
// Register general operations with the OperationHandler
public register(operationHandler: OperationHandler): void {
operationHandler.registerHandler(GeneralOperations.operationCodes.HEARTBEAT, GeneralOperations.handleHeartbeat);
operationHandler.registerHandler(GeneralOperations.operationCodes.ARE_YOU_HUMAN, GeneralOperations.handleAreYouHuman);
operationHandler.registerHandler(GeneralOperations.operationCodes.SET_PUBLIC_KEY, GeneralOperations.handlePublicKey);
operationHandler.registerHandler(GeneralOperations.operationCodes.SET_AES_KEY, GeneralOperations.handleAESKey);
operationHandler.registerHandler(GeneralOperations.operationCodes.OK, GeneralOperations.handleOk);
@@ -1,6 +1,5 @@
import { ParsedMessage } from '../message_handler';
import { OperationHandler } from '../operations_base/operation_handler';
import ping from "ping";
import {
constants,
createCipheriv,
@@ -16,16 +15,16 @@ export abstract class SocketCommunicatorBase {
protected readonly port: number;
protected readonly operationHandler: OperationHandler;
protected handlerResult: ParsedMessage | null;
protected networkSpeed: number | null = null;
protected chunkBuffers: { [messageId: string]: string[] };
protected readonly EOP = '<EOP>';
protected privateKey: string | null;
protected publicKey: string | null;
protected aesKey: Buffer | null;
protected aesIv: Buffer | null;
protected readonly EOP = '<EOP>';
protected readonly CHUNK_SIZE = 1024;
private incompleteChunkBuffer: string = '';
protected constructor(ip: string, port: number, operationHandler: OperationHandler) {
@@ -113,40 +112,6 @@ export abstract class SocketCommunicatorBase {
).toString('base64');
}
protected async scanNetworkLatency(): Promise<number> {
const targetIp = this.ip; // Use the IP from the superclass
try {
const response = await ping.promise.probe(targetIp);
if (!response.alive || response.time === "unknown") {
console.warn(`Ping failed to reach ${targetIp}. Using default network speed.`);
return 200; // Default latency in ms if ping fails
}
return response.time; // Latency in ms from ping response
} catch (error: any) {
console.error(`Ping error: ${error.message}. Using default network speed.`);
return 200; // Default latency in ms if an error occurs
}
}
// Calculate optimal chunk size based on network latency, with fallback if necessary
protected async calculateOptimalChunkSize(messageLength: number): Promise<number> {
const latency = await this.scanNetworkLatency();
this.networkSpeed = latency > 0 ? 1000 / latency : 1; // Speed in bytes/ms based on latency
// Calculate initial chunk size based on latency (bounded between 512 and 1024 bytes)
let chunkSize = Math.min(Math.max(512, Math.floor(5000 / this.networkSpeed)), 1024);
// Adjust chunk size for base64 alignment (multiple of 4)
while (messageLength % chunkSize !== 0 && chunkSize > 0) {
chunkSize -= 4;
}
return chunkSize || 1024; // Fallback to 1024 if alignment adjustment results in 0
}
async handleIncomingChunk(data: Buffer): Promise<void> {
// Append incoming data to the incomplete buffer
this.incompleteChunkBuffer += data.toString();
@@ -171,9 +136,6 @@ export abstract class SocketCommunicatorBase {
// Store the chunk in the correct position based on sequenceNumber (1-based indexing)
this.chunkBuffers[header.messageId][header.sequenceNumber - 1] = chunkContent;
console.log(`Received chunk: ${incomingMessage}`);
console.log(`Chunks received so far: ${this.chunkBuffers[header.messageId].filter(chunk => chunk !== undefined).length}`);
// Check if all chunks have been received
if (this.chunkBuffers[header.messageId].filter(chunk => chunk !== undefined).length === header.totalChunks) {
// Join all chunks to form the full message
@@ -22,12 +22,10 @@ export class TcpClientCommunicator extends SocketCommunicatorBase {
}
setServerPublicKey(publicKey: string): void {
console.log('\n\nSetting server public key\n\n');
this.publicKey = publicKey;
}
setAesKey(aesKey: string, aesIv: string): void {
console.log('\n\nSetting AES key\n\n');
this.aesKey = Buffer.from(aesKey, 'base64');
this.aesIv = Buffer.from(aesIv, 'base64');
}
@@ -60,29 +58,29 @@ export class TcpClientCommunicator extends SocketCommunicatorBase {
}
async sendMessage(operationCode: string, metaInfo?: { [key: string]: any }, fileContent?: Buffer): Promise<void> {
if (!this.networkSpeed) {
this.networkSpeed = await this.scanNetworkLatency();
}
const message = MessageHandler.formatMessage(operationCode, metaInfo, fileContent);
const outgoingMessage = this.encryptWithAes(message);
// Calculate optimal chunk size based on network latency
const optimalChunkSize = await this.calculateOptimalChunkSize(outgoingMessage.length);
const totalChunks = Math.ceil(outgoingMessage.length / optimalChunkSize);
const totalChunks = Math.ceil(outgoingMessage.length / this.CHUNK_SIZE);
const messageId = Date.now().toString();
// Send each chunk with a delay between them
for (let i = 0; i < totalChunks; i++) {
const chunk = outgoingMessage.slice(i * optimalChunkSize, (i + 1) * optimalChunkSize);
const chunk = outgoingMessage.slice(i * this.CHUNK_SIZE, (i + 1) * this.CHUNK_SIZE);
const chunkHeader = JSON.stringify({
messageId,
sequenceNumber: i + 1,
totalChunks,
});
const chunkWithHeader = `${chunkHeader}|${chunk}${this.EOP}`;
if(!this.socket.write(chunkWithHeader)) this.socket.end();
if (!this.socket.write(chunkWithHeader)) {
// Wait for the 'drain' event before writing the next chunk
await new Promise((resolve) => this.socket.once('drain', resolve));
}
}
}
@@ -38,10 +38,6 @@ export class TcpServerCommunicator extends SocketCommunicatorBase {
}
async sendMessage(operationCode: string, metaInfo?: { [key: string]: any }, fileContent?: Buffer): Promise<void> {
if (!this.networkSpeed) {
this.networkSpeed = await this.scanNetworkLatency();
}
const message = MessageHandler.formatMessage(operationCode, metaInfo, fileContent);
let outgoingMessage: string;
@@ -56,21 +52,23 @@ export class TcpServerCommunicator extends SocketCommunicatorBase {
outgoingMessage = this.encryptWithAes(message);
}
// Calculate optimal chunk size based on network latency
const optimalChunkSize = await this.calculateOptimalChunkSize(outgoingMessage.length);
const totalChunks = Math.ceil(outgoingMessage.length / optimalChunkSize);
const totalChunks = Math.ceil(outgoingMessage.length / this.CHUNK_SIZE);
const messageId = Date.now().toString();
// Send each chunk with a delay between them
for (let i = 0; i < totalChunks; i++) {
const chunk = outgoingMessage.slice(i * optimalChunkSize, (i + 1) * optimalChunkSize);
const chunk = outgoingMessage.slice(i * this.CHUNK_SIZE, (i + 1) * this.CHUNK_SIZE);
const chunkHeader = JSON.stringify({
messageId,
sequenceNumber: i + 1,
totalChunks,
});
const chunkWithHeader = `${chunkHeader}|${chunk}${this.EOP}`;
if(!this.socket.write(chunkWithHeader)) this.socket.end();
if (!this.socket.write(chunkWithHeader)) {
// Wait for the 'drain' event before writing the next chunk
await new Promise((resolve) => this.socket.once('drain', resolve));
}
}
}
}
+3 -4
View File
@@ -29,7 +29,7 @@ export class UdpClient {
}
// Send heartbeat and get clients that respond with ALIVE, excluding the host machine's IP addresses
async getAliveClients(): Promise<string[]> {
async getTargetClients(heartbeatCode: string): Promise<string[]> {
const subnet = this.getSubnet();
const ipRange = this.getIPRange(subnet);
@@ -45,7 +45,7 @@ export class UdpClient {
const aliveClients: string[] = [];
for (const ip of activeIps) {
if (!localIPs.includes(ip)) {
const result = await this.sendHeartbeat(ip);
const result = await this.sendHeartbeat(ip, heartbeatCode);
if (result.found) {
aliveClients.push(ip);
}
@@ -73,9 +73,8 @@ export class UdpClient {
}
// Send heartbeat to an IP
private async sendHeartbeat(ip: string): Promise<{ found: boolean }> {
private async sendHeartbeat(ip: string, heartbeatCode: string): Promise<{ found: boolean }> {
return new Promise((resolve) => {
const heartbeatCode = operationCodes.HEARTBEAT;
const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode);
this.log(`Sending heartbeat to ${ip}`);
+39 -15
View File
@@ -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(
@@ -23,4 +25,26 @@ const backupRetrievalWorker = new BackupRetrievalWorker(
);
// Start the backup retrieval process
backupRetrievalWorker.start();
backupRetrievalWorker.start().then(() => {
console.log('Backup retrieval process completed successfully.');
});
process.on('SIGTERM', async () => {
console.log('Received SIGTERM. Cleaning up...');
await cleanupAndExit();
});
process.on('SIGINT', async () => {
console.log('Received SIGINT. Cleaning up...');
await cleanupAndExit();
});
async function cleanupAndExit() {
// Perform any cleanup, such as closing connections, saving data, etc.
// Example: if you have a server instance running, you may want to close it:
// await server.close();
console.log('Cleanup complete. Exiting.');
process.exit(0); // Exit with code 0 to indicate a clean exit
}
+33 -6
View File
@@ -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();
@@ -15,3 +24,21 @@ departmentShareManager.start();
const shareFileManager = new DirectoryWatcher(memoryManagerPath, applicationInfoPath, 'shareDirectory');
shareFileManager.start();
process.on('SIGTERM', async () => {
console.log('Received SIGTERM. Cleaning up...');
await cleanupAndExit();
});
process.on('SIGINT', async () => {
console.log('Received SIGINT. Cleaning up...');
await cleanupAndExit();
});
async function cleanupAndExit() {
backupDirectoryManager.closeWatcher();
departmentShareManager.closeWatcher();
shareFileManager.closeWatcher();
console.log('Cleanup complete. Exiting.');
process.exit(0); // Exit with code 0 to indicate a clean exit
}
+35 -15
View File
@@ -1,19 +1,39 @@
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
);
process.on('SIGTERM', async () => {
console.log('Received SIGTERM. Cleaning up...');
await cleanupAndExit();
});
process.on('SIGINT', async () => {
console.log('Received SIGINT. Cleaning up...');
await cleanupAndExit();
});
async function cleanupAndExit() {
networkScanner.stopAllIntervals();
console.log('Cleanup complete. Exiting.');
process.exit(0); // Exit with code 0 to indicate a clean exit
}
+28 -7
View File
@@ -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,25 @@ backupManager.start();
const fileSharer = new FileSharer(queueManagerPath, tcpPort);
fileSharer.start();
const departmentSharer = new DepartmentSharer(usersConfigPath, applicationInfoPath, memoryManagerPath, tcpPort);
departmentSharer.start();
process.on('SIGTERM', async () => {
console.log('Received SIGTERM. Cleaning up...');
await cleanupAndExit();
});
process.on('SIGINT', async () => {
console.log('Received SIGINT. Cleaning up...');
await cleanupAndExit();
});
async function cleanupAndExit() {
usersInfoFetcher.stop();
await backupManager.stop();
await fileSharer.stop();
await departmentSharer.stop();
console.log('Cleanup complete. Exiting.');
process.exit(0); // Exit with code 0 to indicate a clean exit
}
+24 -16
View File
@@ -1,19 +1,27 @@
import { workerData } from 'worker_threads';
import { AnnouncementSender} from "../helpers/announcement_sender";
import { AnnouncementSender } from "../helpers/announcement_sender";
// Destructure data passed from the main thread
const {
applicationInfoPath,
clientPort,
message
}: {
applicationInfoPath: string,
clientPort: number,
message: string
} = workerData;
// Read environment variables passed by WorkerManager
const applicationInfoPath = process.env.APPLICATION_INFO_PATH as string;
const clientPort = parseInt(process.env.CLIENT_PORT as string, 10);
const message = process.env.MESSAGE as string;
// Initialize the AnnouncementWorker
const announcementWorker = new AnnouncementSender(applicationInfoPath, clientPort);
if (!applicationInfoPath || !clientPort || !message) {
console.error("Missing necessary environment variables for AnnouncementWorker.");
process.exit(1);
}
// Start the announcement process and handle results
announcementWorker.start(message);
// Initialize the AnnouncementSender instance
const announcementSender = new AnnouncementSender(applicationInfoPath, clientPort);
// Start the announcement process
announcementSender.start(message);
// Handle graceful termination on receiving kill signals
const handleExit = async () => {
console.log("Announcement worker is shutting down gracefully...");
await announcementSender.stop(); // Assuming stop() is implemented to clean up resources
process.exit(0);
};
process.on('SIGTERM', handleExit);
process.on('SIGINT', handleExit);
+29 -7
View File
@@ -1,14 +1,36 @@
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;
let udpServer: UdpServer | null
let tcpServer: TcpServer | 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();
tcpServer.start();
process.on('SIGTERM', async () => {
console.log('Received SIGTERM. Cleaning up...');
await cleanupAndExit();
});
process.on('SIGINT', async () => {
console.log('Received SIGINT. Cleaning up...');
await cleanupAndExit();
});
async function cleanupAndExit() {
// Perform any cleanup, such as closing connections, saving data, etc.
// Example: if you have a server instance running, you may want to close it:
// await server.close();
console.log('Cleanup complete. Exiting.');
process.exit(0); // Exit with code 0 to indicate a clean exit
}