backup added

This commit is contained in:
andrei-mihnea-cerbu
2025-02-04 22:33:28 +02:00
parent 5a6fa296be
commit 52d5f16300
9 changed files with 18 additions and 158 deletions
+2 -1
View File
@@ -33,9 +33,10 @@ export class BackupRetrievalWorker {
}
async start(): Promise<void> {
if (!this.stopRequested) return
if (this.stopRequested) return
this.isBusy = true
try {
this.log('Start successfully. Retrieving backup.')
const data = await this.db.read()
const userInfo = data.app_config.user_info
const encryptionKey = data.app_config.encryption_key
+6 -7
View File
@@ -4,6 +4,7 @@ import { TcpCommunicator } from './tcp_communicator'
import { operationCodes } from '../network/operation_codes'
import { ParsedMessage } from '../network/message_handler'
import { Database } from '../database/database'
import {NetworkUserScheme} from "../database/schemes/network_scheme";
export class DepartmentSharer {
private readonly db: Database
@@ -46,9 +47,13 @@ export class DepartmentSharer {
const activeUsers = data.network.usersInLan
this.departmentDirectory = departmentStructure.path
if(departmentStructure.path === ''){
throw new Error('Department directory not set.')
}
// Filter users who belong to the same department
const departmentUsers = activeUsers.filter(
(user: any) => user.user_info.departmentId === departmentId,
(user: NetworkUserScheme) => user.departmentId === departmentId,
)
if (departmentUsers.length === 0) {
throw new Error('No users found in the same department.')
@@ -101,8 +106,6 @@ export class DepartmentSharer {
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]
@@ -135,8 +138,6 @@ export class DepartmentSharer {
)
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')
@@ -162,8 +163,6 @@ export class DepartmentSharer {
while (this.isBusy) {
await new Promise((resolve) => setTimeout(resolve, 100))
}
console.log('[BackupManager] Stopped successfully.')
}
private async waitForResponse(): Promise<ParsedMessage | null> {
+1
View File
@@ -60,6 +60,7 @@ export class FileSharer {
}
}
}
this.log('Queue processed successfully.')
this.isBusy = false // Reset busy flag after the queue is processed
}
-119
View File
@@ -1,119 +0,0 @@
import fs from 'fs'
import path from 'path'
export class JsonManager {
private readonly filePath: string
private readonly lockFilePath: string
constructor(filePath: string) {
const dir = path.dirname(filePath)
// Check if the directory exists, throw error if it doesn't
if (!fs.existsSync(dir)) {
throw new Error(`The directory does not exist: ${dir}`)
}
this.filePath = filePath
this.lockFilePath = `${filePath}.lock` // Define the lock file path
// If the file doesn't exist, create it
if (!fs.existsSync(filePath)) {
fs.writeFileSync(filePath, JSON.stringify({}, null, 2), 'utf8')
}
}
// Method to acquire a lock (create .lock file)
private async acquireLock(): Promise<void> {
while (fs.existsSync(this.lockFilePath)) {
// Wait until the lock file is released
await new Promise((resolve) => setTimeout(resolve, 100)) // 100ms delay before retrying
}
// Create the lock file
fs.writeFileSync(this.lockFilePath, '')
}
// Method to release the lock (delete .lock file)
private releaseLock(): void {
if (fs.existsSync(this.lockFilePath)) {
fs.unlinkSync(this.lockFilePath)
}
}
// Read a value by key from the JSON file with a lock
public async readValue(key: string): Promise<any | null> {
await this.acquireLock() // Acquire the lock
try {
if (!fs.existsSync(this.filePath)) return null
const data = JSON.parse(fs.readFileSync(this.filePath, 'utf8'))
return data[key] !== undefined ? data[key] : null
} catch (err: any) {
console.error(`Error reading from JSON file: ${err.message}`)
return null
} finally {
this.releaseLock() // Always release the lock after the operation
}
}
// Write a key-value pair to the JSON file with a lock
public async writeValue(key: string, value: any): Promise<boolean> {
await this.acquireLock() // Acquire the lock
try {
let data: { [key: string]: any } = {}
if (fs.existsSync(this.filePath)) {
data = JSON.parse(fs.readFileSync(this.filePath, 'utf8'))
}
// Update the key with the new value
data[key] = value
fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf8')
return true
} catch (err: any) {
console.error(`Error writing to JSON file: ${err.message}`)
return false
} finally {
this.releaseLock() // Always release the lock after the operation
}
}
// Remove a key-value pair from the JSON file with a lock
public async removeValue(key: string): Promise<boolean> {
await this.acquireLock() // Acquire the lock
try {
if (!fs.existsSync(this.filePath)) return false
const data = JSON.parse(fs.readFileSync(this.filePath, 'utf8'))
if (data[key] !== undefined) {
delete data[key]
fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf8')
return true
}
return false
} catch (err: any) {
console.error(`Error removing key from JSON file: ${err.message}`)
return false
} finally {
this.releaseLock() // Always release the lock after the operation
}
}
// Reset the JSON file by clearing all data with a lock
public async resetFile(): Promise<boolean> {
await this.acquireLock() // Acquire the lock
try {
fs.writeFileSync(this.filePath, JSON.stringify({}, null, 2), 'utf8')
return true
} catch (err: any) {
console.error(`Error resetting JSON file: ${err.message}`)
return false
} finally {
this.releaseLock() // Always release the lock after the operation
}
}
}
-2
View File
@@ -59,7 +59,6 @@ export class NetworkScanner {
this.log('UC Check running...', 'log', 'startUCCheck')
const udpClient = new UdpClient(this.udpPort)
const aliveClients = await udpClient.getTargetClients(operationCodes.ARE_YOU_UC)
console.log(aliveClients)
const data = await this.db.read()
const foundClient = aliveClients.length > 0
const serverFound = data.app_config.server_found
@@ -108,7 +107,6 @@ export class NetworkScanner {
try {
this.log('IP Lookup running...', 'log', 'startUserIPLookup')
const data = await this.db.read()
const udpClient = new UdpClient(this.udpPort)
const activeClients = await udpClient.getTargetClients(operationCodes.ARE_YOU_HUMAN)
+1 -5
View File
@@ -51,10 +51,6 @@ contextBridge.exposeInMainWorld('uiAPI', {
ipcRenderer.invoke('show-file-in-explorer', path),
readAnnouncement: (): Promise<string> => ipcRenderer.invoke('read-announcement'),
closeAnnouncementWindow: (): Promise<void> => ipcRenderer.invoke('close-announcement-window'),
})
contextBridge.exposeInMainWorld('electronAPI', {
// Workers
startBackupRetrieval: (destinationPath: string): Promise<void> =>
ipcRenderer.invoke('start-backup-retrieval', destinationPath),
ipcRenderer.invoke('start-backup-retrieval', destinationPath),
})
@@ -158,12 +158,6 @@ export class UserToUserOperations implements OperationPlugin {
const fullFilePath = path.join(shareDirectory, userName, relativeFilePath)
await fs.mkdir(path.dirname(fullFilePath), { recursive: true })
await fs.writeFile(fullFilePath, parsedMessage.fileContent as Buffer)
await database.pushToReceiveQueue({
ip: '',
path: fullFilePath,
userName,
})
console.log(`File shared: ${fullFilePath}`)
return {
operationCode: operationCodes.OK,
+5 -17
View File
@@ -1,9 +1,9 @@
import dgram from 'dgram'
import ping from 'ping'
import { OperationHandler } from '../operations_base/operation_handler'
import { MessageHandler } from '../message_handler'
import { GeneralOperations } from '../operations_custom/general_operations'
import { operationCodes } from '../operation_codes'
import {OperationHandler} from '../operations_base/operation_handler'
import {MessageHandler} from '../message_handler'
import {GeneralOperations} from '../operations_custom/general_operations'
import {operationCodes} from '../operation_codes'
import os from 'os'
export class UdpClient {
@@ -35,11 +35,9 @@ export class UdpClient {
// Get local machine's IP addresses to exclude
const localIPs = this.getLocalIPs()
this.log(`Local IPs to exclude from scan: ${localIPs.join(', ')}`)
// First, filter active IPs that respond to ping
const activeIps = await this.filterActiveIps(ipRange)
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: any[] = []
@@ -80,10 +78,8 @@ export class UdpClient {
return new Promise((resolve) => {
const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode)
this.log(`Sending heartbeat to ${ip}`)
this.udpSocket.send(heartbeatMessage, this.port, ip, (err) => {
if (err) {
this.log(`Failed to send heartbeat to ${ip}: ${err.message}`, 'error')
resolve({ found: false })
} else {
const timeout = setTimeout(() => {
@@ -96,10 +92,8 @@ export class UdpClient {
clearTimeout(timeout)
const parsedMessage = MessageHandler.parseMessage(msg.toString())
if (parsedMessage?.operationCode === operationCodes.ALIVE) {
this.log(`Received ALIVE response from ${ip}`)
resolve({ found: true, data: parsedMessage.metaInfo })
} else {
this.log(`Unexpected response from ${ip}`)
resolve({ found: false })
}
}
@@ -113,9 +107,7 @@ export class UdpClient {
private dropConnection(ip: string): void {
try {
this.udpSocket.removeAllListeners('message')
this.log(`Dropped connection listeners for ${ip}`)
} catch (err: any) {
this.log(`Error dropping connection to ${ip}: ${err.message}`, 'error')
}
}
@@ -125,9 +117,7 @@ export class UdpClient {
for (const iface of Object.values(interfaces)) {
for (const address of iface || []) {
if (address.family === 'IPv4' && !address.internal) {
const subnet = address.address.split('.').slice(0, 3).join('.')
this.log(`Detected subnet: ${subnet}`)
return subnet
return address.address.split('.').slice(0, 3).join('.')
}
}
}
@@ -140,7 +130,6 @@ export class UdpClient {
for (let i = 1; i < 255; i++) {
ipRange.push(`${subnet}.${i}`)
}
this.log(`Generated IP range for subnet ${subnet}`)
return ipRange
}
@@ -158,7 +147,6 @@ export class UdpClient {
}
}
this.log(`Active IPs after pinging: ${activeIps.join(', ')}`)
return activeIps
}
}