network chunk v20
This commit is contained in:
Generated
+11
@@ -23,6 +23,7 @@
|
|||||||
"@types/ping": "^0.4.4",
|
"@types/ping": "^0.4.4",
|
||||||
"@types/proper-lockfile": "^4.1.4",
|
"@types/proper-lockfile": "^4.1.4",
|
||||||
"@types/uuid": "^10.0.0",
|
"@types/uuid": "^10.0.0",
|
||||||
|
"check-disk-space": "^3.4.0",
|
||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
"del-cli": "^5.0.0",
|
"del-cli": "^5.0.0",
|
||||||
"electron": "^33.0.2",
|
"electron": "^33.0.2",
|
||||||
@@ -1489,6 +1490,16 @@
|
|||||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
"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": {
|
"node_modules/chownr": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"@types/ping": "^0.4.4",
|
"@types/ping": "^0.4.4",
|
||||||
"@types/proper-lockfile": "^4.1.4",
|
"@types/proper-lockfile": "^4.1.4",
|
||||||
"@types/uuid": "^10.0.0",
|
"@types/uuid": "^10.0.0",
|
||||||
|
"check-disk-space": "^3.4.0",
|
||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
"del-cli": "^5.0.0",
|
"del-cli": "^5.0.0",
|
||||||
"electron": "^33.0.2",
|
"electron": "^33.0.2",
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ import { JsonManager } from './json_manager'; // Assuming this manages JSON conf
|
|||||||
import { TcpCommunicator } from "./tcp_communicator";
|
import { TcpCommunicator } from "./tcp_communicator";
|
||||||
import { operationCodes } from '../network/operation_codes'; // Assuming this holds operation codes
|
import { operationCodes } from '../network/operation_codes'; // Assuming this holds operation codes
|
||||||
import { parentPort } from 'worker_threads';
|
import { parentPort } from 'worker_threads';
|
||||||
import {ParsedMessage} from "../network/message_handler";
|
import { ParsedMessage } from "../network/message_handler";
|
||||||
|
|
||||||
export class AnnouncementSender {
|
export class AnnouncementSender {
|
||||||
private applicationInfo: JsonManager;
|
private applicationInfo: JsonManager;
|
||||||
private readonly clientPort: number;
|
private readonly clientPort: number;
|
||||||
private message: string = '';
|
private message: string = '';
|
||||||
private tcpCommunicator: TcpCommunicator | null = null;
|
private tcpCommunicator: TcpCommunicator | null = null;
|
||||||
|
private stopRequested: boolean = false;
|
||||||
|
|
||||||
constructor(applicationInfoPath: string, clientPort: number) {
|
constructor(applicationInfoPath: string, clientPort: number) {
|
||||||
this.applicationInfo = new JsonManager(applicationInfoPath);
|
this.applicationInfo = new JsonManager(applicationInfoPath);
|
||||||
@@ -18,6 +19,8 @@ export class AnnouncementSender {
|
|||||||
async start(message: string): Promise<void> {
|
async start(message: string): Promise<void> {
|
||||||
console.log('AnnouncementWorker started.');
|
console.log('AnnouncementWorker started.');
|
||||||
this.message = message;
|
this.message = message;
|
||||||
|
this.stopRequested = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const activeUsersIp = await this.applicationInfo.readValue('users_ip');
|
const activeUsersIp = await this.applicationInfo.readValue('users_ip');
|
||||||
if (!activeUsersIp || !activeUsersIp.length) {
|
if (!activeUsersIp || !activeUsersIp.length) {
|
||||||
@@ -25,6 +28,11 @@ export class AnnouncementSender {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const ip of activeUsersIp) {
|
for (const ip of activeUsersIp) {
|
||||||
|
if (this.stopRequested) {
|
||||||
|
console.log('AnnouncementWorker stopped.');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const success = await this.sendAnnouncementToIp(ip);
|
const success = await this.sendAnnouncementToIp(ip);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw new Error(`Failed to send announcement to all users.`);
|
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}`);
|
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) {
|
} catch (error: any) {
|
||||||
console.error('Error in AnnouncementWorker:', error);
|
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.');
|
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> {
|
private async sendAnnouncementToIp(ip: string): Promise<boolean> {
|
||||||
this.tcpCommunicator = new TcpCommunicator(ip, this.clientPort);
|
this.tcpCommunicator = new TcpCommunicator(ip, this.clientPort);
|
||||||
if (!await this.tcpCommunicator.connect()) {
|
if (!await this.tcpCommunicator.connect()) {
|
||||||
@@ -73,7 +90,12 @@ export class AnnouncementSender {
|
|||||||
private async waitForResponse(): Promise<ParsedMessage | null> {
|
private async waitForResponse(): Promise<ParsedMessage | null> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const idResponseCheck = setInterval(async () => {
|
const idResponseCheck = setInterval(async () => {
|
||||||
if (!this.tcpCommunicator) return null;
|
if (this.stopRequested || !this.tcpCommunicator) {
|
||||||
|
clearInterval(idResponseCheck);
|
||||||
|
resolve(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.tcpCommunicator.hasResponseArrived()) {
|
if (this.tcpCommunicator.hasResponseArrived()) {
|
||||||
clearInterval(idResponseCheck);
|
clearInterval(idResponseCheck);
|
||||||
resolve(this.tcpCommunicator.getLastResult());
|
resolve(this.tcpCommunicator.getLastResult());
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { MemoryManager } from './memory_manager';
|
|||||||
import { JsonManager } from './json_manager';
|
import { JsonManager } from './json_manager';
|
||||||
import { TcpCommunicator } from './tcp_communicator';
|
import { TcpCommunicator } from './tcp_communicator';
|
||||||
import { operationCodes } from '../network/operation_codes';
|
import { operationCodes } from '../network/operation_codes';
|
||||||
import { parentPort } from 'worker_threads';
|
|
||||||
import { ParsedMessage } from "../network/message_handler";
|
import { ParsedMessage } from "../network/message_handler";
|
||||||
|
|
||||||
export class BackupManager {
|
export class BackupManager {
|
||||||
@@ -15,6 +14,8 @@ export class BackupManager {
|
|||||||
private userConfig: JsonManager;
|
private userConfig: JsonManager;
|
||||||
private readonly clientPort: number;
|
private readonly clientPort: number;
|
||||||
private isBusy: boolean = false;
|
private isBusy: boolean = false;
|
||||||
|
private intervalId: NodeJS.Timeout | null = null;
|
||||||
|
private stopRequested: boolean = false;
|
||||||
|
|
||||||
constructor(userConfigPath: string, applicationInfoPath: string, memoryManagerPath: string, clientPort: number) {
|
constructor(userConfigPath: string, applicationInfoPath: string, memoryManagerPath: string, clientPort: number) {
|
||||||
this.applicationInfo = new JsonManager(applicationInfoPath);
|
this.applicationInfo = new JsonManager(applicationInfoPath);
|
||||||
@@ -24,12 +25,16 @@ export class BackupManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
setInterval(async () => {
|
this.intervalId = setInterval(async () => {
|
||||||
if (!this.isBusy) {
|
if (!this.isBusy || !this.stopRequested) {
|
||||||
this.isBusy = true;
|
this.isBusy = true;
|
||||||
this.log('Start successfully. Backup files to users.');
|
this.log('Start successfully. Backup files to users.');
|
||||||
await this.initialize();
|
await this.initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (global.gc) {
|
||||||
|
global.gc();
|
||||||
|
}
|
||||||
}, 10000); // 10-second interval for testing
|
}, 10000); // 10-second interval for testing
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,9 +144,9 @@ export class BackupManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (unsentFiles.length > 0) {
|
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 {
|
} 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
|
// Unified logging function
|
||||||
private log(message: string, level: 'log' | 'error' | 'warn' = 'log'): void {
|
private log(message: string, level: 'log' | 'error' | 'warn' = 'log'): void {
|
||||||
const prefix = '[BackupManager]';
|
const prefix = '[BackupManager]';
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { JsonManager } from './json_manager';
|
import { JsonManager } from './json_manager';
|
||||||
import { TcpCommunicator } from "./tcp_communicator";
|
import { TcpCommunicator } from "./tcp_communicator";
|
||||||
import { operationCodes } from '../network/operation_codes';
|
import { operationCodes } from '../network/operation_codes';
|
||||||
import { parentPort } from 'worker_threads';
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
@@ -15,6 +14,8 @@ export class BackupRetrievalWorker {
|
|||||||
private encryptionKey: Buffer | null = null;
|
private encryptionKey: Buffer | null = null;
|
||||||
private iv: Buffer | null = null;
|
private iv: Buffer | null = null;
|
||||||
private tcpCommunicator: TcpCommunicator | null = null;
|
private tcpCommunicator: TcpCommunicator | null = null;
|
||||||
|
private stopRequested: boolean = false;
|
||||||
|
private isBusy: boolean = false;
|
||||||
|
|
||||||
constructor(userConfigPath: string, applicationInfoPath: string, clientPort: number, destinationPath: string) {
|
constructor(userConfigPath: string, applicationInfoPath: string, clientPort: number, destinationPath: string) {
|
||||||
this.userConfig = new JsonManager(userConfigPath);
|
this.userConfig = new JsonManager(userConfigPath);
|
||||||
@@ -34,6 +35,8 @@ export class BackupRetrievalWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
|
if(!this.stopRequested) return;
|
||||||
|
this.isBusy = true;
|
||||||
try {
|
try {
|
||||||
const userInfo = await this.userConfig.readValue('user_info');
|
const userInfo = await this.userConfig.readValue('user_info');
|
||||||
if (!userInfo || !userInfo.name) {
|
if (!userInfo || !userInfo.name) {
|
||||||
@@ -62,13 +65,19 @@ export class BackupRetrievalWorker {
|
|||||||
this.log(`Backup retrieved successfully from ${ip}`);
|
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) {
|
} catch (error: any) {
|
||||||
this.log(`Error in BackupRetrievalWorker: ${error.message}`, 'error');
|
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> {
|
private async waitForResponse(): Promise<ParsedMessage | null> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const idResponseCheck = setInterval(async () => {
|
const idResponseCheck = setInterval(async () => {
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ export class DepartmentSharer {
|
|||||||
private readonly clientPort: number;
|
private readonly clientPort: number;
|
||||||
private isBusy: boolean = false;
|
private isBusy: boolean = false;
|
||||||
private tcpCommunicator: TcpCommunicator | null = null;
|
private tcpCommunicator: TcpCommunicator | null = null;
|
||||||
|
private stopRequested: boolean = false;
|
||||||
|
private intervalId: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
userConfigPath: string,
|
userConfigPath: string,
|
||||||
@@ -30,12 +32,16 @@ export class DepartmentSharer {
|
|||||||
|
|
||||||
// Start sharing files with the department every minute
|
// Start sharing files with the department every minute
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
setInterval(async () => {
|
this.intervalId = setInterval(async () => {
|
||||||
if (!this.isBusy) {
|
if (!this.isBusy || !this.stopRequested) {
|
||||||
this.isBusy = true;
|
this.isBusy = true;
|
||||||
this.log('Start successfully. Sharing files with the department.');
|
this.log('Start successfully. Sharing files with the department.');
|
||||||
await this.shareFilesWithDepartment();
|
await this.shareFilesWithDepartment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (global.gc) {
|
||||||
|
global.gc();
|
||||||
|
}
|
||||||
}, 10000); // 10-second interval for testing
|
}, 10000); // 10-second interval for testing
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,11 +93,10 @@ export class DepartmentSharer {
|
|||||||
const userIp = user.ip;
|
const userIp = user.ip;
|
||||||
this.tcpCommunicator = new TcpCommunicator(userIp, this.clientPort);
|
this.tcpCommunicator = new TcpCommunicator(userIp, this.clientPort);
|
||||||
|
|
||||||
if (await this.tcpCommunicator.connect()) continue;
|
if (!await this.tcpCommunicator.connect()) continue;
|
||||||
|
|
||||||
// First clear the department directory
|
// First clear the department directory;
|
||||||
const clearSuccess = await this.clearDepartmentDirectory();
|
if (await this.clearDepartmentDirectory(userName)) {
|
||||||
if (clearSuccess) {
|
|
||||||
await this.sendFilesToUser(departmentFiles.structure, userName);
|
await this.sendFilesToUser(departmentFiles.structure, userName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,10 +113,10 @@ export class DepartmentSharer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clear the department directory for a user
|
// 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(!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();
|
const response = await this.waitForResponse();
|
||||||
|
|
||||||
if (!response || response.operationCode !== operationCodes.OK){
|
if (!response || response.operationCode !== operationCodes.OK){
|
||||||
@@ -127,6 +132,8 @@ export class DepartmentSharer {
|
|||||||
if(!this.tcpCommunicator) return;
|
if(!this.tcpCommunicator) return;
|
||||||
const unsentFiles = Object.keys(files);
|
const unsentFiles = Object.keys(files);
|
||||||
|
|
||||||
|
console.log(`\n\n${unsentFiles}\n\n`);
|
||||||
|
|
||||||
for (const fileName of unsentFiles) {
|
for (const fileName of unsentFiles) {
|
||||||
const filePath = files[fileName];
|
const filePath = files[fileName];
|
||||||
|
|
||||||
@@ -152,17 +159,37 @@ export class DepartmentSharer {
|
|||||||
// Send the file
|
// Send the file
|
||||||
if (!await this.tcpCommunicator.sendMessage(operationCodes.DEPARTMENT_FILE, metaInfo, Buffer.from(fileContent))) return;
|
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();
|
const response = await this.waitForResponse();
|
||||||
if (!response || response.operationCode !== operationCodes.OK) {
|
if (!response || response.operationCode !== operationCodes.OK) {
|
||||||
this.log(`Failed to send file: ${fileName}`, 'error');
|
this.log(`Failed to send file: ${fileName}`, 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.log(`File sent successfully: ${fileName} to ${userName}`);
|
||||||
|
|
||||||
unsentFiles.splice(unsentFiles.indexOf(fileName), 1);
|
unsentFiles.splice(unsentFiles.indexOf(fileName), 1);
|
||||||
await this.tcpCommunicator.disconnect();
|
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> {
|
private async waitForResponse(): Promise<ParsedMessage | null> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const idResponseCheck = setInterval(async () => {
|
const idResponseCheck = setInterval(async () => {
|
||||||
|
|||||||
@@ -140,6 +140,10 @@ export class DirectoryWatcher {
|
|||||||
this.directoryWatcher.close();
|
this.directoryWatcher.close();
|
||||||
this.directoryWatcher = null;
|
this.directoryWatcher = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (global.gc) {
|
||||||
|
global.gc();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unified logging function
|
// Unified logging function
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ export class FileSharer {
|
|||||||
private readonly clientPort: number;
|
private readonly clientPort: number;
|
||||||
private isBusy: boolean;
|
private isBusy: boolean;
|
||||||
private tcpCommunicator: TcpCommunicator | null = null;
|
private tcpCommunicator: TcpCommunicator | null = null;
|
||||||
|
private stopRequested: boolean = false;
|
||||||
|
private intervalId: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
constructor(queueFilePath: string, clientPort: number) {
|
constructor(queueFilePath: string, clientPort: number) {
|
||||||
this.queueManager = new QueueManager<FileItemTask>(queueFilePath, compareFnFileItemTask);
|
this.queueManager = new QueueManager<FileItemTask>(queueFilePath, compareFnFileItemTask);
|
||||||
@@ -26,26 +28,24 @@ export class FileSharer {
|
|||||||
|
|
||||||
// Start processing the file queue
|
// Start processing the file queue
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
setInterval(async () => {
|
this.intervalId = setInterval(async () => {
|
||||||
if (!this.isBusy) { // Check if the queue is already being processed
|
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.");
|
this.log("Start successfully. Processing the queue.");
|
||||||
await this.processQueue(); // Process the queue at regular intervals
|
await this.processQueue();
|
||||||
this.log("Queue processing completed.");
|
}
|
||||||
|
|
||||||
|
if (global.gc) {
|
||||||
|
global.gc();
|
||||||
}
|
}
|
||||||
}, 10000); // 10 seconds interval
|
}, 10000); // 10 seconds interval
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to process the queue
|
// Method to process the queue
|
||||||
private async processQueue(): Promise<void> {
|
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()) {
|
while (!this.queueManager.isEmpty()) {
|
||||||
const task = this.queueManager.peek();
|
const task = this.queueManager.peek();
|
||||||
|
this.log('trimiti fisier');
|
||||||
|
|
||||||
if (task) {
|
if (task) {
|
||||||
this.log(`Processing task for file: ${task.path} to IP: ${task.ip}`);
|
this.log(`Processing task for file: ${task.path} to IP: ${task.ip}`);
|
||||||
@@ -106,6 +106,22 @@ export class FileSharer {
|
|||||||
return true;
|
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> {
|
private async waitForResponse(): Promise<ParsedMessage | null> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const idResponseCheck = setInterval(async () => {
|
const idResponseCheck = setInterval(async () => {
|
||||||
|
|||||||
@@ -1,46 +1,47 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import * as lockfile from 'proper-lockfile';
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
export class JsonManager {
|
export class JsonManager {
|
||||||
private readonly filePath: string;
|
private readonly filePath: string;
|
||||||
|
private readonly lockFilePath: string;
|
||||||
|
|
||||||
constructor(filePath: string) {
|
constructor(filePath: string) {
|
||||||
const dir = path.dirname(filePath);
|
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)) {
|
if (!fs.existsSync(dir)) {
|
||||||
throw new Error(`The directory does not exist: ${dir}`);
|
throw new Error(`The directory does not exist: ${dir}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.filePath = filePath;
|
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)) {
|
if (!fs.existsSync(filePath)) {
|
||||||
fs.writeFileSync(filePath, JSON.stringify({}, null, 2), 'utf8');
|
fs.writeFileSync(filePath, JSON.stringify({}, null, 2), 'utf8');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to acquire a lock with retries
|
// Method to acquire a lock (create .lock file)
|
||||||
private async acquireLock(): Promise<() => Promise<void>> {
|
private async acquireLock(): Promise<void> {
|
||||||
return lockfile.lock(this.filePath, {
|
while (fs.existsSync(this.lockFilePath)) {
|
||||||
retries: {
|
// Wait until the lock file is released
|
||||||
retries: 20, // Retry up to 10 times
|
await new Promise(resolve => setTimeout(resolve, 100)); // 100ms delay before retrying
|
||||||
factor: 1, // Retry factor
|
}
|
||||||
minTimeout: 100, // Minimum delay between retries in ms
|
// Create the lock file
|
||||||
maxTimeout: 200 // Maximum delay between retries in ms
|
fs.writeFileSync(this.lockFilePath, '');
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to release the lock
|
// Method to release the lock (delete .lock file)
|
||||||
private async releaseLock(release: () => Promise<void>): Promise<void> {
|
private releaseLock(): void {
|
||||||
await release();
|
if (fs.existsSync(this.lockFilePath)) {
|
||||||
|
fs.unlinkSync(this.lockFilePath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read a value by key from the JSON file with a lock
|
// Read a value by key from the JSON file with a lock
|
||||||
public async readValue(key: string): Promise<any | null> {
|
public async readValue(key: string): Promise<any | null> {
|
||||||
const release = await this.acquireLock();
|
await this.acquireLock(); // Acquire the lock
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!fs.existsSync(this.filePath)) return null;
|
if (!fs.existsSync(this.filePath)) return null;
|
||||||
@@ -51,13 +52,13 @@ export class JsonManager {
|
|||||||
console.error(`Error reading from JSON file: ${err.message}`);
|
console.error(`Error reading from JSON file: ${err.message}`);
|
||||||
return null;
|
return null;
|
||||||
} finally {
|
} 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
|
// Write a key-value pair to the JSON file with a lock
|
||||||
public async writeValue(key: string, value: any): Promise<boolean> {
|
public async writeValue(key: string, value: any): Promise<boolean> {
|
||||||
const release = await this.acquireLock();
|
await this.acquireLock(); // Acquire the lock
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let data: { [key: string]: any } = {};
|
let data: { [key: string]: any } = {};
|
||||||
@@ -75,13 +76,13 @@ export class JsonManager {
|
|||||||
console.error(`Error writing to JSON file: ${err.message}`);
|
console.error(`Error writing to JSON file: ${err.message}`);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} 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
|
// Remove a key-value pair from the JSON file with a lock
|
||||||
public async removeValue(key: string): Promise<boolean> {
|
public async removeValue(key: string): Promise<boolean> {
|
||||||
const release = await this.acquireLock();
|
await this.acquireLock(); // Acquire the lock
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!fs.existsSync(this.filePath)) return false;
|
if (!fs.existsSync(this.filePath)) return false;
|
||||||
@@ -97,13 +98,13 @@ export class JsonManager {
|
|||||||
console.error(`Error removing key from JSON file: ${err.message}`);
|
console.error(`Error removing key from JSON file: ${err.message}`);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} 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
|
// Reset the JSON file by clearing all data with a lock
|
||||||
public async resetFile(): Promise<boolean> {
|
public async resetFile(): Promise<boolean> {
|
||||||
const release = await this.acquireLock();
|
await this.acquireLock(); // Acquire the lock
|
||||||
|
|
||||||
try {
|
try {
|
||||||
fs.writeFileSync(this.filePath, JSON.stringify({}, null, 2), 'utf8');
|
fs.writeFileSync(this.filePath, JSON.stringify({}, null, 2), 'utf8');
|
||||||
@@ -112,7 +113,7 @@ export class JsonManager {
|
|||||||
console.error(`Error resetting JSON file: ${err.message}`);
|
console.error(`Error resetting JSON file: ${err.message}`);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
await this.releaseLock(release); // Always release the lock after the operation
|
this.releaseLock(); // Always release the lock after the operation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import {JsonManager} from "./json_manager";
|
import {JsonManager} from "./json_manager";
|
||||||
import {UdpClient} from "../network/udp/udp_client";
|
import {UdpClient} from "../network/udp/udp_client";
|
||||||
import {parentPort} from "worker_threads";
|
|
||||||
import {TcpCommunicator} from "./tcp_communicator";
|
import {TcpCommunicator} from "./tcp_communicator";
|
||||||
import {operationCodes} from "../network/operation_codes";
|
import {operationCodes} from "../network/operation_codes";
|
||||||
import {ParsedMessage} from "../network/message_handler";
|
import {ParsedMessage} from "../network/message_handler";
|
||||||
@@ -55,7 +54,7 @@ export class NetworkScanner {
|
|||||||
try {
|
try {
|
||||||
this.log('UC Check running...', 'log', 'startUCCheck');
|
this.log('UC Check running...', 'log', 'startUCCheck');
|
||||||
const udpClient = new UdpClient(this.udpPort);
|
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 storedIp = await this.applicationInfo.readValue('serverIp');
|
||||||
const foundClient = aliveClients.length > 0;
|
const foundClient = aliveClients.length > 0;
|
||||||
|
|
||||||
@@ -65,19 +64,19 @@ export class NetworkScanner {
|
|||||||
if (!storedIp || storedIp !== ipAddress) {
|
if (!storedIp || storedIp !== ipAddress) {
|
||||||
await this.applicationInfo.writeValue('serverIp', ipAddress);
|
await this.applicationInfo.writeValue('serverIp', ipAddress);
|
||||||
if (!this.appStarted) {
|
if (!this.appStarted) {
|
||||||
parentPort?.postMessage({ type: 'changeContent', page: this.okPage });
|
process.send?.({ type: 'changeContent', page: this.okPage });
|
||||||
}
|
}
|
||||||
this.appStarted = true;
|
this.appStarted = true;
|
||||||
} else if (!this.appStarted) {
|
} else if (!this.appStarted) {
|
||||||
parentPort?.postMessage({ type: 'changeContent', page: this.okPage });
|
process.send?.({ type: 'changeContent', page: this.okPage });
|
||||||
this.appStarted = true;
|
this.appStarted = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
parentPort?.postMessage({ type: 'changeContent', page: this.errorPage });
|
process.send?.({ type: 'changeContent', page: this.errorPage });
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.log(`Error checking UC: ${err}`, 'error', 'startUCCheck');
|
this.log(`Error checking UC: ${err}`, 'error', 'startUCCheck');
|
||||||
parentPort?.postMessage({ type: 'changeContent', page: this.errorPage });
|
process.send?.({ type: 'changeContent', page: this.errorPage });
|
||||||
} finally {
|
} finally {
|
||||||
this.ucCheckBusy = false;
|
this.ucCheckBusy = false;
|
||||||
}
|
}
|
||||||
@@ -96,7 +95,7 @@ export class NetworkScanner {
|
|||||||
this.log('IP Lookup running...', 'log', 'startUserIPLookup');
|
this.log('IP Lookup running...', 'log', 'startUserIPLookup');
|
||||||
const serverIp = await this.applicationInfo.readValue('serverIp');
|
const serverIp = await this.applicationInfo.readValue('serverIp');
|
||||||
const udpClient = new UdpClient(this.udpPort);
|
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);
|
const filteredIPs = activeIPs.filter(ip => ip !== serverIp);
|
||||||
|
|
||||||
// Save the filtered IPs to 'users_ip'
|
// Save the filtered IPs to 'users_ip'
|
||||||
@@ -152,7 +151,7 @@ export class NetworkScanner {
|
|||||||
if (response?.operationCode !== operationCodes.OK) {
|
if (response?.operationCode !== operationCodes.OK) {
|
||||||
await this.userConfig.resetFile();
|
await this.userConfig.resetFile();
|
||||||
await this.userConfig.writeValue('app_type', app_type);
|
await this.userConfig.writeValue('app_type', app_type);
|
||||||
parentPort?.postMessage({ type: 'changeContent', page: this.databaseResetPage });
|
process.send?.({ type: 'changeContent', page: this.databaseResetPage });
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.log(`Error during login request: ${err}`, 'error', 'sendLoginRequest');
|
this.log(`Error during login request: ${err}`, 'error', 'sendLoginRequest');
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ export class TcpCommunicator {
|
|||||||
getLastResult(): ParsedMessage | null {
|
getLastResult(): ParsedMessage | null {
|
||||||
const message = this.lastResult;
|
const message = this.lastResult;
|
||||||
this.lastResult = null;
|
this.lastResult = null;
|
||||||
|
|
||||||
|
if (global.gc) {
|
||||||
|
global.gc();
|
||||||
|
}
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export class UsersInfoFetcher {
|
|||||||
private readonly clientPort: number;
|
private readonly clientPort: number;
|
||||||
private memoryId: string;
|
private memoryId: string;
|
||||||
private readonly activeUsersKey: string;
|
private readonly activeUsersKey: string;
|
||||||
|
private intervalId: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
constructor(applicationInfoPath: string, memoryManagerPath: string, clientPort: number) {
|
constructor(applicationInfoPath: string, memoryManagerPath: string, clientPort: number) {
|
||||||
this.applicationInfo = new JsonManager(applicationInfoPath);
|
this.applicationInfo = new JsonManager(applicationInfoPath);
|
||||||
@@ -23,9 +24,13 @@ export class UsersInfoFetcher {
|
|||||||
|
|
||||||
// Method to start checking user info periodically (every minute)
|
// Method to start checking user info periodically (every minute)
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
setInterval(async () => {
|
this.intervalId = setInterval(async () => {
|
||||||
await this.initialize(); // Re-run every minute
|
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
|
// 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
|
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
|
// Unified logging function
|
||||||
private log(message: string, level: 'log' | 'error' = 'log'): void {
|
private log(message: string, level: 'log' | 'error' = 'log'): void {
|
||||||
const prefix = '[UsersInfoFetcher]';
|
const prefix = '[UsersInfoFetcher]';
|
||||||
|
|||||||
@@ -1,214 +1,128 @@
|
|||||||
import { Worker } from 'worker_threads';
|
import { fork, ChildProcess } from 'child_process';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {WindowManager} from "./window_manager";
|
import { WindowManager } from "./window_manager";
|
||||||
|
|
||||||
export class WorkerManager {
|
export class WorkerManager {
|
||||||
private readonly pathToWorkerDir: string;
|
private readonly pathToWorkerDir: string;
|
||||||
private windowManager: WindowManager
|
private windowManager: WindowManager;
|
||||||
private workers: Worker[]; // Array to store running workers
|
private workers: ChildProcess[];
|
||||||
|
private cleanupInProgress: boolean = false;
|
||||||
|
|
||||||
constructor(pathToWorkerDir: string, windowManager: WindowManager) {
|
constructor(pathToWorkerDir: string, windowManager: WindowManager) {
|
||||||
this.pathToWorkerDir = pathToWorkerDir;
|
this.pathToWorkerDir = pathToWorkerDir;
|
||||||
this.windowManager = windowManager;
|
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> {
|
async startNetworkScannerWorker(udpPort: number, tcpPort: number, okPage: string, errorPage: string, databaseResetPage: string, userConfigPath: string, applicationInfoPath: string): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return this.startForkedWorker('network_scanner_worker.js', {
|
||||||
const worker = new Worker(path.join(this.pathToWorkerDir, 'network_scanner_worker.js'), {
|
UDP_PORT: udpPort.toString(),
|
||||||
workerData: { udpPort, tcpPort, okPage, errorPage, databaseResetPage, userConfigPath, applicationInfoPath }, // Pass necessary data to the worker
|
TCP_PORT: tcpPort.toString(),
|
||||||
});
|
OK_PAGE: okPage,
|
||||||
|
ERROR_PAGE: errorPage,
|
||||||
this.workers.push(worker); // Store the worker reference
|
DATABASE_RESET_PAGE: databaseResetPage,
|
||||||
|
USER_CONFIG_PATH: userConfigPath,
|
||||||
worker.on('message', (data) => {
|
APPLICATION_INFO_PATH: applicationInfoPath
|
||||||
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
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the Directories Watcher Worker
|
|
||||||
async startDirectoriesWatchersWorker(memoryManagerPath: string, applicationInfoPath: string): Promise<void> {
|
async startDirectoriesWatchersWorker(memoryManagerPath: string, applicationInfoPath: string): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return this.startForkedWorker('directories_watcher_worker.js', {
|
||||||
const worker = new Worker(path.join(this.pathToWorkerDir, 'directories_watcher_worker.js'), {
|
MEMORY_MANAGER_PATH: memoryManagerPath,
|
||||||
workerData: { memoryManagerPath, applicationInfoPath }, // Pass the port to the worker
|
APPLICATION_INFO_PATH: applicationInfoPath
|
||||||
});
|
|
||||||
|
|
||||||
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
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the Servers Worker (UDP and TCP servers)
|
|
||||||
async startServersWorker(host: string, udpPort: number, tcpPort: number): Promise<void> {
|
async startServersWorker(host: string, udpPort: number, tcpPort: number): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return this.startForkedWorker('servers_worker.js', {
|
||||||
const worker = new Worker(path.join(this.pathToWorkerDir, 'servers_worker.js'), {
|
HOST: host,
|
||||||
workerData: { HOST: host, USER_UDP_PORT: udpPort, USER_TCP_PORT: tcpPort }, // Pass host and ports to the worker
|
USER_UDP_PORT: udpPort.toString(),
|
||||||
});
|
USER_TCP_PORT: tcpPort.toString()
|
||||||
|
|
||||||
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<void> {
|
async startResourceCoordinatorWorker(usersConfigPath: string, applicationInfoPath: string, memoryManagerPath: string, queueManagerPath: string, tcpPort: number): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return this.startForkedWorker('resource_coordinator_worker.js', {
|
||||||
const worker = new Worker(path.join(this.pathToWorkerDir, 'resource_coordinator_worker.js'), {
|
USERS_CONFIG_PATH: usersConfigPath,
|
||||||
workerData: {
|
APPLICATION_INFO_PATH: applicationInfoPath,
|
||||||
usersConfigPath,
|
MEMORY_MANAGER_PATH: memoryManagerPath,
|
||||||
applicationInfoPath,
|
QUEUE_MANAGER_PATH: queueManagerPath,
|
||||||
memoryManagerPath,
|
TCP_PORT: tcpPort.toString()
|
||||||
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<void> {
|
||||||
async startBackupRetrievalWorker(
|
return this.startForkedWorker('backup_retrieval_worker.js', {
|
||||||
userConfigPath: string,
|
USER_CONFIG_PATH: userConfigPath,
|
||||||
applicationInfoPath: string,
|
APPLICATION_INFO_PATH: applicationInfoPath,
|
||||||
clientPort: number,
|
CLIENT_PORT: clientPort.toString(),
|
||||||
destinationPath: string
|
DESTINATION_PATH: destinationPath
|
||||||
): 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 startAnnouncementWorker(applicationInfoPath: string, clientPort: number, message: string): Promise<void> {
|
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) => {
|
return new Promise((resolve, reject) => {
|
||||||
const worker = new Worker(path.join(this.pathToWorkerDir, 'send_announcement_worker.js'), {
|
const worker = fork(path.join(this.pathToWorkerDir, scriptName), {
|
||||||
workerData: { applicationInfoPath, clientPort, message }, // Pass necessary data to the worker
|
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) => {
|
worker.on('message', (data: unknown) => {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 3000)); // Wait for 1 second
|
const message = data as { type: string, page?: string, message?: string };
|
||||||
this.windowManager.changeContent('main_menu');
|
|
||||||
this.windowManager.showAlert(`${data.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) => {
|
worker.on('error', (err) => {
|
||||||
console.error('Announcement Worker error:', err);
|
console.error(`${scriptName} error:`, err);
|
||||||
worker.terminate();
|
worker.kill();
|
||||||
this.removeWorker(worker);
|
this.removeWorker(worker);
|
||||||
reject(err); // Reject the promise if there's an error
|
reject(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
worker.on('exit', (code) => {
|
worker.on('exit', (code, signal) => {
|
||||||
console.log(`Announcement Worker exited with code ${code}`);
|
this.removeWorker(worker);
|
||||||
this.removeWorker(worker); // Remove worker reference when it exits
|
if (code === 0) {
|
||||||
resolve(); // Resolve when the worker exits cleanly
|
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 {
|
closeAllWorkers(): void {
|
||||||
|
if (this.cleanupInProgress) return;
|
||||||
|
this.cleanupInProgress = true;
|
||||||
|
|
||||||
console.log('Terminating all running workers...');
|
console.log('Terminating all running workers...');
|
||||||
this.workers.forEach(worker => worker.terminate()); // Terminate each worker
|
this.workers.forEach(worker => worker.kill());
|
||||||
this.workers = []; // Clear the array after terminating all workers
|
this.workers = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method to remove a worker from the workers array when it exits
|
private removeWorker(worker: ChildProcess): void {
|
||||||
private removeWorker(worker: Worker): void {
|
|
||||||
const index = this.workers.indexOf(worker);
|
const index = this.workers.indexOf(worker);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
this.workers.splice(index, 1); // Remove the worker from the array
|
this.workers.splice(index, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
export let operationCodes = {
|
export let operationCodes = {
|
||||||
// General Operations
|
// General Operations
|
||||||
HEARTBEAT: 'HEARTBEAT',
|
ARE_YOU_HUMAN: 'ARE_YOU_HUMAN',
|
||||||
|
ARE_YOU_UC: 'ARE_YOU_UC',
|
||||||
ALIVE: 'ALIVE',
|
ALIVE: 'ALIVE',
|
||||||
SET_PUBLIC_KEY: 'SET_PUBLIC_KEY',
|
SET_PUBLIC_KEY: 'SET_PUBLIC_KEY',
|
||||||
SET_AES_KEY: 'SET_AES_KEY',
|
SET_AES_KEY: 'SET_AES_KEY',
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ export class GeneralOperations implements OperationPlugin {
|
|||||||
public static readonly operationCodes = {
|
public static readonly operationCodes = {
|
||||||
OK: 'OK',
|
OK: 'OK',
|
||||||
ERR: 'ERR',
|
ERR: 'ERR',
|
||||||
HEARTBEAT: 'HEARTBEAT',
|
ARE_YOU_HUMAN: 'ARE_YOU_HUMAN',
|
||||||
ALIVE: 'ALIVE',
|
ALIVE: 'ALIVE',
|
||||||
SET_PUBLIC_KEY: 'SET_PUBLIC_KEY',
|
SET_PUBLIC_KEY: 'SET_PUBLIC_KEY',
|
||||||
SET_AES_KEY: 'SET_AES_KEY',
|
SET_AES_KEY: 'SET_AES_KEY',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle heartbeat operation asynchronously
|
// Handle heartbeat operation asynchronously
|
||||||
public static async handleHeartbeat(): Promise<ParsedMessage> {
|
public static async handleAreYouHuman(): Promise<ParsedMessage> {
|
||||||
const networkInterfaces = os.networkInterfaces();
|
const networkInterfaces = os.networkInterfaces();
|
||||||
let ipAddress = 'Unknown';
|
let ipAddress = 'Unknown';
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ export class GeneralOperations implements OperationPlugin {
|
|||||||
|
|
||||||
// Register general operations with the OperationHandler
|
// Register general operations with the OperationHandler
|
||||||
public register(operationHandler: OperationHandler): void {
|
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_PUBLIC_KEY, GeneralOperations.handlePublicKey);
|
||||||
operationHandler.registerHandler(GeneralOperations.operationCodes.SET_AES_KEY, GeneralOperations.handleAESKey);
|
operationHandler.registerHandler(GeneralOperations.operationCodes.SET_AES_KEY, GeneralOperations.handleAESKey);
|
||||||
operationHandler.registerHandler(GeneralOperations.operationCodes.OK, GeneralOperations.handleOk);
|
operationHandler.registerHandler(GeneralOperations.operationCodes.OK, GeneralOperations.handleOk);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { ParsedMessage } from '../message_handler';
|
import { ParsedMessage } from '../message_handler';
|
||||||
import { OperationHandler } from '../operations_base/operation_handler';
|
import { OperationHandler } from '../operations_base/operation_handler';
|
||||||
import ping from "ping";
|
|
||||||
import {
|
import {
|
||||||
constants,
|
constants,
|
||||||
createCipheriv,
|
createCipheriv,
|
||||||
@@ -16,16 +15,16 @@ export abstract class SocketCommunicatorBase {
|
|||||||
protected readonly port: number;
|
protected readonly port: number;
|
||||||
protected readonly operationHandler: OperationHandler;
|
protected readonly operationHandler: OperationHandler;
|
||||||
protected handlerResult: ParsedMessage | null;
|
protected handlerResult: ParsedMessage | null;
|
||||||
protected networkSpeed: number | null = null;
|
|
||||||
|
|
||||||
protected chunkBuffers: { [messageId: string]: string[] };
|
protected chunkBuffers: { [messageId: string]: string[] };
|
||||||
protected readonly EOP = '<EOP>';
|
|
||||||
|
|
||||||
protected privateKey: string | null;
|
protected privateKey: string | null;
|
||||||
protected publicKey: string | null;
|
protected publicKey: string | null;
|
||||||
protected aesKey: Buffer | null;
|
protected aesKey: Buffer | null;
|
||||||
protected aesIv: Buffer | null;
|
protected aesIv: Buffer | null;
|
||||||
|
|
||||||
|
protected readonly EOP = '<EOP>';
|
||||||
|
protected readonly CHUNK_SIZE = 1024;
|
||||||
private incompleteChunkBuffer: string = '';
|
private incompleteChunkBuffer: string = '';
|
||||||
|
|
||||||
protected constructor(ip: string, port: number, operationHandler: OperationHandler) {
|
protected constructor(ip: string, port: number, operationHandler: OperationHandler) {
|
||||||
@@ -113,40 +112,6 @@ export abstract class SocketCommunicatorBase {
|
|||||||
).toString('base64');
|
).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> {
|
async handleIncomingChunk(data: Buffer): Promise<void> {
|
||||||
// Append incoming data to the incomplete buffer
|
// Append incoming data to the incomplete buffer
|
||||||
this.incompleteChunkBuffer += data.toString();
|
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)
|
// Store the chunk in the correct position based on sequenceNumber (1-based indexing)
|
||||||
this.chunkBuffers[header.messageId][header.sequenceNumber - 1] = chunkContent;
|
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
|
// Check if all chunks have been received
|
||||||
if (this.chunkBuffers[header.messageId].filter(chunk => chunk !== undefined).length === header.totalChunks) {
|
if (this.chunkBuffers[header.messageId].filter(chunk => chunk !== undefined).length === header.totalChunks) {
|
||||||
// Join all chunks to form the full message
|
// Join all chunks to form the full message
|
||||||
|
|||||||
@@ -22,12 +22,10 @@ export class TcpClientCommunicator extends SocketCommunicatorBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setServerPublicKey(publicKey: string): void {
|
setServerPublicKey(publicKey: string): void {
|
||||||
console.log('\n\nSetting server public key\n\n');
|
|
||||||
this.publicKey = publicKey;
|
this.publicKey = publicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
setAesKey(aesKey: string, aesIv: string): void {
|
setAesKey(aesKey: string, aesIv: string): void {
|
||||||
console.log('\n\nSetting AES key\n\n');
|
|
||||||
this.aesKey = Buffer.from(aesKey, 'base64');
|
this.aesKey = Buffer.from(aesKey, 'base64');
|
||||||
this.aesIv = Buffer.from(aesIv, '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> {
|
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 message = MessageHandler.formatMessage(operationCode, metaInfo, fileContent);
|
||||||
|
|
||||||
const outgoingMessage = this.encryptWithAes(message);
|
const outgoingMessage = this.encryptWithAes(message);
|
||||||
|
|
||||||
// Calculate optimal chunk size based on network latency
|
// Calculate optimal chunk size based on network latency
|
||||||
const optimalChunkSize = await this.calculateOptimalChunkSize(outgoingMessage.length);
|
const totalChunks = Math.ceil(outgoingMessage.length / this.CHUNK_SIZE);
|
||||||
const totalChunks = Math.ceil(outgoingMessage.length / optimalChunkSize);
|
|
||||||
const messageId = Date.now().toString();
|
const messageId = Date.now().toString();
|
||||||
|
|
||||||
// Send each chunk with a delay between them
|
// Send each chunk with a delay between them
|
||||||
for (let i = 0; i < totalChunks; i++) {
|
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({
|
const chunkHeader = JSON.stringify({
|
||||||
messageId,
|
messageId,
|
||||||
sequenceNumber: i + 1,
|
sequenceNumber: i + 1,
|
||||||
totalChunks,
|
totalChunks,
|
||||||
});
|
});
|
||||||
const chunkWithHeader = `${chunkHeader}|${chunk}${this.EOP}`;
|
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> {
|
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 message = MessageHandler.formatMessage(operationCode, metaInfo, fileContent);
|
||||||
|
|
||||||
let outgoingMessage: string;
|
let outgoingMessage: string;
|
||||||
@@ -56,21 +52,23 @@ export class TcpServerCommunicator extends SocketCommunicatorBase {
|
|||||||
outgoingMessage = this.encryptWithAes(message);
|
outgoingMessage = this.encryptWithAes(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate optimal chunk size based on network latency
|
const totalChunks = Math.ceil(outgoingMessage.length / this.CHUNK_SIZE);
|
||||||
const optimalChunkSize = await this.calculateOptimalChunkSize(outgoingMessage.length);
|
|
||||||
const totalChunks = Math.ceil(outgoingMessage.length / optimalChunkSize);
|
|
||||||
const messageId = Date.now().toString();
|
const messageId = Date.now().toString();
|
||||||
|
|
||||||
// Send each chunk with a delay between them
|
// Send each chunk with a delay between them
|
||||||
for (let i = 0; i < totalChunks; i++) {
|
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({
|
const chunkHeader = JSON.stringify({
|
||||||
messageId,
|
messageId,
|
||||||
sequenceNumber: i + 1,
|
sequenceNumber: i + 1,
|
||||||
totalChunks,
|
totalChunks,
|
||||||
});
|
});
|
||||||
const chunkWithHeader = `${chunkHeader}|${chunk}${this.EOP}`;
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export class UdpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send heartbeat and get clients that respond with ALIVE, excluding the host machine's IP addresses
|
// 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 subnet = this.getSubnet();
|
||||||
const ipRange = this.getIPRange(subnet);
|
const ipRange = this.getIPRange(subnet);
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ export class UdpClient {
|
|||||||
const aliveClients: string[] = [];
|
const aliveClients: string[] = [];
|
||||||
for (const ip of activeIps) {
|
for (const ip of activeIps) {
|
||||||
if (!localIPs.includes(ip)) {
|
if (!localIPs.includes(ip)) {
|
||||||
const result = await this.sendHeartbeat(ip);
|
const result = await this.sendHeartbeat(ip, heartbeatCode);
|
||||||
if (result.found) {
|
if (result.found) {
|
||||||
aliveClients.push(ip);
|
aliveClients.push(ip);
|
||||||
}
|
}
|
||||||
@@ -73,9 +73,8 @@ export class UdpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send heartbeat to an IP
|
// 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) => {
|
return new Promise((resolve) => {
|
||||||
const heartbeatCode = operationCodes.HEARTBEAT;
|
|
||||||
const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode);
|
const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode);
|
||||||
|
|
||||||
this.log(`Sending heartbeat to ${ip}`);
|
this.log(`Sending heartbeat to ${ip}`);
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
import { workerData, parentPort } from 'worker_threads';
|
import { BackupRetrievalWorker } from '../helpers/backup_retrieval';
|
||||||
import { BackupRetrievalWorker} from '../helpers/backup_retrieval'; // Assuming the class is in the same folder
|
import dotenv from 'dotenv';
|
||||||
|
|
||||||
// Destructure the data passed from the WorkerManager
|
// Load environment variables from .env file if it exists
|
||||||
const {
|
dotenv.config();
|
||||||
userConfigPath,
|
|
||||||
applicationInfoPath,
|
// Retrieve configuration from environment variables
|
||||||
clientPort,
|
const userConfigPath = process.env.USER_CONFIG_PATH as string;
|
||||||
destinationPath
|
const applicationInfoPath = process.env.APPLICATION_INFO_PATH as string;
|
||||||
}: {
|
const clientPort = Number(process.env.CLIENT_PORT);
|
||||||
userConfigPath: string,
|
const destinationPath = process.env.DESTINATION_PATH as string;
|
||||||
applicationInfoPath: string,
|
|
||||||
clientPort: number,
|
// Validate that all required environment variables are present
|
||||||
destinationPath: string
|
if (!userConfigPath || !applicationInfoPath || !clientPort || !destinationPath) {
|
||||||
} = workerData;
|
console.error('Error: Missing required environment variables.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the BackupRetrievalWorker
|
// Initialize the BackupRetrievalWorker
|
||||||
const backupRetrievalWorker = new BackupRetrievalWorker(
|
const backupRetrievalWorker = new BackupRetrievalWorker(
|
||||||
@@ -23,4 +25,26 @@ const backupRetrievalWorker = new BackupRetrievalWorker(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Start the backup retrieval process
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
import {DirectoryWatcher} from "../helpers/directory_watcher";
|
import { DirectoryWatcher } from "../helpers/directory_watcher";
|
||||||
import {workerData} from "worker_threads";
|
import dotenv from 'dotenv';
|
||||||
|
|
||||||
const {
|
// Load environment variables from .env file if it exists
|
||||||
memoryManagerPath,
|
dotenv.config();
|
||||||
applicationInfoPath,
|
|
||||||
} = workerData;
|
|
||||||
|
|
||||||
|
// 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');
|
const backupDirectoryManager = new DirectoryWatcher(memoryManagerPath, applicationInfoPath, 'backupDirectory');
|
||||||
backupDirectoryManager.start();
|
backupDirectoryManager.start();
|
||||||
|
|
||||||
@@ -15,3 +24,21 @@ departmentShareManager.start();
|
|||||||
const shareFileManager = new DirectoryWatcher(memoryManagerPath, applicationInfoPath, 'shareDirectory');
|
const shareFileManager = new DirectoryWatcher(memoryManagerPath, applicationInfoPath, 'shareDirectory');
|
||||||
shareFileManager.start();
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,19 +1,39 @@
|
|||||||
import { parentPort, workerData } from 'worker_threads';
|
import { parentPort } from 'worker_threads';
|
||||||
import { NetworkScanner } from '../helpers/network_scanner';
|
import { NetworkScanner } from '../helpers/network_scanner';
|
||||||
|
|
||||||
// Define the structure of workerData
|
// Extract data from environment variables
|
||||||
interface WorkerData {
|
const udpPort = parseInt(process.env.UDP_PORT || '0', 10);
|
||||||
udpPort: number;
|
const tcpPort = parseInt(process.env.TCP_PORT || '0', 10);
|
||||||
tcpPort: number;
|
const okPage = process.env.OK_PAGE || '';
|
||||||
okPage: string;
|
const errorPage = process.env.ERROR_PAGE || '';
|
||||||
errorPage: string;
|
const databaseResetPage = process.env.DATABASE_RESET_PAGE || '';
|
||||||
databaseResetPage: string;
|
const userConfigPath = process.env.USER_CONFIG_PATH || '';
|
||||||
userConfigPath: string;
|
const applicationInfoPath = process.env.APPLICATION_INFO_PATH || '';
|
||||||
applicationInfoPath: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract the data passed to the worker
|
|
||||||
const { udpPort, tcpPort, okPage, errorPage, databaseResetPage, userConfigPath, applicationInfoPath }: WorkerData = workerData;
|
|
||||||
|
|
||||||
// Start the NetworkScanner instance
|
// 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
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import { workerData } from 'worker_threads';
|
|
||||||
import { UsersInfoFetcher } from '../helpers/users_info_fetcher';
|
import { UsersInfoFetcher } from '../helpers/users_info_fetcher';
|
||||||
import {BackupManager} from "../helpers/backup_manager";
|
import { BackupManager } from '../helpers/backup_manager';
|
||||||
import {FileSharer} from "../helpers/file_sharer";
|
import { FileSharer } from '../helpers/file_sharer';
|
||||||
import {DepartmentSharer} from "../helpers/department_sharer";
|
import { DepartmentSharer } from '../helpers/department_sharer';
|
||||||
|
|
||||||
// Destructure the required information from workerData
|
// Retrieve data from environment variables
|
||||||
const { usersConfigPath, applicationInfoPath, memoryManagerPath, queueManagerPath, tcpPort } = workerData;
|
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);
|
const usersInfoFetcher = new UsersInfoFetcher(applicationInfoPath, memoryManagerPath, tcpPort);
|
||||||
usersInfoFetcher.start();
|
usersInfoFetcher.start();
|
||||||
@@ -16,7 +19,25 @@ backupManager.start();
|
|||||||
const fileSharer = new FileSharer(queueManagerPath, tcpPort);
|
const fileSharer = new FileSharer(queueManagerPath, tcpPort);
|
||||||
fileSharer.start();
|
fileSharer.start();
|
||||||
|
|
||||||
|
|
||||||
const departmentSharer = new DepartmentSharer(usersConfigPath, applicationInfoPath, memoryManagerPath, tcpPort);
|
const departmentSharer = new DepartmentSharer(usersConfigPath, applicationInfoPath, memoryManagerPath, tcpPort);
|
||||||
departmentSharer.start();
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
// Read environment variables passed by WorkerManager
|
||||||
const {
|
const applicationInfoPath = process.env.APPLICATION_INFO_PATH as string;
|
||||||
applicationInfoPath,
|
const clientPort = parseInt(process.env.CLIENT_PORT as string, 10);
|
||||||
clientPort,
|
const message = process.env.MESSAGE as string;
|
||||||
message
|
|
||||||
}: {
|
|
||||||
applicationInfoPath: string,
|
|
||||||
clientPort: number,
|
|
||||||
message: string
|
|
||||||
} = workerData;
|
|
||||||
|
|
||||||
// Initialize the AnnouncementWorker
|
if (!applicationInfoPath || !clientPort || !message) {
|
||||||
const announcementWorker = new AnnouncementSender(applicationInfoPath, clientPort);
|
console.error("Missing necessary environment variables for AnnouncementWorker.");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
// Start the announcement process and handle results
|
// Initialize the AnnouncementSender instance
|
||||||
announcementWorker.start(message);
|
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);
|
||||||
|
|||||||
@@ -1,14 +1,36 @@
|
|||||||
import {UdpServer} from "../network/udp/udp_server";
|
import { UdpServer } from "../network/udp/udp_server";
|
||||||
import {TcpServer} from "../network/tcp/tcp_server";
|
import { TcpServer } from "../network/tcp/tcp_server";
|
||||||
import {workerData} from "worker_threads";
|
|
||||||
|
|
||||||
let udpServer: UdpServer | null = null;
|
let udpServer: UdpServer | null
|
||||||
let tcpServer: TcpServer | null = 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 = new UdpServer(HOST, USER_UDP_PORT);
|
||||||
udpServer.start();
|
udpServer.start();
|
||||||
|
|
||||||
tcpServer = new TcpServer(HOST, USER_TCP_PORT);
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ export class GeneralOperations implements OperationPlugin {
|
|||||||
public static readonly operationCodes = {
|
public static readonly operationCodes = {
|
||||||
OK: 'OK',
|
OK: 'OK',
|
||||||
ERR: 'ERR',
|
ERR: 'ERR',
|
||||||
HEARTBEAT: 'HEARTBEAT',
|
ARE_YOU_UC: 'ARE_YOU_UC',
|
||||||
ALIVE: 'ALIVE',
|
ALIVE: 'ALIVE',
|
||||||
SET_PUBLIC_KEY: 'SET_PUBLIC_KEY',
|
SET_PUBLIC_KEY: 'SET_PUBLIC_KEY',
|
||||||
SET_AES_KEY: 'SET_AES_KEY',
|
SET_AES_KEY: 'SET_AES_KEY',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle heartbeat operation asynchronously
|
// Handle heartbeat operation asynchronously
|
||||||
public static async handleHeartbeat(): Promise<ParsedMessage> {
|
public static async handleAreYouUC(): Promise<ParsedMessage> {
|
||||||
const networkInterfaces = os.networkInterfaces();
|
const networkInterfaces = os.networkInterfaces();
|
||||||
let ipAddress = 'Unknown';
|
let ipAddress = 'Unknown';
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ export class GeneralOperations implements OperationPlugin {
|
|||||||
|
|
||||||
// Register general operations with the OperationHandler
|
// Register general operations with the OperationHandler
|
||||||
public register(operationHandler: OperationHandler): void {
|
public register(operationHandler: OperationHandler): void {
|
||||||
operationHandler.registerHandler(GeneralOperations.operationCodes.HEARTBEAT, GeneralOperations.handleHeartbeat);
|
operationHandler.registerHandler(GeneralOperations.operationCodes.ARE_YOU_UC, GeneralOperations.handleAreYouUC);
|
||||||
operationHandler.registerHandler(GeneralOperations.operationCodes.SET_PUBLIC_KEY, GeneralOperations.handlePublicKey);
|
operationHandler.registerHandler(GeneralOperations.operationCodes.SET_PUBLIC_KEY, GeneralOperations.handlePublicKey);
|
||||||
operationHandler.registerHandler(GeneralOperations.operationCodes.SET_AES_KEY, GeneralOperations.handleAESKey);
|
operationHandler.registerHandler(GeneralOperations.operationCodes.SET_AES_KEY, GeneralOperations.handleAESKey);
|
||||||
operationHandler.registerHandler(GeneralOperations.operationCodes.OK, GeneralOperations.handleOk);
|
operationHandler.registerHandler(GeneralOperations.operationCodes.OK, GeneralOperations.handleOk);
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ export class BackupManager {
|
|||||||
private userConfig: JsonManager;
|
private userConfig: JsonManager;
|
||||||
private readonly clientPort: number;
|
private readonly clientPort: number;
|
||||||
private isBusy: boolean = false;
|
private isBusy: boolean = false;
|
||||||
|
private intervalId: NodeJS.Timeout | null = null;
|
||||||
|
private stopRequested: boolean = false;
|
||||||
|
|
||||||
constructor(userConfigPath: string, applicationInfoPath: string, memoryManagerPath: string, clientPort: number) {
|
constructor(userConfigPath: string, applicationInfoPath: string, memoryManagerPath: string, clientPort: number) {
|
||||||
this.applicationInfo = new JsonManager(applicationInfoPath);
|
this.applicationInfo = new JsonManager(applicationInfoPath);
|
||||||
@@ -23,8 +25,8 @@ export class BackupManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
setInterval(async () => {
|
this.intervalId = setInterval(async () => {
|
||||||
if (!this.isBusy) {
|
if (!this.isBusy || !this.stopRequested) {
|
||||||
this.isBusy = true;
|
this.isBusy = true;
|
||||||
this.log('Start successfully. Backup files to users.');
|
this.log('Start successfully. Backup files to users.');
|
||||||
await this.initialize();
|
await this.initialize();
|
||||||
@@ -160,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
|
// Unified logging function
|
||||||
private log(message: string, level: 'log' | 'error' | 'warn' = 'log'): void {
|
private log(message: string, level: 'log' | 'error' | 'warn' = 'log'): void {
|
||||||
const prefix = '[BackupManager]';
|
const prefix = '[BackupManager]';
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ export class BackupRetrievalWorker {
|
|||||||
private encryptionKey: Buffer | null = null;
|
private encryptionKey: Buffer | null = null;
|
||||||
private iv: Buffer | null = null;
|
private iv: Buffer | null = null;
|
||||||
private tcpCommunicator: TcpCommunicator | null = null;
|
private tcpCommunicator: TcpCommunicator | null = null;
|
||||||
|
private stopRequested: boolean = false;
|
||||||
|
private isBusy: boolean = false;
|
||||||
|
|
||||||
constructor(userConfigPath: string, applicationInfoPath: string, clientPort: number, destinationPath: string) {
|
constructor(userConfigPath: string, applicationInfoPath: string, clientPort: number, destinationPath: string) {
|
||||||
this.userConfig = new JsonManager(userConfigPath);
|
this.userConfig = new JsonManager(userConfigPath);
|
||||||
@@ -33,6 +35,8 @@ export class BackupRetrievalWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
|
if(!this.stopRequested) return;
|
||||||
|
this.isBusy = true;
|
||||||
try {
|
try {
|
||||||
const userInfo = await this.userConfig.readValue('user_info');
|
const userInfo = await this.userConfig.readValue('user_info');
|
||||||
if (!userInfo || !userInfo.name) {
|
if (!userInfo || !userInfo.name) {
|
||||||
@@ -61,10 +65,15 @@ export class BackupRetrievalWorker {
|
|||||||
this.log(`Backup retrieved successfully from ${ip}`);
|
this.log(`Backup retrieved successfully from ${ip}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
process.send?.({ type: 'log', message: 'Backup retrieval completed successfully.' });
|
process.send?.({ type: 'showAlert', message: 'Backup retrieval completed successfully.' });
|
||||||
|
process.send?.({ type: 'changeContent', page: 'main_menu' });
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
this.log(`Error in BackupRetrievalWorker: ${error.message}`, 'error');
|
this.log(`Error in BackupRetrievalWorker: ${error.message}`, 'error');
|
||||||
process.send?.({ type: 'log', 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global.gc) {
|
if (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> {
|
private async waitForResponse(): Promise<ParsedMessage | null> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const idResponseCheck = setInterval(async () => {
|
const idResponseCheck = setInterval(async () => {
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ export class DepartmentSharer {
|
|||||||
private readonly clientPort: number;
|
private readonly clientPort: number;
|
||||||
private isBusy: boolean = false;
|
private isBusy: boolean = false;
|
||||||
private tcpCommunicator: TcpCommunicator | null = null;
|
private tcpCommunicator: TcpCommunicator | null = null;
|
||||||
|
private stopRequested: boolean = false;
|
||||||
|
private intervalId: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
userConfigPath: string,
|
userConfigPath: string,
|
||||||
@@ -30,8 +32,8 @@ export class DepartmentSharer {
|
|||||||
|
|
||||||
// Start sharing files with the department every minute
|
// Start sharing files with the department every minute
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
setInterval(async () => {
|
this.intervalId = setInterval(async () => {
|
||||||
if (!this.isBusy) {
|
if (!this.isBusy || !this.stopRequested) {
|
||||||
this.isBusy = true;
|
this.isBusy = true;
|
||||||
this.log('Start successfully. Sharing files with the department.');
|
this.log('Start successfully. Sharing files with the department.');
|
||||||
await this.shareFilesWithDepartment();
|
await this.shareFilesWithDepartment();
|
||||||
@@ -172,6 +174,22 @@ export class DepartmentSharer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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> {
|
private async waitForResponse(): Promise<ParsedMessage | null> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const idResponseCheck = setInterval(async () => {
|
const idResponseCheck = setInterval(async () => {
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ export class FileSharer {
|
|||||||
private readonly clientPort: number;
|
private readonly clientPort: number;
|
||||||
private isBusy: boolean;
|
private isBusy: boolean;
|
||||||
private tcpCommunicator: TcpCommunicator | null = null;
|
private tcpCommunicator: TcpCommunicator | null = null;
|
||||||
|
private stopRequested: boolean = false;
|
||||||
|
private intervalId: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
constructor(queueFilePath: string, clientPort: number) {
|
constructor(queueFilePath: string, clientPort: number) {
|
||||||
this.queueManager = new QueueManager<FileItemTask>(queueFilePath, compareFnFileItemTask);
|
this.queueManager = new QueueManager<FileItemTask>(queueFilePath, compareFnFileItemTask);
|
||||||
@@ -26,8 +28,8 @@ export class FileSharer {
|
|||||||
|
|
||||||
// Start processing the file queue
|
// Start processing the file queue
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
setInterval(async () => {
|
this.intervalId = setInterval(async () => {
|
||||||
if (!this.isBusy) { // Check if the queue is already being processed
|
if (!this.isBusy || !this.stopRequested) { // Check if the queue is already being processed
|
||||||
this.isBusy = true; // Set busy flag to true before starting
|
this.isBusy = true; // Set busy flag to true before starting
|
||||||
this.log("Start successfully. Processing the queue.");
|
this.log("Start successfully. Processing the queue.");
|
||||||
await this.processQueue();
|
await this.processQueue();
|
||||||
@@ -104,6 +106,22 @@ export class FileSharer {
|
|||||||
return true;
|
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> {
|
private async waitForResponse(): Promise<ParsedMessage | null> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const idResponseCheck = setInterval(async () => {
|
const idResponseCheck = setInterval(async () => {
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export class NetworkScanner {
|
|||||||
try {
|
try {
|
||||||
this.log('UC Check running...', 'log', 'startUCCheck');
|
this.log('UC Check running...', 'log', 'startUCCheck');
|
||||||
const udpClient = new UdpClient(this.udpPort);
|
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 storedIp = await this.applicationInfo.readValue('serverIp');
|
||||||
const foundClient = aliveClients.length > 0;
|
const foundClient = aliveClients.length > 0;
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ export class NetworkScanner {
|
|||||||
this.log('IP Lookup running...', 'log', 'startUserIPLookup');
|
this.log('IP Lookup running...', 'log', 'startUserIPLookup');
|
||||||
const serverIp = await this.applicationInfo.readValue('serverIp');
|
const serverIp = await this.applicationInfo.readValue('serverIp');
|
||||||
const udpClient = new UdpClient(this.udpPort);
|
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);
|
const filteredIPs = activeIPs.filter(ip => ip !== serverIp);
|
||||||
|
|
||||||
// Save the filtered IPs to 'users_ip'
|
// Save the filtered IPs to 'users_ip'
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export class UsersInfoFetcher {
|
|||||||
private readonly clientPort: number;
|
private readonly clientPort: number;
|
||||||
private memoryId: string;
|
private memoryId: string;
|
||||||
private readonly activeUsersKey: string;
|
private readonly activeUsersKey: string;
|
||||||
|
private intervalId: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
constructor(applicationInfoPath: string, memoryManagerPath: string, clientPort: number) {
|
constructor(applicationInfoPath: string, memoryManagerPath: string, clientPort: number) {
|
||||||
this.applicationInfo = new JsonManager(applicationInfoPath);
|
this.applicationInfo = new JsonManager(applicationInfoPath);
|
||||||
@@ -23,13 +24,13 @@ export class UsersInfoFetcher {
|
|||||||
|
|
||||||
// Method to start checking user info periodically (every minute)
|
// Method to start checking user info periodically (every minute)
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
setInterval(async () => {
|
this.intervalId = setInterval(async () => {
|
||||||
await this.initialize(); // Re-run every minute
|
await this.initialize(); // Re-run every minute
|
||||||
|
|
||||||
if (global.gc) {
|
if (global.gc) {
|
||||||
global.gc();
|
global.gc();
|
||||||
}
|
}
|
||||||
}, 5000); // 1 minute interval
|
}, 5000); // 5-second interval for testing
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize and fetch user IPs and process users info
|
// Initialize and fetch user IPs and process users info
|
||||||
@@ -101,6 +102,14 @@ export class UsersInfoFetcher {
|
|||||||
await this.memoryManager.updateMetaInformation(this.memoryId, userInfo); // Update active users in memory
|
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
|
// Unified logging function
|
||||||
private log(message: string, level: 'log' | 'error' = 'log'): void {
|
private log(message: string, level: 'log' | 'error' = 'log'): void {
|
||||||
const prefix = '[UsersInfoFetcher]';
|
const prefix = '[UsersInfoFetcher]';
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import { WindowManager } from "./window_manager";
|
|||||||
export class WorkerManager {
|
export class WorkerManager {
|
||||||
private readonly pathToWorkerDir: string;
|
private readonly pathToWorkerDir: string;
|
||||||
private windowManager: WindowManager;
|
private windowManager: WindowManager;
|
||||||
private workers: ChildProcess[]; // Array to store running child processes
|
private workers: ChildProcess[];
|
||||||
|
private cleanupInProgress: boolean = false;
|
||||||
|
|
||||||
constructor(pathToWorkerDir: string, windowManager: WindowManager) {
|
constructor(pathToWorkerDir: string, windowManager: WindowManager) {
|
||||||
this.pathToWorkerDir = pathToWorkerDir;
|
this.pathToWorkerDir = pathToWorkerDir;
|
||||||
@@ -87,17 +88,24 @@ export class WorkerManager {
|
|||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
worker.on('exit', (code) => {
|
worker.on('exit', (code, signal) => {
|
||||||
console.log(`${scriptName} exited with code ${code}`);
|
|
||||||
this.removeWorker(worker);
|
this.removeWorker(worker);
|
||||||
if (code === 0) resolve();
|
if (code === 0) {
|
||||||
else reject(new Error(`${scriptName} exited with code ${code}`));
|
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 {
|
closeAllWorkers(): void {
|
||||||
|
if (this.cleanupInProgress) return; // Prevent duplicate cleanup
|
||||||
|
this.cleanupInProgress = true;
|
||||||
|
|
||||||
console.log('Terminating all running workers...');
|
console.log('Terminating all running workers...');
|
||||||
this.workers.forEach(worker => worker.kill());
|
this.workers.forEach(worker => worker.kill());
|
||||||
this.workers = [];
|
this.workers = [];
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
export let operationCodes = {
|
export let operationCodes = {
|
||||||
// General Operations
|
// General Operations
|
||||||
HEARTBEAT: 'HEARTBEAT',
|
ARE_YOU_HUMAN: 'ARE_YOU_HUMAN',
|
||||||
|
ARE_YOU_UC: 'ARE_YOU_UC',
|
||||||
ALIVE: 'ALIVE',
|
ALIVE: 'ALIVE',
|
||||||
SET_PUBLIC_KEY: 'SET_PUBLIC_KEY',
|
SET_PUBLIC_KEY: 'SET_PUBLIC_KEY',
|
||||||
SET_AES_KEY: 'SET_AES_KEY',
|
SET_AES_KEY: 'SET_AES_KEY',
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ export class GeneralOperations implements OperationPlugin {
|
|||||||
public static readonly operationCodes = {
|
public static readonly operationCodes = {
|
||||||
OK: 'OK',
|
OK: 'OK',
|
||||||
ERR: 'ERR',
|
ERR: 'ERR',
|
||||||
HEARTBEAT: 'HEARTBEAT',
|
ARE_YOU_HUMAN: 'ARE_YOU_HUMAN',
|
||||||
ALIVE: 'ALIVE',
|
ALIVE: 'ALIVE',
|
||||||
SET_PUBLIC_KEY: 'SET_PUBLIC_KEY',
|
SET_PUBLIC_KEY: 'SET_PUBLIC_KEY',
|
||||||
SET_AES_KEY: 'SET_AES_KEY',
|
SET_AES_KEY: 'SET_AES_KEY',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle heartbeat operation asynchronously
|
// Handle heartbeat operation asynchronously
|
||||||
public static async handleHeartbeat(): Promise<ParsedMessage> {
|
public static async handleAreYouHuman(): Promise<ParsedMessage> {
|
||||||
const networkInterfaces = os.networkInterfaces();
|
const networkInterfaces = os.networkInterfaces();
|
||||||
let ipAddress = 'Unknown';
|
let ipAddress = 'Unknown';
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ export class GeneralOperations implements OperationPlugin {
|
|||||||
|
|
||||||
// Register general operations with the OperationHandler
|
// Register general operations with the OperationHandler
|
||||||
public register(operationHandler: OperationHandler): void {
|
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_PUBLIC_KEY, GeneralOperations.handlePublicKey);
|
||||||
operationHandler.registerHandler(GeneralOperations.operationCodes.SET_AES_KEY, GeneralOperations.handleAESKey);
|
operationHandler.registerHandler(GeneralOperations.operationCodes.SET_AES_KEY, GeneralOperations.handleAESKey);
|
||||||
operationHandler.registerHandler(GeneralOperations.operationCodes.OK, GeneralOperations.handleOk);
|
operationHandler.registerHandler(GeneralOperations.operationCodes.OK, GeneralOperations.handleOk);
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export class UdpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send heartbeat and get clients that respond with ALIVE, excluding the host machine's IP addresses
|
// 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 subnet = this.getSubnet();
|
||||||
const ipRange = this.getIPRange(subnet);
|
const ipRange = this.getIPRange(subnet);
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ export class UdpClient {
|
|||||||
const aliveClients: string[] = [];
|
const aliveClients: string[] = [];
|
||||||
for (const ip of activeIps) {
|
for (const ip of activeIps) {
|
||||||
if (!localIPs.includes(ip)) {
|
if (!localIPs.includes(ip)) {
|
||||||
const result = await this.sendHeartbeat(ip);
|
const result = await this.sendHeartbeat(ip, heartbeatCode);
|
||||||
if (result.found) {
|
if (result.found) {
|
||||||
aliveClients.push(ip);
|
aliveClients.push(ip);
|
||||||
}
|
}
|
||||||
@@ -73,9 +73,8 @@ export class UdpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send heartbeat to an IP
|
// 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) => {
|
return new Promise((resolve) => {
|
||||||
const heartbeatCode = operationCodes.HEARTBEAT;
|
|
||||||
const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode);
|
const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode);
|
||||||
|
|
||||||
this.log(`Sending heartbeat to ${ip}`);
|
this.log(`Sending heartbeat to ${ip}`);
|
||||||
|
|||||||
@@ -25,4 +25,26 @@ const backupRetrievalWorker = new BackupRetrievalWorker(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Start the backup retrieval process
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,3 +23,22 @@ departmentShareManager.start();
|
|||||||
|
|
||||||
const shareFileManager = new DirectoryWatcher(memoryManagerPath, applicationInfoPath, 'shareDirectory');
|
const shareFileManager = new DirectoryWatcher(memoryManagerPath, applicationInfoPath, 'shareDirectory');
|
||||||
shareFileManager.start();
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,3 +20,20 @@ const networkScanner = new NetworkScanner(
|
|||||||
errorPage,
|
errorPage,
|
||||||
databaseResetPage
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,3 +21,23 @@ fileSharer.start();
|
|||||||
|
|
||||||
const departmentSharer = new DepartmentSharer(usersConfigPath, applicationInfoPath, memoryManagerPath, tcpPort);
|
const departmentSharer = new DepartmentSharer(usersConfigPath, applicationInfoPath, memoryManagerPath, tcpPort);
|
||||||
departmentSharer.start();
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { UdpServer } from "../network/udp/udp_server";
|
import { UdpServer } from "../network/udp/udp_server";
|
||||||
import { TcpServer } from "../network/tcp/tcp_server";
|
import { TcpServer } from "../network/tcp/tcp_server";
|
||||||
|
|
||||||
let udpServer: UdpServer | null = null;
|
let udpServer: UdpServer | null
|
||||||
let tcpServer: TcpServer | null = null;
|
let tcpServer: TcpServer | null
|
||||||
|
|
||||||
// Retrieve data from environment variables
|
// Retrieve data from environment variables
|
||||||
const USER_UDP_PORT = parseInt(process.env.USER_UDP_PORT || '0', 10);
|
const USER_UDP_PORT = parseInt(process.env.USER_UDP_PORT || '0', 10);
|
||||||
@@ -15,3 +15,22 @@ udpServer.start();
|
|||||||
|
|
||||||
tcpServer = new TcpServer(HOST, USER_TCP_PORT);
|
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
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user