BACKEND DONE FOR ALL APPS
This commit is contained in:
@@ -0,0 +1,278 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { TcpClient } from '../network/tcp/tcp_client'; // Assuming this class exists
|
||||
import { operationCodes } from '../network/operation_codes';
|
||||
import { JsonManager } from './json_manager'; // Manages JSON configurations
|
||||
import { MemoryManager } from './memory_manager'; // Manages in-memory data structures
|
||||
|
||||
export class DepartmentSharer {
|
||||
private userConfig: JsonManager;
|
||||
private applicationInfo: JsonManager;
|
||||
private memoryManager: MemoryManager; // To read the department files
|
||||
private departmentDirectory: string | null;
|
||||
private readonly clientPort: number;
|
||||
|
||||
constructor(
|
||||
userConfigPath: string,
|
||||
applicationInfoPath: string,
|
||||
memoryManagerPath: string,
|
||||
clientPort: number
|
||||
) {
|
||||
this.userConfig = new JsonManager(userConfigPath);
|
||||
this.applicationInfo = new JsonManager(applicationInfoPath);
|
||||
this.memoryManager = new MemoryManager(memoryManagerPath); // To retrieve files
|
||||
this.clientPort = clientPort;
|
||||
this.departmentDirectory = null;
|
||||
}
|
||||
|
||||
// Start sharing files with the department every minute
|
||||
async start(): Promise<void> {
|
||||
setInterval(async () => {
|
||||
await this.shareFilesWithDepartment(); // Retry every minute
|
||||
}, 10000); // 10-second interval for testing
|
||||
}
|
||||
|
||||
// Share files with users in the same department
|
||||
private async shareFilesWithDepartment(): Promise<void> {
|
||||
console.log('\n\nStarting Department Share Process\n\n');
|
||||
|
||||
// Get the current user's department information
|
||||
const userInfo = await this.userConfig.readValue('user_info');
|
||||
if (!userInfo || !userInfo.departmentId || !userInfo.name) {
|
||||
console.error('User information or department ID is missing in the configuration.');
|
||||
return;
|
||||
}
|
||||
|
||||
const departmentId = userInfo.departmentId;
|
||||
const userName = userInfo.name;
|
||||
|
||||
// Get the list of active users from applicationInfo
|
||||
const activeUsersId = await this.applicationInfo.readValue('active_users_info');
|
||||
if (!activeUsersId) {
|
||||
console.error('No active users found.');
|
||||
return;
|
||||
}
|
||||
|
||||
const activeUsers = await this.memoryManager.retrieveMetaInformation(activeUsersId);
|
||||
if (!activeUsers || activeUsers.length === 0) {
|
||||
console.error('No active users found.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Get department directory info
|
||||
const departmentData = await this.applicationInfo.readValue('departmentDirectory');
|
||||
if (!departmentData || !departmentData.path || !departmentData.id) {
|
||||
console.error('No department directory found.');
|
||||
return;
|
||||
}
|
||||
|
||||
this.departmentDirectory = departmentData.path;
|
||||
|
||||
// Read files from the MemoryManager related to this department
|
||||
const departmentFiles = await this.memoryManager.retrieveMetaInformation(departmentData.id);
|
||||
if (!departmentFiles || !departmentFiles.structure) {
|
||||
console.error('No files found for this department in the memory manager.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Send each file to every department user
|
||||
await this.shareFilesWithUsers(departmentUsers, departmentFiles.structure, userName);
|
||||
|
||||
// After sending all files, clear the department directory
|
||||
await this.clearDepartmentDirectory(departmentUsers);
|
||||
}
|
||||
|
||||
// Send the files to the users in the department
|
||||
private async shareFilesWithUsers(users: any[], files: { [key: string]: string }, userName: string): Promise<void> {
|
||||
const unsentFiles = Object.keys(files); // Keep track of unsent files
|
||||
|
||||
for (const fileName of unsentFiles) {
|
||||
const filePath = files[fileName];
|
||||
|
||||
// Ensure the file exists before attempting to send
|
||||
if (!fs.existsSync(filePath)) {
|
||||
console.error(`File not found: ${filePath}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read the file content
|
||||
const fileContent = fs.readFileSync(filePath);
|
||||
|
||||
// Get the relative path of the file (used in the meta info)
|
||||
if (!this.departmentDirectory) return;
|
||||
const relativeFilePath = path.relative(this.departmentDirectory, filePath);
|
||||
|
||||
// Prepare the metaInfo (same structure as FileSharer)
|
||||
const metaInfo = {
|
||||
userName, // Sender's username
|
||||
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);
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (unsentFiles.length > 0) {
|
||||
console.log('Some files could not be sent, retrying later.');
|
||||
} else {
|
||||
console.log('All files shared successfully.');
|
||||
}
|
||||
}
|
||||
|
||||
// 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> {
|
||||
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
|
||||
}
|
||||
}, 100); // Check every 100ms
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user