program finalizat

This commit is contained in:
andrei-mihnea-cerbu
2024-10-29 15:07:26 +02:00
parent ab1eaec413
commit 979539d3db
138 changed files with 14602 additions and 5068 deletions
+57 -159
View File
@@ -1,9 +1,10 @@
import fs from 'fs';
import path from 'path';
import { TcpClient } from '../network/tcp/tcp_client'; // Assuming this class exists
import { TcpCommunicator } from './tcp_communicator'; // Using TcpCommunicator instead of TcpClient
import { operationCodes } from '../network/operation_codes';
import { JsonManager } from './json_manager'; // Manages JSON configurations
import { MemoryManager } from './memory_manager'; // Manages in-memory data structures
import { ParsedMessage } from "../network/message_handler";
export class DepartmentSharer {
private userConfig: JsonManager;
@@ -11,6 +12,8 @@ export class DepartmentSharer {
private memoryManager: MemoryManager; // To read the department files
private departmentDirectory: string | null;
private readonly clientPort: number;
private isBusy: boolean = false; // Busy flag to prevent simultaneous sharing
private tcpCommunicator: TcpCommunicator | null = null; // For each user connection
constructor(
userConfigPath: string,
@@ -20,7 +23,7 @@ export class DepartmentSharer {
) {
this.userConfig = new JsonManager(userConfigPath);
this.applicationInfo = new JsonManager(applicationInfoPath);
this.memoryManager = new MemoryManager(memoryManagerPath); // To retrieve files
this.memoryManager = new MemoryManager(memoryManagerPath);
this.clientPort = clientPort;
this.departmentDirectory = null;
}
@@ -28,7 +31,11 @@ export class DepartmentSharer {
// Start sharing files with the department every minute
async start(): Promise<void> {
setInterval(async () => {
await this.shareFilesWithDepartment(); // Retry every minute
if (!this.isBusy) {
this.isBusy = true;
await this.shareFilesWithDepartment();
this.isBusy = false;
}
}, 10000); // 10-second interval for testing
}
@@ -61,7 +68,6 @@ export class DepartmentSharer {
// Filter users who belong to the same department
const departmentUsers = activeUsers.filter((user: any) => user.user_info.departmentId === departmentId);
if (departmentUsers.length === 0) {
console.log('No users found in the same department.');
return;
@@ -83,15 +89,41 @@ export class DepartmentSharer {
return;
}
// Send each file to every department user
await this.shareFilesWithUsers(departmentUsers, departmentFiles.structure, userName);
// Iterate over all department users and perform the operations
for (const user of departmentUsers) {
const userIp = user.ip;
this.tcpCommunicator = new TcpCommunicator(userIp, this.clientPort);
// After sending all files, clear the department directory
await this.clearDepartmentDirectory(departmentUsers);
if(await this.tcpCommunicator.connect()) continue;
// First clear the department directory
const clearSuccess = await this.clearDepartmentDirectory();
if (clearSuccess) {
await this.sendFilesToUser(departmentFiles.structure, userName);
}
await this.tcpCommunicator.disconnect();
}
}
// Send the files to the users in the department
private async shareFilesWithUsers(users: any[], files: { [key: string]: string }, userName: string): Promise<void> {
// Clear the department directory for a user
private async clearDepartmentDirectory(): Promise<boolean> {
if(!this.tcpCommunicator) return false;
if (!await this.tcpCommunicator.sendMessage(operationCodes.CLEAR_DEPARTMENT)) return false;
const response = await this.waitForResponse();
if (!response || response.operationCode !== operationCodes.OK){
console.error('Failed to clear the department directory.');
return false;
}
return true;
}
// Send the files to a user in the department
private async sendFilesToUser(files: { [key: string]: string }, userName: string): Promise<void> {
if(!this.tcpCommunicator) return;
const unsentFiles = Object.keys(files); // Keep track of unsent files
for (const fileName of unsentFiles) {
@@ -116,163 +148,29 @@ export class DepartmentSharer {
relativeFilePath // Use the relative path to preserve directory structure
};
// Send the file to each user in the same department
for (const user of users) {
const userIp = user.ip;
const tcpClient = new TcpClient(this.clientPort);
// Send the file
if (!await this.tcpCommunicator.sendMessage(operationCodes.DEPARTMENT_FILE, metaInfo, Buffer.from(fileContent))) return;
// Open a connection to the user's IP
tcpClient.openSocket(userIp);
try {
// Wait for the AES key and send the file
const success = await this.waitForAesKeyAndSendFile(tcpClient, operationCodes.DEPARTMENT_FILE, metaInfo, fileContent);
if (success) {
console.log(`File successfully sent: ${fileName} to user ${userIp}`);
unsentFiles.splice(unsentFiles.indexOf(fileName), 1); // Remove successfully sent file
tcpClient.closeSocket(); // Close the connection after sending
break; // Move to the next file after a successful send
}
} catch (error) {
console.error(`Failed to send file: ${fileName} to IP: ${userIp}. Error: ${error}`);
tcpClient.closeSocket(); // Ensure socket is closed on error
}
const response = await this.waitForResponse();
if (!response || response.operationCode !== operationCodes.OK) {
console.error(`Failed to send file: ${fileName}`);
return;
}
}
if (unsentFiles.length > 0) {
console.log('Some files could not be sent, retrying later.');
} else {
console.log('All files shared successfully.');
unsentFiles.splice(unsentFiles.indexOf(fileName), 1);
await this.tcpCommunicator.disconnect();
}
}
// Clear the department directory for all users after sharing
private async clearDepartmentDirectory(users: any[]): Promise<void> {
for (const user of users) {
const userIp = user.ip;
const tcpClient = new TcpClient(this.clientPort);
// Open a connection to the user's IP
tcpClient.openSocket(userIp);
try {
const success = await this.waitForAesKeyAndSendClearDepartment(tcpClient, operationCodes.CLEAR_DEPARTMENT);
if (success) {
console.log(`Department directory cleared successfully for user ${userIp}`);
} else {
console.error(`Failed to clear department directory for user ${userIp}`);
}
} catch (error) {
console.error(`Error clearing department directory for user ${userIp}:`, error);
} finally {
tcpClient.closeSocket(); // Ensure the socket is closed
}
}
}
// Wait for AES key to be set, send the file, and wait for the response
private async waitForAesKeyAndSendFile(tcpClient: TcpClient, operationCode: string, metaInfo: { [key: string]: any }, fileContent: Buffer, checkInterval: number = 500, timeout: number = 10000): Promise<boolean> {
const startTime = Date.now();
return new Promise((resolve, reject) => {
const intervalId = setInterval(async () => {
const elapsedTime = Date.now() - startTime;
// Check if AES key is set, if timeout occurs, reject
if (!tcpClient.isAesKeySet()) {
if (elapsedTime > timeout) {
clearInterval(intervalId);
console.error('Timeout waiting for AES key.');
reject(new Error('Timeout waiting for AES key.'));
}
return; // Continue waiting for AES key
}
// AES key is set, send the file
clearInterval(intervalId);
try {
const success = await tcpClient.sendMessage(operationCode, metaInfo, fileContent);
if (!success) {
reject(new Error('Failed to send the file content.'));
return;
}
// Wait for a response after sending the message
const responseReceived = await this.waitForMessageResponse(tcpClient, timeout);
if (!responseReceived) {
reject(new Error('Timeout waiting for the message response.'));
return;
}
resolve(true); // Everything went fine
} catch (error) {
reject(error);
}
}, checkInterval); // Check for AES key every `checkInterval`
});
}
// Wait for AES key to be set, send the clear department message, and wait for the response
private async waitForAesKeyAndSendClearDepartment(tcpClient: TcpClient, operationCode: string, checkInterval: number = 500, timeout: number = 10000): Promise<boolean> {
const startTime = Date.now();
return new Promise((resolve, reject) => {
const intervalId = setInterval(async () => {
const elapsedTime = Date.now() - startTime;
// Check if AES key is set, if timeout occurs, reject
if (!tcpClient.isAesKeySet()) {
if (elapsedTime > timeout) {
clearInterval(intervalId);
console.error('Timeout waiting for AES key.');
reject(new Error('Timeout waiting for AES key.'));
}
return; // Continue waiting for AES key
}
// AES key is set, send the clear department message
clearInterval(intervalId);
try {
const success = await tcpClient.sendMessage(operationCode, {});
if (!success) {
reject(new Error('Failed to send the clear department operation.'));
return;
}
// Wait for a response after sending the message
const responseReceived = await this.waitForMessageResponse(tcpClient, timeout);
if (!responseReceived) {
reject(new Error('Timeout waiting for the message response.'));
return;
}
resolve(true); // Everything went fine
} catch (error) {
reject(error);
}
}, checkInterval); // Check for AES key every `checkInterval`
});
}
// Wait for the response from the TCP client
private waitForMessageResponse(tcpClient: TcpClient, timeout: number = 10000): Promise<boolean> {
private async waitForResponse(): Promise<ParsedMessage | null> {
return new Promise((resolve) => {
const startTime = Date.now();
const intervalId = setInterval(() => {
const response = tcpClient.getLastResult();
const elapsedTime = Date.now() - startTime;
if (response?.operationCode === operationCodes.OK) {
clearInterval(intervalId);
resolve(true); // Message successfully received
} else if (elapsedTime > timeout) {
clearInterval(intervalId);
resolve(false); // No response after timeout
const idResponseCheck = setInterval(async () => {
if (!this.tcpCommunicator) return null;
if (this.tcpCommunicator.hasResponseArrived()) {
clearInterval(idResponseCheck);
resolve(this.tcpCommunicator.getLastResult()); // Resolve the response or null if not available
}
}, 100); // Check every 100ms
}, 100); // Check every 100 milliseconds if the response has arrived
});
}
}