Files
FACULTATE-LICENTA/CEO/src/helpers/department_sharer.ts
T
2024-11-13 17:23:21 +02:00

215 lines
8.1 KiB
TypeScript

import fs from 'fs';
import path from 'path';
import { TcpCommunicator } from './tcp_communicator';
import { operationCodes } from '../network/operation_codes';
import { JsonManager } from './json_manager';
import { MemoryManager } from './memory_manager';
import { ParsedMessage } from "../network/message_handler";
export class DepartmentSharer {
private userConfig: JsonManager;
private applicationInfo: JsonManager;
private memoryManager: MemoryManager;
private departmentDirectory: string | null;
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,
applicationInfoPath: string,
memoryManagerPath: string,
clientPort: number
) {
this.userConfig = new JsonManager(userConfigPath);
this.applicationInfo = new JsonManager(applicationInfoPath);
this.memoryManager = new MemoryManager(memoryManagerPath);
this.clientPort = clientPort;
this.departmentDirectory = null;
}
// Start sharing files with the department every minute
async start(): Promise<void> {
this.intervalId = setInterval(async () => {
if (!this.isBusy || !this.stopRequested) {
this.isBusy = true;
this.log('Start successfully. Sharing files with the department.');
await this.shareFilesWithDepartment();
}
if (global.gc) {
global.gc();
}
}, 10000); // 10-second interval for testing
}
// Share files with users in the same department
private async shareFilesWithDepartment(): Promise<void> {
try {
// Get the current user's department information
const userInfo = await this.userConfig.readValue('user_info');
if (!userInfo || !userInfo.departmentId || !userInfo.name) {
throw new Error('User information or department ID is missing in the configuration.');
}
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) {
throw new Error('No active users found.');
}
const activeUsers = await this.memoryManager.retrieveMetaInformation(activeUsersId);
if (!activeUsers || activeUsers.length === 0) {
throw new Error('No active users found.');
}
// Filter users who belong to the same department
const departmentUsers = activeUsers.filter((user: any) => user.user_info.departmentId === departmentId);
if (departmentUsers.length === 0) {
throw new Error('No users found in the same department.');
}
// Get department directory info
const departmentData = await this.applicationInfo.readValue('departmentDirectory');
if (!departmentData || !departmentData.path || !departmentData.id) {
throw new Error('No department directory found.');
}
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) {
throw new Error('No files found for this department in the memory manager.');
}
// 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);
if (!await this.tcpCommunicator.connect()) continue;
// First clear the department directory;
if (await this.clearDepartmentDirectory(userName)) {
await this.sendFilesToUser(departmentFiles.structure, userName);
}
await this.tcpCommunicator.disconnect();
}
}
catch(error: any) {
this.log(error.message, 'error');
}
finally{
this.log('Department sharing completed.');
this.isBusy = false;
}
}
// Clear the department directory for a user
private async clearDepartmentDirectory(userName: string): Promise<boolean> {
if(!this.tcpCommunicator) return false;
if (!await this.tcpCommunicator.sendMessage(operationCodes.CLEAR_DEPARTMENT, {userName: userName})) return false;
const response = await this.waitForResponse();
if (!response || response.operationCode !== operationCodes.OK){
this.log('Failed to clear the department directory.', 'error');
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);
console.log(`\n\n${unsentFiles}\n\n`);
for (const fileName of unsentFiles) {
const filePath = files[fileName];
// Ensure the file exists before attempting to send
if (!fs.existsSync(filePath)) {
this.log(`File not found: ${filePath}`, 'error');
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,
relativeFilePath
};
// Send the file
if (!await this.tcpCommunicator.sendMessage(operationCodes.DEPARTMENT_FILE, metaInfo, Buffer.from(fileContent))) return;
console.log(`\n\nSending file: ${fileName} to ${userName}\n\n`);
const response = await this.waitForResponse();
if (!response || response.operationCode !== operationCodes.OK) {
this.log(`Failed to send file: ${fileName}`, 'error');
return;
}
this.log(`File sent successfully: ${fileName} to ${userName}`);
unsentFiles.splice(unsentFiles.indexOf(fileName), 1);
await this.tcpCommunicator.disconnect();
}
}
async stop(): Promise<void> {
this.stopRequested = true; // Signal that stop is requested
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
// Wait for any ongoing process to complete if busy
while (this.isBusy) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
console.log("[BackupManager] Stopped successfully.");
}
private async waitForResponse(): Promise<ParsedMessage | null> {
return new Promise((resolve) => {
const idResponseCheck = setInterval(async () => {
if (!this.tcpCommunicator) return null;
if (this.tcpCommunicator.hasResponseArrived()) {
clearInterval(idResponseCheck);
resolve(this.tcpCommunicator.getLastResult());
}
}, 100);
});
}
// Unified logging function
private log(message: string, level: 'log' | 'error' = 'log'): void {
const prefix = '[DepartmentSharer]';
if (level === 'error') {
console.error(`${prefix} ${message}`);
} else {
console.log(`${prefix} ${message}`);
}
}
}