Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions src/apps/backups/BackupService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ export class BackupService {
await this.isThereEnoughSpace(filesDiff);
logger.debug({ tag: 'BACKUPS', msg: 'Space check completed' });

const itemsAlreadyBacked = filesDiff.unmodified.length + foldersDiff.unmodified.length;
tracker.addToTotal(filesDiff.total + foldersDiff.total);
const emptyAddedFiles = filesDiff.added.filter((f) => f.size === 0).length;
const itemsAlreadyBacked = filesDiff.unmodified.length + foldersDiff.unmodified.length + emptyAddedFiles;
tracker.incrementProcessed(itemsAlreadyBacked);

logger.debug({ tag: 'BACKUPS', msg: 'Starting folder backup' });
Expand Down Expand Up @@ -212,8 +212,9 @@ export class BackupService {
return;
}
// eslint-disable-next-line no-await-in-loop
await this.fileBatchUploader.run(localRootPath, tree, batch, signal);
tracker.incrementProcessed(batch.length);
await this.fileBatchUploader.run(localRootPath, tree, batch, signal, () => {
tracker.incrementProcessed(1);
});
}
}

Expand All @@ -227,13 +228,13 @@ export class BackupService {
const batches = ModifiedFilesBatchCreator.run(modified);

for (const batch of batches) {
logger.debug({ tag: 'BACKUPS', msg: 'Signal aborted', aborted: signal.aborted });
if (signal.aborted) {
return;
}
// eslint-disable-next-line no-await-in-loop
await this.fileBatchUpdater.run(localTree.root, remoteTree, Array.from(batch.keys()), signal);
tracker.incrementProcessed(batch.size);
await this.fileBatchUpdater.run(localTree.root, remoteTree, Array.from(batch.keys()), signal, () => {
tracker.incrementProcessed(1);
});
}
}

Expand All @@ -249,7 +250,7 @@ export class BackupService {

// eslint-disable-next-line no-await-in-loop
await addFileToTrash(file.uuid);
tracker.incrementProcessed(1);
}
tracker.incrementProcessed(deleted.length);
}
}
91 changes: 91 additions & 0 deletions src/backend/features/backup/backup-progress-state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
export type BackupProgressState = {
readonly processedItems: number;
readonly backupWeights: ReadonlyMap<string, number>;
readonly backupTotals: ReadonlyMap<string, number>;
readonly currentBackupId: string;
readonly completedBackups: ReadonlySet<string>;
};

export const createInitialState = (): BackupProgressState => ({
processedItems: 0,
backupWeights: new Map(),
backupTotals: new Map(),
currentBackupId: '',
completedBackups: new Set(),
});

export const initializeWeights = (
state: BackupProgressState,
backupIds: string[],
fileCounts: ReadonlyMap<string, number>,
): BackupProgressState => {
const totalFiles = Array.from(fileCounts.values()).reduce((a, b) => a + b, 0);

if (totalFiles === 0) {
return state;
}

const weights = new Map<string, number>();
const totals = new Map<string, number>();

backupIds.forEach((id) => {
const count = fileCounts.get(id) || 1;
weights.set(id, count / totalFiles);
totals.set(id, count);
});

return {
...state,
backupWeights: weights,
backupTotals: totals,
};
};

export const setCurrentBackupId = (state: BackupProgressState, backupId: string): BackupProgressState => ({
...state,
currentBackupId: backupId,
processedItems: 0,
});

export const incrementProcessed = (state: BackupProgressState, count: number = 1): BackupProgressState => ({
...state,
processedItems: state.processedItems + count,
});

export const markBackupAsCompleted = (state: BackupProgressState, backupId: string): BackupProgressState => ({
...state,
completedBackups: new Set([...state.completedBackups, backupId]),
});

export const getPercentage = (state: BackupProgressState): number => {
let weightedProgress = 0;

for (const backupId of state.completedBackups) {
const weight = state.backupWeights.get(backupId) || 0;
weightedProgress += weight * 100;
}

if (state.backupWeights.has(state.currentBackupId) && !state.completedBackups.has(state.currentBackupId)) {
const currentWeight = state.backupWeights.get(state.currentBackupId)!;
const currentTotal = state.backupTotals.get(state.currentBackupId) || 1;

if (currentTotal > 0) {
const backupProgress = (state.processedItems / currentTotal) * 100;
weightedProgress += currentWeight * backupProgress;
}
}

return Math.min(100, Math.round(weightedProgress));
};

export const resetState = (): BackupProgressState => createInitialState();

export const initializeAndSetBackup = (
state: BackupProgressState,
backupIds: string[],
fileCounts: ReadonlyMap<string, number>,
firstBackupId: string,
): BackupProgressState => {
const weightedState = initializeWeights(state, backupIds, fileCounts);
return setCurrentBackupId(weightedState, firstBackupId);
};
Loading
Loading