simplified gathering information from clients

This commit is contained in:
andrei-mihnea-cerbu
2025-02-04 20:43:05 +02:00
parent 885627213e
commit b0754d00c6
8 changed files with 43 additions and 137 deletions
+6 -7
View File
@@ -110,16 +110,15 @@ export class NetworkScanner {
const data = await this.db.read()
const serverIp = data.network.serverIp
const udpClient = new UdpClient(this.udpPort)
const activeIPs = await udpClient.getTargetClients(operationCodes.ARE_YOU_HUMAN)
const filteredIPs = activeIPs.filter((ip) => ip !== serverIp)
const activeClients = await udpClient.getTargetClients(operationCodes.ARE_YOU_HUMAN)
// Save the filtered IPs to 'users_ip'
await this.db.update((data) => {
data.network.usersInLan = filteredIPs.map((ip) => ({
id: '',
ip,
name: '',
departmentId: '',
data.network.usersInLan = activeClients.map((client) => ({
id: client.id,
ip: client.ip,
name: client.name,
departmentId: client.departmentId,
}))
return data
})
-92
View File
@@ -1,92 +0,0 @@
import { Database } from '../database/database'
import { NetworkUserScheme } from '../database/schemes/network_scheme'
import { TcpCommunicator } from './tcp_communicator'
import { operationCodes } from '../network/operation_codes'
import { ParsedMessage } from '../network/message_handler'
export class UsersInfoFetcher {
private db: Database
private tcpCommunicator: TcpCommunicator | null = null
private readonly clientPort: number
private intervalId: NodeJS.Timeout | null = null
constructor(pathToDatabaseFile: string, clientPort: number) {
this.db = new Database(pathToDatabaseFile)
this.clientPort = clientPort
this.tcpCommunicator = null
}
// Start fetching user info periodically
async start(): Promise<void> {
this.intervalId = setInterval(async () => {
const data = await this.db.read()
const usersIps = data.network.usersInLan.map((user: NetworkUserScheme) => user.ip)
for (const ip of usersIps) {
this.tcpCommunicator = new TcpCommunicator(ip, this.clientPort)
if (!(await this.tcpCommunicator.connect())) {
this.log(`Failed to open connection for IP: ${ip}`, 'error')
continue
}
if (!(await this.tcpCommunicator?.sendMessage(operationCodes.GET_USER_INFORMATION))) {
await this.tcpCommunicator.disconnect()
continue
}
// Wait for the response
const response = await this.waitForResponse()
if (response && response.metaInfo) {
await this.db.update((data) => {
const userIndex = data.network.usersInLan.findIndex((user) => user.ip === ip)
if (userIndex !== -1) {
// @ts-ignore
data.network.usersInLan[userIndex].id = response.metaInfo.id
// @ts-ignore
data.network.usersInLan[userIndex].name = response.metaInfo.name
// @ts-ignore
data.network.usersInLan[userIndex].departmentId = response.metaInfo.departmentId
} else {
this.log(`User with IP ${ip} not found in the database.`, 'error')
}
return data
})
}
await this.tcpCommunicator.disconnect()
}
if (global.gc) {
global.gc()
}
}, 5000) // 5-second interval for testing
}
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) // Check every 100ms
})
}
stop(): void {
if (this.intervalId) {
clearInterval(this.intervalId)
this.intervalId = null
this.log('Stopped successfully.')
}
}
private log(message: string, level: 'log' | 'error' = 'log'): void {
const prefix = '[UsersInfoFetcher]'
level === 'error' ? console.error(`${prefix} ${message}`) : console.log(`${prefix} ${message}`)
}
}
+5 -1
View File
@@ -2,7 +2,11 @@ import { Database } from '../database/database'
import { DatabaseScheme } from '../database/schemes/database_scheme'
import path from 'path'
import { EncryptionKeyScheme, UserInfoScheme } from '../database/schemes/app_config_scheme'
import {DirectoryInfo, DirectorySchemes, FileItemTask} from '../database/schemes/local_resources_scheme'
import {
DirectoryInfo,
DirectorySchemes,
FileItemTask,
} from '../database/schemes/local_resources_scheme'
const pathToDatabaseFile = path.join(__dirname, '..', 'database.json')
+5 -1
View File
@@ -4,7 +4,11 @@ import { EncryptionKeyScheme, UserInfoScheme } from '../database/schemes/app_con
import { ipcUCHandler } from '../ipc-handlers/uc_handler'
import { ParsedMessage } from '../network/message_handler'
import { NetworkUserScheme } from '../database/schemes/network_scheme'
import {DirectoryInfo, DirectorySchemes, FileItemTask} from '../database/schemes/local_resources_scheme'
import {
DirectoryInfo,
DirectorySchemes,
FileItemTask,
} from '../database/schemes/local_resources_scheme'
contextBridge.exposeInMainWorld('databaseAPI', {
getAppType: (): Promise<string> => ipcDatabaseHandler.getAppType(),
@@ -2,6 +2,10 @@ import { ParsedMessage } from '../message_handler'
import { OperationHandler } from '../operations_base/operation_handler'
import os from 'node:os'
import { OperationPlugin } from '../operations_base/operation_plugin'
import { Database } from '../../database/database'
import path from 'path'
const pathToDatabaseFile = path.join(__dirname, '..', '..', 'database.json')
export class GeneralOperations implements OperationPlugin {
public static readonly operationCodes = {
@@ -28,9 +32,23 @@ export class GeneralOperations implements OperationPlugin {
if (ipAddress !== 'Unknown') break
}
const database = new Database(pathToDatabaseFile)
const data = await database.read()
let response = {
ip: ipAddress,
name: '',
departmentId: '',
id: '',
}
if (data.app_config.logged_in) {
response.name = data.app_config.user_info.name
response.departmentId = data.app_config.user_info.departmentId
response.id = data.app_config.user_info.id
}
return {
operationCode: GeneralOperations.operationCodes.ALIVE,
metaInfo: { ipAddress },
metaInfo: response,
}
}
@@ -5,14 +5,13 @@ import path from 'path'
import fs from 'fs/promises'
import checkDiskSpace from 'check-disk-space'
import { OperationPlugin } from '../operations_base/operation_plugin'
import {Database} from "../../database/database";
import { Database } from '../../database/database'
const pathToDatabaseFile = path.join(__dirname, '..', '..', 'database.json')
const pathToDatabaseFile = path.join(__dirname, '..', '..', 'database.json')
export class UserToUserOperations implements OperationPlugin {
public static readonly operationCodes = {
SEND_ANNOUNCEMENT: 'SEND_ANNOUNCEMENT',
GET_USER_INFORMATION: 'GET_USER_INFORMATION',
BACKUP_FILE: 'BACKUP_FILE',
CLEAR_BACKUP: 'CLEAR_BACKUP',
SHARE_FILE: 'SHARE_FILE',
@@ -51,7 +50,7 @@ export class UserToUserOperations implements OperationPlugin {
const database = new Database(pathToDatabaseFile)
try {
await database.update((data: any) => {
if(!parsedMessage.metaInfo) return data;
if (!parsedMessage.metaInfo) return data
data.app_config.announcement = parsedMessage.metaInfo.message
return data
@@ -63,23 +62,6 @@ export class UserToUserOperations implements OperationPlugin {
}
}
public static async handleGetUserInformation(
parsedMessage: ParsedMessage,
): Promise<ParsedMessage> {
const database = new Database(pathToDatabaseFile)
try {
const data = await database.read()
const userInfo = data.app_config.user_info
return { operationCode: operationCodes.OK, metaInfo: userInfo }
} catch (error: any) {
console.error(`Error fetching user info: ${error.message}`)
return {
operationCode: operationCodes.ERR,
metaInfo: { message: 'Error fetching user info' },
}
}
}
public static async handleBackupFile(parsedMessage: ParsedMessage): Promise<ParsedMessage> {
if (
!parsedMessage.metaInfo?.userName ||
@@ -388,10 +370,6 @@ export class UserToUserOperations implements OperationPlugin {
UserToUserOperations.operationCodes.SEND_ANNOUNCEMENT,
UserToUserOperations.handleSendAnnouncement,
)
operationHandler.registerHandler(
UserToUserOperations.operationCodes.GET_USER_INFORMATION,
UserToUserOperations.handleGetUserInformation,
)
operationHandler.registerHandler(
UserToUserOperations.operationCodes.BACKUP_FILE,
UserToUserOperations.handleBackupFile,
+5 -5
View File
@@ -29,7 +29,7 @@ export class UdpClient {
}
// Send heartbeat and get clients that respond with ALIVE, excluding the host machine's IP addresses
async getTargetClients(heartbeatCode: string): Promise<string[]> {
async getTargetClients(heartbeatCode: string): Promise<any[]> {
const subnet = this.getSubnet()
const ipRange = this.getIPRange(subnet)
@@ -42,12 +42,12 @@ export class UdpClient {
this.log(`Active IPs in subnet ${subnet}: ${activeIps.join(', ')}`)
// Send heartbeat to each active IP and keep only those that respond with ALIVE
const aliveClients: string[] = []
const aliveClients: any[] = []
for (const ip of activeIps) {
if (!localIPs.includes(ip)) {
const result = await this.sendHeartbeat(ip, heartbeatCode)
if (result.found) {
aliveClients.push(ip)
aliveClients.push(result.data ? result.data : ip)
}
}
}
@@ -73,7 +73,7 @@ export class UdpClient {
}
// Send heartbeat to an IP
private async sendHeartbeat(ip: string, heartbeatCode: string): Promise<{ found: boolean }> {
private async sendHeartbeat(ip: string, heartbeatCode: string): Promise<{ found: boolean, data?: any }> {
return new Promise((resolve) => {
const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode)
@@ -94,7 +94,7 @@ export class UdpClient {
const parsedMessage = MessageHandler.parseMessage(msg.toString())
if (parsedMessage?.operationCode === operationCodes.ALIVE) {
this.log(`Received ALIVE response from ${ip}`)
resolve({ found: true })
resolve({ found: true, data: parsedMessage.metaInfo })
} else {
this.log(`Unexpected response from ${ip}`)
resolve({ found: false })
@@ -1,4 +1,3 @@
import { UsersInfoFetcher } from '../helpers/users_info_fetcher'
import { BackupManager } from '../helpers/backup_manager'
import { FileSharer } from '../helpers/file_sharer'
import { DepartmentSharer } from '../helpers/department_sharer'
@@ -7,9 +6,6 @@ import { DepartmentSharer } from '../helpers/department_sharer'
const pathToDatabaseFile = process.env.DATABASE_FILE_PATH || ''
const tcpPort = parseInt(process.env.TCP_PORT || '0', 10)
const usersInfoFetcher = new UsersInfoFetcher(pathToDatabaseFile, tcpPort)
usersInfoFetcher.start()
const backupManager = new BackupManager(pathToDatabaseFile, tcpPort)
backupManager.start()
@@ -30,7 +26,6 @@ process.on('SIGINT', async () => {
})
async function cleanupAndExit() {
usersInfoFetcher.stop()
await backupManager.stop()
await fileSharer.stop()
await departmentSharer.stop()