147 lines
5.3 KiB
TypeScript
147 lines
5.3 KiB
TypeScript
import fs from "fs";
|
|
import path from "path";
|
|
import { QueueManager } from './queue_manager';
|
|
import { TcpCommunicator } from "./tcp_communicator";
|
|
import { operationCodes } from '../network/operation_codes';
|
|
import { compareFnFileItemTask, FileItemTask } from "../interfaces/file_item_task";
|
|
import { ParsedMessage } from "../network/message_handler";
|
|
|
|
interface FileSendTask {
|
|
ip: string;
|
|
path: string;
|
|
userName: string;
|
|
}
|
|
|
|
export class FileSharer {
|
|
private queueManager: QueueManager<FileSendTask>;
|
|
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);
|
|
this.clientPort = clientPort;
|
|
this.isBusy = false; // Initialize the busy flag
|
|
}
|
|
|
|
// Start processing the file queue
|
|
async start(): Promise<void> {
|
|
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();
|
|
}
|
|
|
|
if (global.gc) {
|
|
global.gc();
|
|
}
|
|
}, 10000); // 10 seconds interval
|
|
}
|
|
|
|
// Method to process the queue
|
|
private async processQueue(): Promise<void> {
|
|
while (!this.queueManager.isEmpty()) {
|
|
const task = this.queueManager.peek();
|
|
this.log('trimiti fisier');
|
|
|
|
if (task) {
|
|
this.log(`Processing task for file: ${task.path} to IP: ${task.ip}`);
|
|
const success = await this.sendFile(task);
|
|
|
|
if (!success) {
|
|
this.log(`Failed to send file: ${task.path} to IP: ${task.ip}. Re-adding to queue.`, 'error');
|
|
this.queueManager.dequeue();
|
|
this.queueManager.enqueue(task); // Re-add to queue if failed
|
|
} else {
|
|
this.log(`File sent successfully: ${task.path} to IP: ${task.ip}`);
|
|
this.queueManager.dequeue();
|
|
}
|
|
}
|
|
}
|
|
this.isBusy = false; // Reset busy flag after the queue is processed
|
|
}
|
|
|
|
// Method to send the file to a specific IP using TcpCommunicator
|
|
private async sendFile(task: FileSendTask): Promise<boolean> {
|
|
const { ip, path: filePath, userName } = task;
|
|
|
|
// Ensure the file exists before attempting to send
|
|
if (!fs.existsSync(filePath)) {
|
|
this.log(`File not found: ${filePath}`, 'error');
|
|
return false;
|
|
}
|
|
|
|
// Read the file contents
|
|
const fileContent = fs.readFileSync(filePath);
|
|
|
|
// Extract the file name from the file path using path.basename
|
|
const fileName = path.basename(filePath);
|
|
|
|
const metaInfo = {
|
|
userName, // Sender's username
|
|
relativeFilePath: fileName, // Use the file name instead of the full path
|
|
};
|
|
|
|
this.tcpCommunicator = new TcpCommunicator(ip, this.clientPort);
|
|
|
|
if (!await this.tcpCommunicator.connect()) {
|
|
this.log(`Failed to connect to IP: ${ip}`, 'error');
|
|
return false;
|
|
}
|
|
|
|
this.log(`Sending file: ${filePath} to IP: ${ip}`);
|
|
|
|
if (!await this.tcpCommunicator.sendMessage(operationCodes.SHARE_FILE, metaInfo, fileContent)) return false;
|
|
|
|
const response = await this.waitForResponse();
|
|
if (!response || response.operationCode !== operationCodes.OK) {
|
|
this.log(`Failed to send file: ${filePath} to IP: ${ip}`, 'error');
|
|
return false;
|
|
}
|
|
|
|
await this.tcpCommunicator.disconnect();
|
|
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 () => {
|
|
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 100 milliseconds if the response has arrived
|
|
});
|
|
}
|
|
|
|
// Unified logging function
|
|
private log(message: string, level: 'log' | 'error' = 'log'): void {
|
|
const prefix = '[FileSharer]';
|
|
if (level === 'error') {
|
|
console.error(`${prefix} ${message}`);
|
|
} else {
|
|
console.log(`${prefix} ${message}`);
|
|
}
|
|
}
|
|
}
|