simplified gathering information from clients
This commit is contained in:
@@ -110,16 +110,15 @@ export class NetworkScanner {
|
|||||||
const data = await this.db.read()
|
const data = await this.db.read()
|
||||||
const serverIp = data.network.serverIp
|
const serverIp = data.network.serverIp
|
||||||
const udpClient = new UdpClient(this.udpPort)
|
const udpClient = new UdpClient(this.udpPort)
|
||||||
const activeIPs = await udpClient.getTargetClients(operationCodes.ARE_YOU_HUMAN)
|
const activeClients = await udpClient.getTargetClients(operationCodes.ARE_YOU_HUMAN)
|
||||||
const filteredIPs = activeIPs.filter((ip) => ip !== serverIp)
|
|
||||||
|
|
||||||
// Save the filtered IPs to 'users_ip'
|
// Save the filtered IPs to 'users_ip'
|
||||||
await this.db.update((data) => {
|
await this.db.update((data) => {
|
||||||
data.network.usersInLan = filteredIPs.map((ip) => ({
|
data.network.usersInLan = activeClients.map((client) => ({
|
||||||
id: '',
|
id: client.id,
|
||||||
ip,
|
ip: client.ip,
|
||||||
name: '',
|
name: client.name,
|
||||||
departmentId: '',
|
departmentId: client.departmentId,
|
||||||
}))
|
}))
|
||||||
return data
|
return data
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,11 @@ import { Database } from '../database/database'
|
|||||||
import { DatabaseScheme } from '../database/schemes/database_scheme'
|
import { DatabaseScheme } from '../database/schemes/database_scheme'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { EncryptionKeyScheme, UserInfoScheme } from '../database/schemes/app_config_scheme'
|
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')
|
const pathToDatabaseFile = path.join(__dirname, '..', 'database.json')
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,11 @@ import { EncryptionKeyScheme, UserInfoScheme } from '../database/schemes/app_con
|
|||||||
import { ipcUCHandler } from '../ipc-handlers/uc_handler'
|
import { ipcUCHandler } from '../ipc-handlers/uc_handler'
|
||||||
import { ParsedMessage } from '../network/message_handler'
|
import { ParsedMessage } from '../network/message_handler'
|
||||||
import { NetworkUserScheme } from '../database/schemes/network_scheme'
|
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', {
|
contextBridge.exposeInMainWorld('databaseAPI', {
|
||||||
getAppType: (): Promise<string> => ipcDatabaseHandler.getAppType(),
|
getAppType: (): Promise<string> => ipcDatabaseHandler.getAppType(),
|
||||||
|
|||||||
@@ -2,6 +2,10 @@ import { ParsedMessage } from '../message_handler'
|
|||||||
import { OperationHandler } from '../operations_base/operation_handler'
|
import { OperationHandler } from '../operations_base/operation_handler'
|
||||||
import os from 'node:os'
|
import os from 'node:os'
|
||||||
import { OperationPlugin } from '../operations_base/operation_plugin'
|
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 {
|
export class GeneralOperations implements OperationPlugin {
|
||||||
public static readonly operationCodes = {
|
public static readonly operationCodes = {
|
||||||
@@ -28,9 +32,23 @@ export class GeneralOperations implements OperationPlugin {
|
|||||||
if (ipAddress !== 'Unknown') break
|
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 {
|
return {
|
||||||
operationCode: GeneralOperations.operationCodes.ALIVE,
|
operationCode: GeneralOperations.operationCodes.ALIVE,
|
||||||
metaInfo: { ipAddress },
|
metaInfo: response,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,13 @@ import path from 'path'
|
|||||||
import fs from 'fs/promises'
|
import fs from 'fs/promises'
|
||||||
import checkDiskSpace from 'check-disk-space'
|
import checkDiskSpace from 'check-disk-space'
|
||||||
import { OperationPlugin } from '../operations_base/operation_plugin'
|
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 {
|
export class UserToUserOperations implements OperationPlugin {
|
||||||
public static readonly operationCodes = {
|
public static readonly operationCodes = {
|
||||||
SEND_ANNOUNCEMENT: 'SEND_ANNOUNCEMENT',
|
SEND_ANNOUNCEMENT: 'SEND_ANNOUNCEMENT',
|
||||||
GET_USER_INFORMATION: 'GET_USER_INFORMATION',
|
|
||||||
BACKUP_FILE: 'BACKUP_FILE',
|
BACKUP_FILE: 'BACKUP_FILE',
|
||||||
CLEAR_BACKUP: 'CLEAR_BACKUP',
|
CLEAR_BACKUP: 'CLEAR_BACKUP',
|
||||||
SHARE_FILE: 'SHARE_FILE',
|
SHARE_FILE: 'SHARE_FILE',
|
||||||
@@ -51,7 +50,7 @@ export class UserToUserOperations implements OperationPlugin {
|
|||||||
const database = new Database(pathToDatabaseFile)
|
const database = new Database(pathToDatabaseFile)
|
||||||
try {
|
try {
|
||||||
await database.update((data: any) => {
|
await database.update((data: any) => {
|
||||||
if(!parsedMessage.metaInfo) return data;
|
if (!parsedMessage.metaInfo) return data
|
||||||
|
|
||||||
data.app_config.announcement = parsedMessage.metaInfo.message
|
data.app_config.announcement = parsedMessage.metaInfo.message
|
||||||
return data
|
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> {
|
public static async handleBackupFile(parsedMessage: ParsedMessage): Promise<ParsedMessage> {
|
||||||
if (
|
if (
|
||||||
!parsedMessage.metaInfo?.userName ||
|
!parsedMessage.metaInfo?.userName ||
|
||||||
@@ -388,10 +370,6 @@ export class UserToUserOperations implements OperationPlugin {
|
|||||||
UserToUserOperations.operationCodes.SEND_ANNOUNCEMENT,
|
UserToUserOperations.operationCodes.SEND_ANNOUNCEMENT,
|
||||||
UserToUserOperations.handleSendAnnouncement,
|
UserToUserOperations.handleSendAnnouncement,
|
||||||
)
|
)
|
||||||
operationHandler.registerHandler(
|
|
||||||
UserToUserOperations.operationCodes.GET_USER_INFORMATION,
|
|
||||||
UserToUserOperations.handleGetUserInformation,
|
|
||||||
)
|
|
||||||
operationHandler.registerHandler(
|
operationHandler.registerHandler(
|
||||||
UserToUserOperations.operationCodes.BACKUP_FILE,
|
UserToUserOperations.operationCodes.BACKUP_FILE,
|
||||||
UserToUserOperations.handleBackupFile,
|
UserToUserOperations.handleBackupFile,
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export class UdpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send heartbeat and get clients that respond with ALIVE, excluding the host machine's IP addresses
|
// 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 subnet = this.getSubnet()
|
||||||
const ipRange = this.getIPRange(subnet)
|
const ipRange = this.getIPRange(subnet)
|
||||||
|
|
||||||
@@ -42,12 +42,12 @@ export class UdpClient {
|
|||||||
this.log(`Active IPs in subnet ${subnet}: ${activeIps.join(', ')}`)
|
this.log(`Active IPs in subnet ${subnet}: ${activeIps.join(', ')}`)
|
||||||
|
|
||||||
// Send heartbeat to each active IP and keep only those that respond with ALIVE
|
// 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) {
|
for (const ip of activeIps) {
|
||||||
if (!localIPs.includes(ip)) {
|
if (!localIPs.includes(ip)) {
|
||||||
const result = await this.sendHeartbeat(ip, heartbeatCode)
|
const result = await this.sendHeartbeat(ip, heartbeatCode)
|
||||||
if (result.found) {
|
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
|
// 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) => {
|
return new Promise((resolve) => {
|
||||||
const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode)
|
const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode)
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ export class UdpClient {
|
|||||||
const parsedMessage = MessageHandler.parseMessage(msg.toString())
|
const parsedMessage = MessageHandler.parseMessage(msg.toString())
|
||||||
if (parsedMessage?.operationCode === operationCodes.ALIVE) {
|
if (parsedMessage?.operationCode === operationCodes.ALIVE) {
|
||||||
this.log(`Received ALIVE response from ${ip}`)
|
this.log(`Received ALIVE response from ${ip}`)
|
||||||
resolve({ found: true })
|
resolve({ found: true, data: parsedMessage.metaInfo })
|
||||||
} else {
|
} else {
|
||||||
this.log(`Unexpected response from ${ip}`)
|
this.log(`Unexpected response from ${ip}`)
|
||||||
resolve({ found: false })
|
resolve({ found: false })
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { UsersInfoFetcher } from '../helpers/users_info_fetcher'
|
|
||||||
import { BackupManager } from '../helpers/backup_manager'
|
import { BackupManager } from '../helpers/backup_manager'
|
||||||
import { FileSharer } from '../helpers/file_sharer'
|
import { FileSharer } from '../helpers/file_sharer'
|
||||||
import { DepartmentSharer } from '../helpers/department_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 pathToDatabaseFile = process.env.DATABASE_FILE_PATH || ''
|
||||||
const tcpPort = parseInt(process.env.TCP_PORT || '0', 10)
|
const tcpPort = parseInt(process.env.TCP_PORT || '0', 10)
|
||||||
|
|
||||||
const usersInfoFetcher = new UsersInfoFetcher(pathToDatabaseFile, tcpPort)
|
|
||||||
usersInfoFetcher.start()
|
|
||||||
|
|
||||||
const backupManager = new BackupManager(pathToDatabaseFile, tcpPort)
|
const backupManager = new BackupManager(pathToDatabaseFile, tcpPort)
|
||||||
backupManager.start()
|
backupManager.start()
|
||||||
|
|
||||||
@@ -30,7 +26,6 @@ process.on('SIGINT', async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
async function cleanupAndExit() {
|
async function cleanupAndExit() {
|
||||||
usersInfoFetcher.stop()
|
|
||||||
await backupManager.stop()
|
await backupManager.stop()
|
||||||
await fileSharer.stop()
|
await fileSharer.stop()
|
||||||
await departmentSharer.stop()
|
await departmentSharer.stop()
|
||||||
|
|||||||
Reference in New Issue
Block a user