network chunk v20

This commit is contained in:
andrei-mihnea-cerbu
2024-11-13 17:23:21 +02:00
parent f95b67f93d
commit 9baec7a7cb
41 changed files with 714 additions and 392 deletions
+20 -2
View File
@@ -14,6 +14,8 @@ export class BackupManager {
private userConfig: JsonManager;
private readonly clientPort: number;
private isBusy: boolean = false;
private intervalId: NodeJS.Timeout | null = null;
private stopRequested: boolean = false;
constructor(userConfigPath: string, applicationInfoPath: string, memoryManagerPath: string, clientPort: number) {
this.applicationInfo = new JsonManager(applicationInfoPath);
@@ -23,8 +25,8 @@ export class BackupManager {
}
async start(): Promise<void> {
setInterval(async () => {
if (!this.isBusy) {
this.intervalId = setInterval(async () => {
if (!this.isBusy || !this.stopRequested) {
this.isBusy = true;
this.log('Start successfully. Backup files to users.');
await this.initialize();
@@ -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
private log(message: string, level: 'log' | 'error' | 'warn' = 'log'): void {
const prefix = '[BackupManager]';
+22 -2
View File
@@ -14,6 +14,8 @@ export class BackupRetrievalWorker {
private encryptionKey: Buffer | null = null;
private iv: Buffer | null = null;
private tcpCommunicator: TcpCommunicator | null = null;
private stopRequested: boolean = false;
private isBusy: boolean = false;
constructor(userConfigPath: string, applicationInfoPath: string, clientPort: number, destinationPath: string) {
this.userConfig = new JsonManager(userConfigPath);
@@ -33,6 +35,8 @@ export class BackupRetrievalWorker {
}
async start(): Promise<void> {
if(!this.stopRequested) return;
this.isBusy = true;
try {
const userInfo = await this.userConfig.readValue('user_info');
if (!userInfo || !userInfo.name) {
@@ -61,10 +65,15 @@ export class BackupRetrievalWorker {
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) {
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) {
@@ -172,6 +181,17 @@ export class BackupRetrievalWorker {
}
}
async stop(): Promise<void> {
this.stopRequested = true; // Signal that stop is requested
// Wait for any ongoing process to complete if busy
while (this.isBusy) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
console.log("[BackupManager] Stopped successfully.");
}
private async waitForResponse(): Promise<ParsedMessage | null> {
return new Promise((resolve) => {
const idResponseCheck = setInterval(async () => {
+20 -2
View File
@@ -14,6 +14,8 @@ export class DepartmentSharer {
private readonly clientPort: number;
private isBusy: boolean = false;
private tcpCommunicator: TcpCommunicator | null = null;
private stopRequested: boolean = false;
private intervalId: NodeJS.Timeout | null = null;
constructor(
userConfigPath: string,
@@ -30,8 +32,8 @@ export class DepartmentSharer {
// Start sharing files with the department every minute
async start(): Promise<void> {
setInterval(async () => {
if (!this.isBusy) {
this.intervalId = setInterval(async () => {
if (!this.isBusy || !this.stopRequested) {
this.isBusy = true;
this.log('Start successfully. Sharing files with the department.');
await this.shareFilesWithDepartment();
@@ -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> {
return new Promise((resolve) => {
const idResponseCheck = setInterval(async () => {
+20 -2
View File
@@ -17,6 +17,8 @@ export class FileSharer {
private readonly clientPort: number;
private isBusy: boolean;
private tcpCommunicator: TcpCommunicator | null = null;
private stopRequested: boolean = false;
private intervalId: NodeJS.Timeout | null = null;
constructor(queueFilePath: string, clientPort: number) {
this.queueManager = new QueueManager<FileItemTask>(queueFilePath, compareFnFileItemTask);
@@ -26,8 +28,8 @@ export class FileSharer {
// Start processing the file queue
async start(): Promise<void> {
setInterval(async () => {
if (!this.isBusy) { // Check if the queue is already being processed
this.intervalId = setInterval(async () => {
if (!this.isBusy || !this.stopRequested) { // Check if the queue is already being processed
this.isBusy = true; // Set busy flag to true before starting
this.log("Start successfully. Processing the queue.");
await this.processQueue();
@@ -104,6 +106,22 @@ export class FileSharer {
return true;
}
async stop(): Promise<void> {
this.stopRequested = true; // Signal that stop is requested
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
// Wait for any ongoing process to complete if busy
while (this.isBusy) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
console.log("[BackupManager] Stopped successfully.");
}
private async waitForResponse(): Promise<ParsedMessage | null> {
return new Promise((resolve) => {
const idResponseCheck = setInterval(async () => {
+2 -2
View File
@@ -54,7 +54,7 @@ export class NetworkScanner {
try {
this.log('UC Check running...', 'log', 'startUCCheck');
const udpClient = new UdpClient(this.udpPort);
const aliveClients = await udpClient.getAliveClients();
const aliveClients = await udpClient.getTargetClients(operationCodes.ARE_YOU_UC);
const storedIp = await this.applicationInfo.readValue('serverIp');
const foundClient = aliveClients.length > 0;
@@ -95,7 +95,7 @@ export class NetworkScanner {
this.log('IP Lookup running...', 'log', 'startUserIPLookup');
const serverIp = await this.applicationInfo.readValue('serverIp');
const udpClient = new UdpClient(this.udpPort);
const activeIPs = await udpClient.getAliveClients();
const activeIPs = await udpClient.getTargetClients(operationCodes.ARE_YOU_HUMAN);
const filteredIPs = activeIPs.filter(ip => ip !== serverIp);
// Save the filtered IPs to 'users_ip'
+11 -2
View File
@@ -11,6 +11,7 @@ export class UsersInfoFetcher {
private readonly clientPort: number;
private memoryId: string;
private readonly activeUsersKey: string;
private intervalId: NodeJS.Timeout | null = null;
constructor(applicationInfoPath: string, memoryManagerPath: string, clientPort: number) {
this.applicationInfo = new JsonManager(applicationInfoPath);
@@ -23,13 +24,13 @@ export class UsersInfoFetcher {
// Method to start checking user info periodically (every minute)
async start(): Promise<void> {
setInterval(async () => {
this.intervalId = setInterval(async () => {
await this.initialize(); // Re-run every minute
if (global.gc) {
global.gc();
}
}, 5000); // 1 minute interval
}, 5000); // 5-second interval for testing
}
// 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
}
stop(): void {
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
console.log("[UsersInfoFetcher] Stopped successfully.");
}
}
// Unified logging function
private log(message: string, level: 'log' | 'error' = 'log'): void {
const prefix = '[UsersInfoFetcher]';
+14 -6
View File
@@ -5,7 +5,8 @@ import { WindowManager } from "./window_manager";
export class WorkerManager {
private readonly pathToWorkerDir: string;
private windowManager: WindowManager;
private workers: ChildProcess[]; // Array to store running child processes
private workers: ChildProcess[];
private cleanupInProgress: boolean = false;
constructor(pathToWorkerDir: string, windowManager: WindowManager) {
this.pathToWorkerDir = pathToWorkerDir;
@@ -87,17 +88,24 @@ export class WorkerManager {
reject(err);
});
worker.on('exit', (code) => {
console.log(`${scriptName} exited with code ${code}`);
worker.on('exit', (code, signal) => {
this.removeWorker(worker);
if (code === 0) resolve();
else reject(new Error(`${scriptName} exited with code ${code}`));
if (code === 0) {
console.log(`${scriptName} exited successfully`);
resolve();
} else if (signal) {
console.log(`${scriptName} was killed with signal: ${signal}`);
} else {
console.error(`${scriptName} exited with code: ${code}`);;
}
});
});
}
// Close all running workers
closeAllWorkers(): void {
if (this.cleanupInProgress) return; // Prevent duplicate cleanup
this.cleanupInProgress = true;
console.log('Terminating all running workers...');
this.workers.forEach(worker => worker.kill());
this.workers = [];
+2 -1
View File
@@ -1,6 +1,7 @@
export let operationCodes = {
// General Operations
HEARTBEAT: 'HEARTBEAT',
ARE_YOU_HUMAN: 'ARE_YOU_HUMAN',
ARE_YOU_UC: 'ARE_YOU_UC',
ALIVE: 'ALIVE',
SET_PUBLIC_KEY: 'SET_PUBLIC_KEY',
SET_AES_KEY: 'SET_AES_KEY',
@@ -7,14 +7,14 @@ export class GeneralOperations implements OperationPlugin {
public static readonly operationCodes = {
OK: 'OK',
ERR: 'ERR',
HEARTBEAT: 'HEARTBEAT',
ARE_YOU_HUMAN: 'ARE_YOU_HUMAN',
ALIVE: 'ALIVE',
SET_PUBLIC_KEY: 'SET_PUBLIC_KEY',
SET_AES_KEY: 'SET_AES_KEY',
};
// Handle heartbeat operation asynchronously
public static async handleHeartbeat(): Promise<ParsedMessage> {
public static async handleAreYouHuman(): Promise<ParsedMessage> {
const networkInterfaces = os.networkInterfaces();
let ipAddress = 'Unknown';
@@ -79,7 +79,7 @@ export class GeneralOperations implements OperationPlugin {
// Register general operations with the OperationHandler
public register(operationHandler: OperationHandler): void {
operationHandler.registerHandler(GeneralOperations.operationCodes.HEARTBEAT, GeneralOperations.handleHeartbeat);
operationHandler.registerHandler(GeneralOperations.operationCodes.ARE_YOU_HUMAN, GeneralOperations.handleAreYouHuman);
operationHandler.registerHandler(GeneralOperations.operationCodes.SET_PUBLIC_KEY, GeneralOperations.handlePublicKey);
operationHandler.registerHandler(GeneralOperations.operationCodes.SET_AES_KEY, GeneralOperations.handleAESKey);
operationHandler.registerHandler(GeneralOperations.operationCodes.OK, GeneralOperations.handleOk);
+3 -4
View File
@@ -29,7 +29,7 @@ export class UdpClient {
}
// Send heartbeat and get clients that respond with ALIVE, excluding the host machine's IP addresses
async getAliveClients(): Promise<string[]> {
async getTargetClients(heartbeatCode: string): Promise<string[]> {
const subnet = this.getSubnet();
const ipRange = this.getIPRange(subnet);
@@ -45,7 +45,7 @@ export class UdpClient {
const aliveClients: string[] = [];
for (const ip of activeIps) {
if (!localIPs.includes(ip)) {
const result = await this.sendHeartbeat(ip);
const result = await this.sendHeartbeat(ip, heartbeatCode);
if (result.found) {
aliveClients.push(ip);
}
@@ -73,9 +73,8 @@ export class UdpClient {
}
// Send heartbeat to an IP
private async sendHeartbeat(ip: string): Promise<{ found: boolean }> {
private async sendHeartbeat(ip: string, heartbeatCode: string): Promise<{ found: boolean }> {
return new Promise((resolve) => {
const heartbeatCode = operationCodes.HEARTBEAT;
const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode);
this.log(`Sending heartbeat to ${ip}`);
+23 -1
View File
@@ -25,4 +25,26 @@ const backupRetrievalWorker = new BackupRetrievalWorker(
);
// Start the backup retrieval process
backupRetrievalWorker.start();
backupRetrievalWorker.start().then(() => {
console.log('Backup retrieval process completed successfully.');
});
process.on('SIGTERM', async () => {
console.log('Received SIGTERM. Cleaning up...');
await cleanupAndExit();
});
process.on('SIGINT', async () => {
console.log('Received SIGINT. Cleaning up...');
await cleanupAndExit();
});
async function cleanupAndExit() {
// Perform any cleanup, such as closing connections, saving data, etc.
// Example: if you have a server instance running, you may want to close it:
// await server.close();
console.log('Cleanup complete. Exiting.');
process.exit(0); // Exit with code 0 to indicate a clean exit
}
@@ -23,3 +23,22 @@ departmentShareManager.start();
const shareFileManager = new DirectoryWatcher(memoryManagerPath, applicationInfoPath, 'shareDirectory');
shareFileManager.start();
process.on('SIGTERM', async () => {
console.log('Received SIGTERM. Cleaning up...');
await cleanupAndExit();
});
process.on('SIGINT', async () => {
console.log('Received SIGINT. Cleaning up...');
await cleanupAndExit();
});
async function cleanupAndExit() {
backupDirectoryManager.closeWatcher();
departmentShareManager.closeWatcher();
shareFileManager.closeWatcher();
console.log('Cleanup complete. Exiting.');
process.exit(0); // Exit with code 0 to indicate a clean exit
}
@@ -20,3 +20,20 @@ const networkScanner = new NetworkScanner(
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
}
@@ -21,3 +21,23 @@ fileSharer.start();
const departmentSharer = new DepartmentSharer(usersConfigPath, applicationInfoPath, memoryManagerPath, tcpPort);
departmentSharer.start();
process.on('SIGTERM', async () => {
console.log('Received SIGTERM. Cleaning up...');
await cleanupAndExit();
});
process.on('SIGINT', async () => {
console.log('Received SIGINT. Cleaning up...');
await cleanupAndExit();
});
async function cleanupAndExit() {
usersInfoFetcher.stop();
await backupManager.stop();
await fileSharer.stop();
await departmentSharer.stop();
console.log('Cleanup complete. Exiting.');
process.exit(0); // Exit with code 0 to indicate a clean exit
}
+21 -2
View File
@@ -1,8 +1,8 @@
import { UdpServer } from "../network/udp/udp_server";
import { TcpServer } from "../network/tcp/tcp_server";
let udpServer: UdpServer | null = null;
let tcpServer: TcpServer | null = null;
let udpServer: UdpServer | null
let tcpServer: TcpServer | null
// Retrieve data from environment variables
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.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
}