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
+3 -1
View File
@@ -65,7 +65,7 @@ async function restoreBackup() {
} }
// Call the IPC method to initiate the backup retrieval process // Call the IPC method to initiate the backup retrieval process
window.electronAPI.startBackupRetrieval(destinationPath); window.uiAPI.startBackupRetrieval(destinationPath);
// Switch the content to the 'backup_retrieve' page // Switch the content to the 'backup_retrieve' page
fadeOut('backup_retrieve'); fadeOut('backup_retrieve');
@@ -133,6 +133,8 @@ async function loadReceivedFiles() {
// Read the shareDirectory from applicationInfo // Read the shareDirectory from applicationInfo
const shareDirData = await window.databaseAPI.getDirectoryInfo(shareDirId); const shareDirData = await window.databaseAPI.getDirectoryInfo(shareDirId);
console.log('Loading received files:', shareDirData);
const notificationsDiv = document.getElementById('notifications'); const notificationsDiv = document.getElementById('notifications');
const existingButtons = Array.from(notificationsDiv.children).map(button => button.getAttribute('data-filepath')); const existingButtons = Array.from(notificationsDiv.children).map(button => button.getAttribute('data-filepath'));
+2 -1
View File
@@ -33,9 +33,10 @@ export class BackupRetrievalWorker {
} }
async start(): Promise<void> { async start(): Promise<void> {
if (!this.stopRequested) return if (this.stopRequested) return
this.isBusy = true this.isBusy = true
try { try {
this.log('Start successfully. Retrieving backup.')
const data = await this.db.read() const data = await this.db.read()
const userInfo = data.app_config.user_info const userInfo = data.app_config.user_info
const encryptionKey = data.app_config.encryption_key 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 { operationCodes } from '../network/operation_codes'
import { ParsedMessage } from '../network/message_handler' import { ParsedMessage } from '../network/message_handler'
import { Database } from '../database/database' import { Database } from '../database/database'
import {NetworkUserScheme} from "../database/schemes/network_scheme";
export class DepartmentSharer { export class DepartmentSharer {
private readonly db: Database private readonly db: Database
@@ -46,9 +47,13 @@ export class DepartmentSharer {
const activeUsers = data.network.usersInLan const activeUsers = data.network.usersInLan
this.departmentDirectory = departmentStructure.path this.departmentDirectory = departmentStructure.path
if(departmentStructure.path === ''){
throw new Error('Department directory not set.')
}
// Filter users who belong to the same department // Filter users who belong to the same department
const departmentUsers = activeUsers.filter( const departmentUsers = activeUsers.filter(
(user: any) => user.user_info.departmentId === departmentId, (user: NetworkUserScheme) => user.departmentId === departmentId,
) )
if (departmentUsers.length === 0) { if (departmentUsers.length === 0) {
throw new Error('No users found in the same department.') throw new Error('No users found in the same department.')
@@ -101,8 +106,6 @@ export class DepartmentSharer {
if (!this.tcpCommunicator) return if (!this.tcpCommunicator) return
const unsentFiles = Object.keys(files) const unsentFiles = Object.keys(files)
console.log(`\n\n${unsentFiles}\n\n`)
for (const fileName of unsentFiles) { for (const fileName of unsentFiles) {
const filePath = files[fileName] const filePath = files[fileName]
@@ -135,8 +138,6 @@ export class DepartmentSharer {
) )
return return
console.log(`\n\nSending file: ${fileName} to ${userName}\n\n`)
const response = await this.waitForResponse() const response = await this.waitForResponse()
if (!response || response.operationCode !== operationCodes.OK) { if (!response || response.operationCode !== operationCodes.OK) {
this.log(`Failed to send file: ${fileName}`, 'error') this.log(`Failed to send file: ${fileName}`, 'error')
@@ -162,8 +163,6 @@ export class DepartmentSharer {
while (this.isBusy) { while (this.isBusy) {
await new Promise((resolve) => setTimeout(resolve, 100)) await new Promise((resolve) => setTimeout(resolve, 100))
} }
console.log('[BackupManager] Stopped successfully.')
} }
private async waitForResponse(): Promise<ParsedMessage | null> { 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 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') this.log('UC Check running...', 'log', 'startUCCheck')
const udpClient = new UdpClient(this.udpPort) const udpClient = new UdpClient(this.udpPort)
const aliveClients = await udpClient.getTargetClients(operationCodes.ARE_YOU_UC) const aliveClients = await udpClient.getTargetClients(operationCodes.ARE_YOU_UC)
console.log(aliveClients)
const data = await this.db.read() const data = await this.db.read()
const foundClient = aliveClients.length > 0 const foundClient = aliveClients.length > 0
const serverFound = data.app_config.server_found const serverFound = data.app_config.server_found
@@ -108,7 +107,6 @@ export class NetworkScanner {
try { try {
this.log('IP Lookup running...', 'log', 'startUserIPLookup') this.log('IP Lookup running...', 'log', 'startUserIPLookup')
const data = await this.db.read()
const udpClient = new UdpClient(this.udpPort) const udpClient = new UdpClient(this.udpPort)
const activeClients = await udpClient.getTargetClients(operationCodes.ARE_YOU_HUMAN) const activeClients = await udpClient.getTargetClients(operationCodes.ARE_YOU_HUMAN)
-4
View File
@@ -51,10 +51,6 @@ contextBridge.exposeInMainWorld('uiAPI', {
ipcRenderer.invoke('show-file-in-explorer', path), ipcRenderer.invoke('show-file-in-explorer', path),
readAnnouncement: (): Promise<string> => ipcRenderer.invoke('read-announcement'), readAnnouncement: (): Promise<string> => ipcRenderer.invoke('read-announcement'),
closeAnnouncementWindow: (): Promise<void> => ipcRenderer.invoke('close-announcement-window'), closeAnnouncementWindow: (): Promise<void> => ipcRenderer.invoke('close-announcement-window'),
})
contextBridge.exposeInMainWorld('electronAPI', {
// Workers
startBackupRetrieval: (destinationPath: string): Promise<void> => 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) const fullFilePath = path.join(shareDirectory, userName, relativeFilePath)
await fs.mkdir(path.dirname(fullFilePath), { recursive: true }) await fs.mkdir(path.dirname(fullFilePath), { recursive: true })
await fs.writeFile(fullFilePath, parsedMessage.fileContent as Buffer) await fs.writeFile(fullFilePath, parsedMessage.fileContent as Buffer)
await database.pushToReceiveQueue({
ip: '',
path: fullFilePath,
userName,
})
console.log(`File shared: ${fullFilePath}`)
return { return {
operationCode: operationCodes.OK, operationCode: operationCodes.OK,
+1 -13
View File
@@ -35,11 +35,9 @@ export class UdpClient {
// Get local machine's IP addresses to exclude // Get local machine's IP addresses to exclude
const localIPs = this.getLocalIPs() const localIPs = this.getLocalIPs()
this.log(`Local IPs to exclude from scan: ${localIPs.join(', ')}`)
// First, filter active IPs that respond to ping // First, filter active IPs that respond to ping
const activeIps = await this.filterActiveIps(ipRange) 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 // Send heartbeat to each active IP and keep only those that respond with ALIVE
const aliveClients: any[] = [] const aliveClients: any[] = []
@@ -80,10 +78,8 @@ export class UdpClient {
return new Promise((resolve) => { return new Promise((resolve) => {
const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode) const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode)
this.log(`Sending heartbeat to ${ip}`)
this.udpSocket.send(heartbeatMessage, this.port, ip, (err) => { this.udpSocket.send(heartbeatMessage, this.port, ip, (err) => {
if (err) { if (err) {
this.log(`Failed to send heartbeat to ${ip}: ${err.message}`, 'error')
resolve({ found: false }) resolve({ found: false })
} else { } else {
const timeout = setTimeout(() => { const timeout = setTimeout(() => {
@@ -96,10 +92,8 @@ export class UdpClient {
clearTimeout(timeout) clearTimeout(timeout)
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}`)
resolve({ found: true, data: parsedMessage.metaInfo }) resolve({ found: true, data: parsedMessage.metaInfo })
} else { } else {
this.log(`Unexpected response from ${ip}`)
resolve({ found: false }) resolve({ found: false })
} }
} }
@@ -113,9 +107,7 @@ export class UdpClient {
private dropConnection(ip: string): void { private dropConnection(ip: string): void {
try { try {
this.udpSocket.removeAllListeners('message') this.udpSocket.removeAllListeners('message')
this.log(`Dropped connection listeners for ${ip}`)
} catch (err: any) { } 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 iface of Object.values(interfaces)) {
for (const address of iface || []) { for (const address of iface || []) {
if (address.family === 'IPv4' && !address.internal) { if (address.family === 'IPv4' && !address.internal) {
const subnet = address.address.split('.').slice(0, 3).join('.') return address.address.split('.').slice(0, 3).join('.')
this.log(`Detected subnet: ${subnet}`)
return subnet
} }
} }
} }
@@ -140,7 +130,6 @@ export class UdpClient {
for (let i = 1; i < 255; i++) { for (let i = 1; i < 255; i++) {
ipRange.push(`${subnet}.${i}`) ipRange.push(`${subnet}.${i}`)
} }
this.log(`Generated IP range for subnet ${subnet}`)
return ipRange return ipRange
} }
@@ -158,7 +147,6 @@ export class UdpClient {
} }
} }
this.log(`Active IPs after pinging: ${activeIps.join(', ')}`)
return activeIps return activeIps
} }
} }