import {JsonManager} from "./json_manager"; import {UdpClient} from "../network/udp/udp_client"; import {parentPort} from "worker_threads"; import {TcpCommunicator} from "./tcp_communicator"; import {operationCodes} from "../network/operation_codes"; import {ParsedMessage} from "../network/message_handler"; export class NetworkScanner { private applicationInfo: JsonManager; private userConfig: JsonManager; private readonly udpPort: number; private readonly tcpPort: number; private readonly okPage: string; private readonly errorPage: string; private readonly databaseResetPage: string; private appStarted = false; private intervalIds: NodeJS.Timeout[] = []; // Flags to prevent overlapping executions private ucCheckBusy = false; private ipLookupBusy = false; private sendLoginBusy = false; constructor(applicationInfoPath: string, userConfigPath: string, udpPort: number, tcpPort: number, okPage: string, errorPage: string, databaseResetPage: string) { this.applicationInfo = new JsonManager(applicationInfoPath); this.userConfig = new JsonManager(userConfigPath); this.udpPort = udpPort; this.tcpPort = tcpPort; this.okPage = okPage; this.errorPage = errorPage; this.databaseResetPage = databaseResetPage; // Start tasks this.startUCCheck(); this.startUserIPLookup(); this.sendLoginRequest(); } // Log helper function for consistent logging format private log(message: string, level: 'log' | 'error' = 'log', methodName: string = ''): void { const prefix = `[NetworkScanner${methodName ? `.${methodName}` : ''}]`; if (level === 'error') { console.error(`${prefix} ${message}`); } else { console.log(`${prefix} ${message}`); } } // UC Check Task private startUCCheck(interval: number = 5000): void { const intervalId = setInterval(async () => { if (this.ucCheckBusy) return; this.ucCheckBusy = true; try { this.log('UC Check running...', 'log', 'startUCCheck'); const udpClient = new UdpClient(this.udpPort); const aliveClients = await udpClient.getAliveClients(); const storedIp = await this.applicationInfo.readValue('serverIp'); const foundClient = aliveClients.length > 0; if (foundClient) { const ipAddress = aliveClients[0]; // Use the first alive client if (!storedIp || storedIp !== ipAddress) { await this.applicationInfo.writeValue('serverIp', ipAddress); if (!this.appStarted) { parentPort?.postMessage({ type: 'changeContent', page: this.okPage }); } this.appStarted = true; } else if (!this.appStarted) { parentPort?.postMessage({ type: 'changeContent', page: this.okPage }); this.appStarted = true; } } else { parentPort?.postMessage({ type: 'changeContent', page: this.errorPage }); } } catch (err) { this.log(`Error checking UC: ${err}`, 'error', 'startUCCheck'); parentPort?.postMessage({ type: 'changeContent', page: this.errorPage }); } finally { this.ucCheckBusy = false; } }, interval); this.intervalIds.push(intervalId); } // IP Lookup Task private startUserIPLookup(interval: number = 10000): void { const intervalId = setInterval(async () => { if (this.ipLookupBusy) return; this.ipLookupBusy = true; try { 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 filteredIPs = activeIPs.filter(ip => ip !== serverIp); // Save the filtered IPs to 'users_ip' await this.applicationInfo.writeValue('users_ip', filteredIPs); } catch (err) { this.log(`Error during user IP lookup: ${err}`, 'error', 'startUserIPLookup'); } finally { this.ipLookupBusy = false; } }, interval); this.intervalIds.push(intervalId); } // Login Request Task private sendLoginRequest(interval: number = 5000): void { const intervalId = setInterval(async () => { if (this.sendLoginBusy || this.appStarted) return; this.sendLoginBusy = true; try { const userInfo = await this.userConfig.readValue('user_info'); if (!userInfo || !userInfo.email || !userInfo.password) { this.log("Email or password not found in user config.", 'error', 'sendLoginRequest'); return; } const app_type = await this.userConfig.readValue('app_type'); const email = userInfo.email; const password = userInfo.password; const serverIp = await this.applicationInfo.readValue('serverIp'); if (!serverIp) { this.log("Server IP not found in application info.", 'error', 'sendLoginRequest'); return; } const tcpCommunicator = new TcpCommunicator(serverIp, this.tcpPort); if (!await tcpCommunicator.connect()) { this.log("Failed to connect to the server.", 'error', 'sendLoginRequest'); return; } const metaInfo = { email, password, app_type }; if (!await tcpCommunicator.sendMessage(operationCodes.LOGIN, metaInfo)) { this.log("Failed to send login request.", 'error', 'sendLoginRequest'); await tcpCommunicator.disconnect(); return; } const response = await this.waitForResponse(tcpCommunicator); if (response?.operationCode !== operationCodes.OK) { await this.userConfig.resetFile(); await this.userConfig.writeValue('app_type', app_type); parentPort?.postMessage({ type: 'changeContent', page: this.databaseResetPage }); } } catch (err) { this.log(`Error during login request: ${err}`, 'error', 'sendLoginRequest'); } finally { this.sendLoginBusy = false; } }, interval); this.intervalIds.push(intervalId); } // Helper function to wait for a response from the TCP communicator private async waitForResponse(tcpCommunicator: TcpCommunicator): Promise { return new Promise((resolve) => { const checkInterval = setInterval(() => { if (tcpCommunicator.hasResponseArrived()) { clearInterval(checkInterval); resolve(tcpCommunicator.getLastResult()); } }, 100); }); } // Method to stop all intervals (for cleanup if needed) public stopAllIntervals(): void { for (const id of this.intervalIds) { clearInterval(id); } this.log("All intervals have been stopped.", 'log', 'stopAllIntervals'); } }