updated backup manager to also clean
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
export interface NetworkUserScheme {
|
export interface NetworkUserScheme {
|
||||||
id: string
|
|
||||||
ip: string
|
ip: string
|
||||||
name: string
|
name: string
|
||||||
departmentId: string
|
departmentId: string
|
||||||
|
|||||||
@@ -6,18 +6,25 @@ 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'
|
import { NetworkUserScheme } from '../database/schemes/network_scheme'
|
||||||
|
import { UserInfoScheme } from '../database/schemes/app_config_scheme'
|
||||||
|
|
||||||
|
const backupDirectoryPath = path.join(__dirname, '..', 'backup')
|
||||||
|
|
||||||
export class BackupManager {
|
export class BackupManager {
|
||||||
private fileEncryptor: FileEncryptor | null = null
|
private fileEncryptor: FileEncryptor | null = null
|
||||||
private readonly db: Database
|
private readonly db: Database
|
||||||
private readonly clientPort: number
|
private readonly port: number
|
||||||
|
private serverIp: string = '';
|
||||||
private isBusy: boolean = false
|
private isBusy: boolean = false
|
||||||
private intervalId: NodeJS.Timeout | null = null
|
private intervalId: NodeJS.Timeout | null = null
|
||||||
private stopRequested: boolean = false
|
private stopRequested: boolean = false
|
||||||
|
|
||||||
constructor(pathToDatabaseFile: string, clientPort: number) {
|
constructor(pathToDatabaseFile: string, port: number) {
|
||||||
this.db = new Database(pathToDatabaseFile)
|
this.db = new Database(pathToDatabaseFile)
|
||||||
this.clientPort = clientPort
|
this.port = port
|
||||||
|
this.db.read().then((data) => {
|
||||||
|
this.serverIp = data.network.serverIp
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
@@ -46,11 +53,13 @@ export class BackupManager {
|
|||||||
this.fileEncryptor = new FileEncryptor(encryptionKey.key, encryptionKey.iv)
|
this.fileEncryptor = new FileEncryptor(encryptionKey.key, encryptionKey.iv)
|
||||||
|
|
||||||
await this.sendFilesToUsers(
|
await this.sendFilesToUsers(
|
||||||
userInfo.name,
|
userInfo,
|
||||||
usersIp,
|
usersIp,
|
||||||
backupDirectoryData.structure,
|
backupDirectoryData.structure,
|
||||||
backupDirectoryData.path,
|
backupDirectoryData.path,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
await this.validateBackupDirectories(backupDirectoryPath);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
this.log(`Error in initialize process: ${error.message}`, 'error')
|
this.log(`Error in initialize process: ${error.message}`, 'error')
|
||||||
} finally {
|
} finally {
|
||||||
@@ -72,15 +81,84 @@ export class BackupManager {
|
|||||||
return this.fileEncryptor.encryptFileToBase64(filePath)
|
return this.fileEncryptor.encryptFileToBase64(filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async fetchUsersFromServer(): Promise<Set<string>> {
|
||||||
|
const tcpCommunicator = new TcpCommunicator(this.serverIp, this.port)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await tcpCommunicator.connect()
|
||||||
|
this.log(`Connected to server at ${this.serverIp}`)
|
||||||
|
|
||||||
|
await tcpCommunicator.sendMessage(operationCodes.GET_USERS, {})
|
||||||
|
|
||||||
|
const response = await this.waitForResponse(tcpCommunicator)
|
||||||
|
if (!response || !response.metaInfo || !response.metaInfo.users) {
|
||||||
|
throw new Error('Invalid or missing user data from server.')
|
||||||
|
}
|
||||||
|
|
||||||
|
const validUserDirectories = new Set<string>()
|
||||||
|
for (const user of response.metaInfo.users) {
|
||||||
|
const { name, departmentId } = user
|
||||||
|
validUserDirectories.add(`${name}-${departmentId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return validUserDirectories
|
||||||
|
} catch (error) {
|
||||||
|
this.log(`Failed to fetch user list from server. Error: ${error}`, 'error')
|
||||||
|
return new Set<string>()
|
||||||
|
} finally {
|
||||||
|
await tcpCommunicator.disconnect()
|
||||||
|
this.log(`Disconnected from server at ${this.serverIp}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async validateBackupDirectories(backupDirectoryPath: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
const validUserDirectories = await this.fetchUsersFromServer()
|
||||||
|
|
||||||
|
if (!fs.existsSync(backupDirectoryPath)) {
|
||||||
|
this.log('Backup directory does not exist. No cleanup needed.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingDirectories = fs.readdirSync(backupDirectoryPath).filter((dir) =>
|
||||||
|
fs.statSync(path.join(backupDirectoryPath, dir)).isDirectory()
|
||||||
|
)
|
||||||
|
|
||||||
|
for (const directory of existingDirectories) {
|
||||||
|
if (!validUserDirectories.has(directory)) {
|
||||||
|
this.log(`Deleting unrecognized backup directory: ${directory}`, 'warn')
|
||||||
|
fs.rmSync(path.join(backupDirectoryPath, directory), { recursive: true, force: true })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.log('Backup directory validation and cleanup complete.')
|
||||||
|
} catch (error) {
|
||||||
|
// @ts-ignore
|
||||||
|
this.log(`Error validating backup directories: ${error.message}`, 'error')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async sendFilesToUsers(
|
private async sendFilesToUsers(
|
||||||
userName: string,
|
userInfo: UserInfoScheme,
|
||||||
usersIp: string[],
|
usersIp: string[],
|
||||||
fileStructure: { [key: string]: string },
|
fileStructure: { [key: string]: string },
|
||||||
backupDirectoryPath: string,
|
backupDirectoryPath: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
let unsentFiles = Object.keys(fileStructure)
|
let unsentFiles = Object.keys(fileStructure)
|
||||||
|
let remainingUsers = [...usersIp]
|
||||||
|
|
||||||
for (const fileName of unsentFiles) {
|
while (unsentFiles.length > 0 && remainingUsers.length > 0) {
|
||||||
|
for (const ip of remainingUsers) {
|
||||||
|
const tcpCommunicator = new TcpCommunicator(ip, this.port)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await tcpCommunicator.connect()
|
||||||
|
this.log(`Connected to ${ip}`)
|
||||||
|
|
||||||
|
const clearBackupMeta = { name: userInfo.name, departmentId: userInfo.departmentId }
|
||||||
|
await tcpCommunicator.sendMessage(operationCodes.CLEAR_BACKUP, clearBackupMeta)
|
||||||
|
|
||||||
|
for (const fileName of [...unsentFiles]) {
|
||||||
const filePath = fileStructure[fileName]
|
const filePath = fileStructure[fileName]
|
||||||
const encryptedFileContent = this.encryptFile(filePath)
|
const encryptedFileContent = this.encryptFile(filePath)
|
||||||
|
|
||||||
@@ -90,14 +168,11 @@ export class BackupManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const relativeFilePath = path.relative(backupDirectoryPath, filePath)
|
const relativeFilePath = path.relative(backupDirectoryPath, filePath)
|
||||||
const metaInfo = { userName, relativeFilePath }
|
const metaInfo = {
|
||||||
|
name: userInfo.name,
|
||||||
for (const ip of usersIp) {
|
departmentId: userInfo.departmentId,
|
||||||
const tcpCommunicator = new TcpCommunicator(ip, this.clientPort)
|
relativeFilePath,
|
||||||
|
}
|
||||||
try {
|
|
||||||
await tcpCommunicator.connect()
|
|
||||||
this.log(`Connected to ${ip}`)
|
|
||||||
|
|
||||||
const sendSuccess = await tcpCommunicator.sendMessage(
|
const sendSuccess = await tcpCommunicator.sendMessage(
|
||||||
operationCodes.BACKUP_FILE,
|
operationCodes.BACKUP_FILE,
|
||||||
@@ -115,14 +190,22 @@ export class BackupManager {
|
|||||||
|
|
||||||
this.log(`Successfully sent file: ${fileName} to ${ip}`)
|
this.log(`Successfully sent file: ${fileName} to ${ip}`)
|
||||||
unsentFiles = unsentFiles.filter((f) => f !== fileName)
|
unsentFiles = unsentFiles.filter((f) => f !== fileName)
|
||||||
break
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.log(`Failed to send file: ${fileName} to ${ip}. Error: ${error}`, 'error')
|
this.log(`Failed to send backup to ${ip}. Error: ${error}`, 'error')
|
||||||
} finally {
|
} finally {
|
||||||
await tcpCommunicator.disconnect()
|
await tcpCommunicator.disconnect()
|
||||||
this.log(`Disconnected from ${ip}`)
|
this.log(`Disconnected from ${ip}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update remaining users to retry
|
||||||
|
remainingUsers = usersIp.filter((ip) => !this.isBackupCompleteForIp(ip, unsentFiles))
|
||||||
|
|
||||||
|
if (remainingUsers.length === 0) {
|
||||||
|
this.log('Backup process retried for all users. Exiting retry loop.')
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unsentFiles.length > 0) {
|
if (unsentFiles.length > 0) {
|
||||||
@@ -132,6 +215,10 @@ export class BackupManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isBackupCompleteForIp(ip: string, unsentFiles: string[]): boolean {
|
||||||
|
return unsentFiles.length === 0
|
||||||
|
}
|
||||||
|
|
||||||
private async waitForResponse(tcpCommunicator: TcpCommunicator): Promise<ParsedMessage | null> {
|
private async waitForResponse(tcpCommunicator: TcpCommunicator): Promise<ParsedMessage | null> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const idResponseCheck = setInterval(() => {
|
const idResponseCheck = setInterval(() => {
|
||||||
@@ -152,7 +239,6 @@ export class BackupManager {
|
|||||||
this.intervalId = null
|
this.intervalId = null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for any ongoing process to complete if busy
|
|
||||||
while (this.isBusy) {
|
while (this.isBusy) {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 100))
|
await new Promise((resolve) => setTimeout(resolve, 100))
|
||||||
}
|
}
|
||||||
@@ -160,7 +246,6 @@ export class BackupManager {
|
|||||||
console.log('[BackupManager] Stopped successfully.')
|
console.log('[BackupManager] Stopped successfully.')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unified logging function
|
|
||||||
private log(message: string, level: 'log' | 'error' | 'warn' = 'log'): void {
|
private log(message: string, level: 'log' | 'error' | 'warn' = 'log'): void {
|
||||||
const prefix = '[BackupManager]'
|
const prefix = '[BackupManager]'
|
||||||
if (level === 'error') {
|
if (level === 'error') {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import fs from 'fs'
|
|||||||
import crypto from 'crypto'
|
import crypto from 'crypto'
|
||||||
import { ParsedMessage } from '../network/message_handler'
|
import { ParsedMessage } from '../network/message_handler'
|
||||||
import { Database } from '../database/database'
|
import { Database } from '../database/database'
|
||||||
|
import { UserInfoScheme } from '../database/schemes/app_config_scheme'
|
||||||
|
|
||||||
export class BackupRetrievalWorker {
|
export class BackupRetrievalWorker {
|
||||||
private db: Database
|
private db: Database
|
||||||
@@ -41,7 +42,6 @@ export class BackupRetrievalWorker {
|
|||||||
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
|
||||||
|
|
||||||
const userName = userInfo.name
|
|
||||||
this.encryptionKey = Buffer.from(encryptionKey.key, 'base64')
|
this.encryptionKey = Buffer.from(encryptionKey.key, 'base64')
|
||||||
this.iv = Buffer.from(encryptionKey.iv, 'base64')
|
this.iv = Buffer.from(encryptionKey.iv, 'base64')
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ export class BackupRetrievalWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const lanUser of activeUsers) {
|
for (const lanUser of activeUsers) {
|
||||||
const success = await this.processBackupForIp(lanUser.ip, userName)
|
const success = await this.processBackupForIp(lanUser.ip, userInfo)
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw new Error(`Failed to retrieve backup from ${lanUser.ip}`)
|
throw new Error(`Failed to retrieve backup from ${lanUser.ip}`)
|
||||||
}
|
}
|
||||||
@@ -73,33 +73,37 @@ export class BackupRetrievalWorker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async processBackupForIp(ip: string, userName: string): Promise<boolean> {
|
private async processBackupForIp(ip: string, userInfo: UserInfoScheme): Promise<boolean> {
|
||||||
this.tcpCommunicator = new TcpCommunicator(ip, this.clientPort)
|
this.tcpCommunicator = new TcpCommunicator(ip, this.clientPort)
|
||||||
if (!(await this.tcpCommunicator.connect())) {
|
if (!(await this.tcpCommunicator.connect())) {
|
||||||
this.log(`Failed to connect to ${ip}`, 'error')
|
this.log(`Failed to connect to ${ip}`, 'error')
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
const backupExists = await this.checkIfBackupExists(userName)
|
const backupExists = await this.checkIfBackupExists(userInfo.name, userInfo.departmentId)
|
||||||
if (!backupExists) {
|
if (!backupExists) {
|
||||||
this.log(`No backup found for user ${userName} on IP ${ip}`)
|
this.log(`No backup found for user ${userInfo.name} on IP ${ip}`)
|
||||||
await this.tcpCommunicator.disconnect()
|
await this.tcpCommunicator.disconnect()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
const backupStructure = await this.requestBackupStructure(userName)
|
const backupStructure = await this.requestBackupStructure(userInfo.name, userInfo.departmentId)
|
||||||
if (!backupStructure || Object.keys(backupStructure).length === 0) {
|
if (!backupStructure || Object.keys(backupStructure).length === 0) {
|
||||||
this.log(`No files found in backup structure for user ${userName} on IP ${ip}`)
|
this.log(`No files found in backup structure for user ${userInfo.name} on IP ${ip}`)
|
||||||
await this.tcpCommunicator.disconnect()
|
await this.tcpCommunicator.disconnect()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const relativeFilePath of Object.keys(backupStructure)) {
|
for (const relativeFilePath of Object.keys(backupStructure)) {
|
||||||
const fileRequestSuccess = await this.requestBackupFile(userName, relativeFilePath)
|
const fileRequestSuccess = await this.requestBackupFile(
|
||||||
|
userInfo.name,
|
||||||
|
userInfo.departmentId,
|
||||||
|
relativeFilePath,
|
||||||
|
)
|
||||||
if (!fileRequestSuccess) {
|
if (!fileRequestSuccess) {
|
||||||
await this.tcpCommunicator.disconnect()
|
await this.tcpCommunicator.disconnect()
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Failed to retrieve file ${relativeFilePath} from backup for user ${userName} on IP ${ip}`,
|
`Failed to retrieve file ${relativeFilePath} from backup for user ${userInfo.name} on IP ${ip}`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,10 +112,10 @@ export class BackupRetrievalWorker {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private async checkIfBackupExists(userName: string): Promise<boolean> {
|
private async checkIfBackupExists(name: string, departmentId: string): Promise<boolean> {
|
||||||
if (!this.tcpCommunicator) return false
|
if (!this.tcpCommunicator) return false
|
||||||
|
|
||||||
const metaInfo = { name: userName }
|
const metaInfo = { name, departmentId }
|
||||||
if (!(await this.tcpCommunicator.sendMessage(operationCodes.IS_BACKUP_CREATED, metaInfo)))
|
if (!(await this.tcpCommunicator.sendMessage(operationCodes.IS_BACKUP_CREATED, metaInfo)))
|
||||||
return false
|
return false
|
||||||
|
|
||||||
@@ -119,10 +123,10 @@ export class BackupRetrievalWorker {
|
|||||||
return response?.metaInfo?.backupExists === true
|
return response?.metaInfo?.backupExists === true
|
||||||
}
|
}
|
||||||
|
|
||||||
private async requestBackupStructure(userName: string): Promise<any> {
|
private async requestBackupStructure(name: string, departmentId: string): Promise<any> {
|
||||||
if (!this.tcpCommunicator) return false
|
if (!this.tcpCommunicator) return false
|
||||||
|
|
||||||
const metaInfo = { name: userName }
|
const metaInfo = { name, departmentId }
|
||||||
if (!(await this.tcpCommunicator.sendMessage(operationCodes.GET_BACKUP_STRUCTURE, metaInfo)))
|
if (!(await this.tcpCommunicator.sendMessage(operationCodes.GET_BACKUP_STRUCTURE, metaInfo)))
|
||||||
return null
|
return null
|
||||||
|
|
||||||
@@ -130,10 +134,14 @@ export class BackupRetrievalWorker {
|
|||||||
return response?.metaInfo?.structure || null
|
return response?.metaInfo?.structure || null
|
||||||
}
|
}
|
||||||
|
|
||||||
private async requestBackupFile(userName: string, relativeFilePath: string): Promise<boolean> {
|
private async requestBackupFile(
|
||||||
|
name: string,
|
||||||
|
departmentId: string,
|
||||||
|
relativeFilePath: string,
|
||||||
|
): Promise<boolean> {
|
||||||
if (!this.tcpCommunicator) return false
|
if (!this.tcpCommunicator) return false
|
||||||
|
|
||||||
const metaInfo = { name: userName, relativeFilePath }
|
const metaInfo = { name, departmentId, relativeFilePath }
|
||||||
if (!(await this.tcpCommunicator.sendMessage(operationCodes.REQ_FILE_FROM_BACKUP, metaInfo)))
|
if (!(await this.tcpCommunicator.sendMessage(operationCodes.REQ_FILE_FROM_BACKUP, metaInfo)))
|
||||||
return false
|
return false
|
||||||
|
|
||||||
@@ -185,17 +193,6 @@ export class BackupRetrievalWorker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async stop(): Promise<void> {
|
|
||||||
this.stopRequested = true // Signal that stop is requested
|
|
||||||
|
|
||||||
// Wait for any ongoing process to complete if busy
|
|
||||||
while (this.isBusy) {
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 100))
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('[BackupManager] Stopped successfully.')
|
|
||||||
}
|
|
||||||
|
|
||||||
private async waitForResponse(): Promise<ParsedMessage | null> {
|
private async waitForResponse(): Promise<ParsedMessage | null> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const idResponseCheck = setInterval(async () => {
|
const idResponseCheck = setInterval(async () => {
|
||||||
|
|||||||
@@ -4,7 +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";
|
import { NetworkUserScheme } from '../database/schemes/network_scheme'
|
||||||
|
|
||||||
export class DepartmentSharer {
|
export class DepartmentSharer {
|
||||||
private readonly db: Database
|
private readonly db: Database
|
||||||
|
|||||||
@@ -113,7 +113,6 @@ export class NetworkScanner {
|
|||||||
// 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 = activeClients.map((client) => ({
|
data.network.usersInLan = activeClients.map((client) => ({
|
||||||
id: client.id,
|
|
||||||
ip: client.ip,
|
ip: client.ip,
|
||||||
name: client.name,
|
name: client.name,
|
||||||
departmentId: client.departmentId,
|
departmentId: client.departmentId,
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ export class GeneralOperations implements OperationPlugin {
|
|||||||
if (data.app_config.logged_in) {
|
if (data.app_config.logged_in) {
|
||||||
response.name = data.app_config.user_info.name
|
response.name = data.app_config.user_info.name
|
||||||
response.departmentId = data.app_config.user_info.departmentId
|
response.departmentId = data.app_config.user_info.departmentId
|
||||||
response.id = data.app_config.user_info.id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -64,7 +64,8 @@ export class UserToUserOperations implements OperationPlugin {
|
|||||||
|
|
||||||
public static async handleBackupFile(parsedMessage: ParsedMessage): Promise<ParsedMessage> {
|
public static async handleBackupFile(parsedMessage: ParsedMessage): Promise<ParsedMessage> {
|
||||||
if (
|
if (
|
||||||
!parsedMessage.metaInfo?.userName ||
|
!parsedMessage.metaInfo?.name ||
|
||||||
|
!parsedMessage.metaInfo.departmentId ||
|
||||||
!parsedMessage.metaInfo?.relativeFilePath ||
|
!parsedMessage.metaInfo?.relativeFilePath ||
|
||||||
!parsedMessage.fileContent
|
!parsedMessage.fileContent
|
||||||
) {
|
) {
|
||||||
@@ -74,8 +75,15 @@ export class UserToUserOperations implements OperationPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { userName, relativeFilePath } = parsedMessage.metaInfo
|
const { name, departmentId, relativeFilePath } = parsedMessage.metaInfo
|
||||||
const fullFilePath = path.join(__dirname, '..', '..', 'backups', userName, relativeFilePath)
|
const fullFilePath = path.join(
|
||||||
|
__dirname,
|
||||||
|
'..',
|
||||||
|
'..',
|
||||||
|
'backups',
|
||||||
|
`${name}-${departmentId}`,
|
||||||
|
relativeFilePath,
|
||||||
|
)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!(await UserToUserOperations.hasEnoughDiskSpace(path.dirname(fullFilePath), 25))) {
|
if (!(await UserToUserOperations.hasEnoughDiskSpace(path.dirname(fullFilePath), 25))) {
|
||||||
@@ -103,17 +111,13 @@ export class UserToUserOperations implements OperationPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static async handleClearBackup(parsedMessage: ParsedMessage): Promise<ParsedMessage> {
|
public static async handleClearBackup(parsedMessage: ParsedMessage): Promise<ParsedMessage> {
|
||||||
if (!parsedMessage.metaInfo?.userName) {
|
if (!parsedMessage.metaInfo?.name || !parsedMessage.metaInfo?.departmentId) {
|
||||||
return { operationCode: operationCodes.ERR, metaInfo: { message: 'Missing user name.' } }
|
return { operationCode: operationCodes.ERR, metaInfo: { message: 'Missing user name.' } }
|
||||||
}
|
}
|
||||||
|
|
||||||
const userBackupDir = path.join(
|
const { name, departmentId } = parsedMessage.metaInfo
|
||||||
__dirname,
|
|
||||||
'..',
|
const userBackupDir = path.join(__dirname, '..', '..', 'backups', `${name}-${departmentId}`)
|
||||||
'..',
|
|
||||||
'backups',
|
|
||||||
parsedMessage.metaInfo.userName,
|
|
||||||
)
|
|
||||||
try {
|
try {
|
||||||
await fs.rm(userBackupDir, { recursive: true, force: true })
|
await fs.rm(userBackupDir, { recursive: true, force: true })
|
||||||
console.log(`Backup cleared: ${userBackupDir}`)
|
console.log(`Backup cleared: ${userBackupDir}`)
|
||||||
@@ -146,8 +150,6 @@ export class UserToUserOperations implements OperationPlugin {
|
|||||||
const data = await database.read()
|
const data = await database.read()
|
||||||
const shareDirectory = data.local_resources.directory_schemes.shared.path
|
const shareDirectory = data.local_resources.directory_schemes.shared.path
|
||||||
|
|
||||||
console.log(`\n\nShare directory: ${shareDirectory}\n\n`)
|
|
||||||
|
|
||||||
if (!shareDirectory || shareDirectory === '') {
|
if (!shareDirectory || shareDirectory === '') {
|
||||||
return {
|
return {
|
||||||
operationCode: operationCodes.ERR,
|
operationCode: operationCodes.ERR,
|
||||||
@@ -267,14 +269,16 @@ export class UserToUserOperations implements OperationPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static async handleIsBackupCreated(parsedMessage: ParsedMessage): Promise<ParsedMessage> {
|
public static async handleIsBackupCreated(parsedMessage: ParsedMessage): Promise<ParsedMessage> {
|
||||||
if (!parsedMessage.metaInfo?.name) {
|
if (!parsedMessage.metaInfo?.name || !parsedMessage.metaInfo?.departmentId) {
|
||||||
return {
|
return {
|
||||||
operationCode: operationCodes.ERR,
|
operationCode: operationCodes.ERR,
|
||||||
metaInfo: { message: 'Missing name in meta information.' },
|
metaInfo: { message: 'Missing name in meta information.' },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const userBackupDir = path.join(__dirname, '..', '..', 'backups', parsedMessage.metaInfo.name)
|
const { name, departmentId } = parsedMessage.metaInfo
|
||||||
|
|
||||||
|
const userBackupDir = path.join(__dirname, '..', '..', 'backups', `${name}-${departmentId}`)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const exists = await fs
|
const exists = await fs
|
||||||
@@ -294,14 +298,16 @@ export class UserToUserOperations implements OperationPlugin {
|
|||||||
public static async handleGetBackupStructure(
|
public static async handleGetBackupStructure(
|
||||||
parsedMessage: ParsedMessage,
|
parsedMessage: ParsedMessage,
|
||||||
): Promise<ParsedMessage> {
|
): Promise<ParsedMessage> {
|
||||||
if (!parsedMessage.metaInfo?.name) {
|
if (!parsedMessage.metaInfo?.name || !parsedMessage.metaInfo?.departmentId) {
|
||||||
return {
|
return {
|
||||||
operationCode: operationCodes.ERR,
|
operationCode: operationCodes.ERR,
|
||||||
metaInfo: { message: 'Missing name in meta information.' },
|
metaInfo: { message: 'Missing name in meta information.' },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const userBackupDir = path.join(__dirname, '..', '..', 'backups', parsedMessage.metaInfo.name)
|
const { name, departmentId } = parsedMessage.metaInfo
|
||||||
|
|
||||||
|
const userBackupDir = path.join(__dirname, '..', '..', 'backups', `${name}-${departmentId}`)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const structure = await UserToUserOperations.buildDirectoryStructure(userBackupDir)
|
const structure = await UserToUserOperations.buildDirectoryStructure(userBackupDir)
|
||||||
@@ -333,15 +339,26 @@ export class UserToUserOperations implements OperationPlugin {
|
|||||||
public static async handleReqFileFromBackup(
|
public static async handleReqFileFromBackup(
|
||||||
parsedMessage: ParsedMessage,
|
parsedMessage: ParsedMessage,
|
||||||
): Promise<ParsedMessage> {
|
): Promise<ParsedMessage> {
|
||||||
if (!parsedMessage.metaInfo?.name || !parsedMessage.metaInfo?.relativeFilePath) {
|
if (
|
||||||
|
!parsedMessage.metaInfo?.name ||
|
||||||
|
!parsedMessage.metaInfo?.departmentId ||
|
||||||
|
!parsedMessage.metaInfo?.relativeFilePath
|
||||||
|
) {
|
||||||
return {
|
return {
|
||||||
operationCode: operationCodes.ERR,
|
operationCode: operationCodes.ERR,
|
||||||
metaInfo: { message: 'Missing user name or file path in meta information.' },
|
metaInfo: { message: 'Missing user name or file path in meta information.' },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { name, relativeFilePath } = parsedMessage.metaInfo
|
const { name, departmentId, relativeFilePath } = parsedMessage.metaInfo
|
||||||
const fullFilePath = path.join(__dirname, '..', '..', 'backups', name, relativeFilePath)
|
const fullFilePath = path.join(
|
||||||
|
__dirname,
|
||||||
|
'..',
|
||||||
|
'..',
|
||||||
|
'backups',
|
||||||
|
`${name}-${departmentId}`,
|
||||||
|
relativeFilePath,
|
||||||
|
)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const fileContent = await fs.readFile(fullFilePath)
|
const fileContent = await fs.readFile(fullFilePath)
|
||||||
|
|||||||
@@ -107,8 +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')
|
||||||
} catch (err: any) {
|
} catch (err: any) {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the subnet (e.g., 192.168.1)
|
// Get the subnet (e.g., 192.168.1)
|
||||||
|
|||||||
Reference in New Issue
Block a user