Skip to content

Commit

Permalink
feat/backups progress
Browse files Browse the repository at this point in the history
  • Loading branch information
ArceDanielShok committed Aug 7, 2024
1 parent 15cd6a0 commit 3d47892
Show file tree
Hide file tree
Showing 8 changed files with 295 additions and 30 deletions.
13 changes: 13 additions & 0 deletions .hintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"extends": [
"development"
],
"hints": {
"axe/aria": [
"default",
{
"aria-required-children": "off"
}
]
}
}
237 changes: 237 additions & 0 deletions src/apps/backups/Backups.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
// import { Service } from 'diod';
// import Logger from 'electron-log';
// import { FileBatchUpdater } from '../../context/local/localFile/application/update/FileBatchUpdater';
// import { FileBatchUploader } from '../../context/local/localFile/application/upload/FileBatchUploader';
// import { LocalFile } from '../../context/local/localFile/domain/LocalFile';
// import { AbsolutePath } from '../../context/local/localFile/infrastructure/AbsolutePath';
// import LocalTreeBuilder from '../../context/local/localTree/application/LocalTreeBuilder';
// import { LocalTree } from '../../context/local/localTree/domain/LocalTree';
// import { FileDeleter } from '../../context/virtual-drive/files/application/delete/FileDeleter';
// import { File } from '../../context/virtual-drive/files/domain/File';
// import { SimpleFolderCreator } from '../../context/virtual-drive/folders/application/create/SimpleFolderCreator';
// import { RemoteTreeBuilder } from '../../context/virtual-drive/remoteTree/application/RemoteTreeBuilder';
// import { RemoteTree } from '../../context/virtual-drive/remoteTree/domain/RemoteTree';
// import { BackupInfo } from './BackupInfo';
// import { BackupsIPCRenderer } from './BackupsIPCRenderer';
// import { AddedFilesBatchCreator } from './batches/AddedFilesBatchCreator';
// import { ModifiedFilesBatchCreator } from './batches/ModifiedFilesBatchCreator';
// import { DiffFilesCalculator, FilesDiff } from './diff/DiffFilesCalculator';
// import {
// FoldersDiff,
// FoldersDiffCalculator,
// } from './diff/FoldersDiffCalculator';
// import { relative } from './utils/relative';
// import { DriveDesktopError } from '../../context/shared/domain/errors/DriveDesktopError';
// import { UserAvaliableSpaceValidator } from '../../context/user/usage/application/UserAvaliableSpaceValidator';

// @Service()
// export class Backup {
// constructor(
// private readonly localTreeBuilder: LocalTreeBuilder,
// private readonly remoteTreeBuilder: RemoteTreeBuilder,
// private readonly fileBatchUploader: FileBatchUploader,
// private readonly fileBatchUpdater: FileBatchUpdater,
// private readonly remoteFileDeleter: FileDeleter,
// private readonly simpleFolderCreator: SimpleFolderCreator,
// private readonly userAvaliableSpaceValidator: UserAvaliableSpaceValidator
// ) {}

// private backed = 0;

// async run(
// info: BackupInfo,
// abortController: AbortController
// ): Promise<DriveDesktopError | undefined> {
// Logger.info('[BACKUPS] Backing:', info.pathname);

// Logger.info('[BACKUPS] Generating local tree');
// const localTreeEither = await this.localTreeBuilder.run(
// info.pathname as AbsolutePath
// );

// if (localTreeEither.isLeft()) {
// return localTreeEither.getLeft();
// }

// const local = localTreeEither.getRight();

// Logger.info('[BACKUPS] Generating remote tree');
// const remote = await this.remoteTreeBuilder.run(info.folderId);

// const foldersDiff = FoldersDiffCalculator.calculate(local, remote);

// const filesDiff = DiffFilesCalculator.calculate(local, remote);

// await this.isThereEnoughSpace(filesDiff);

// const alreadyBacked =
// filesDiff.unmodified.length + foldersDiff.unmodified.length;

// this.backed = alreadyBacked;

// BackupsIPCRenderer.send(
// 'backups.total-items-calculated',
// filesDiff.total + foldersDiff.total,
// alreadyBacked
// );

// await this.backupFolders(foldersDiff, local, remote);

// await this.backupFiles(filesDiff, local, remote, abortController);

// return undefined;
// }

// private async isThereEnoughSpace(filesDiff: FilesDiff): Promise<void> {
// const bytesToUpload = filesDiff.added.reduce((acc, file) => {
// acc += file.size;

// return acc;
// }, 0);

// const bytesToUpdate = Array.from(filesDiff.modified.entries()).reduce(
// (acc, [local, remote]) => {
// acc += local.size - remote.size;

// return acc;
// },
// 0
// );

// const total = bytesToUpdate + bytesToUpload;

// const thereIsEnoughSpace = await this.userAvaliableSpaceValidator.run(
// total
// );

// if (!thereIsEnoughSpace) {
// throw new DriveDesktopError(
// 'NOT_ENOUGH_SPACE',
// 'The size of the files to upload is greater than the avaliable space'
// );
// }
// }

// private async backupFolders(
// diff: FoldersDiff,
// local: LocalTree,
// remote: RemoteTree
// ) {
// Logger.info('[BACKUPS] Backing folders');

// Logger.info('[BACKUPS] Folders added', diff.added.length);

// for (const localFolder of diff.added) {
// const remoteParentPath = relative(local.root.path, localFolder.basedir());

// const parentExists = remote.has(remoteParentPath);

// if (!parentExists) {
// continue;
// }

// const parent = remote.getParent(
// relative(local.root.path, localFolder.path)
// );

// // eslint-disable-next-line no-await-in-loop
// const folder = await this.simpleFolderCreator.run(
// relative(local.root.path, localFolder.path),
// parent.id
// );

// remote.addFolder(parent, folder);

// this.backed++;
// BackupsIPCRenderer.send('backups.progress-update', this.backed);
// }
// }

// private async backupFiles(
// filesDiff: FilesDiff,
// local: LocalTree,
// remote: RemoteTree,
// abortController: AbortController
// ) {
// Logger.info('[BACKUPS] Backing files');

// const { added, modified, deleted } = filesDiff;

// Logger.info('[BACKUPS] Files added', added.length);
// await this.uploadAndCreate(local.root.path, added, remote, abortController);

// Logger.info('[BACKUPS] Files modified', modified.size);
// await this.uploadAndUpdate(modified, local, remote, abortController);

// Logger.info('[BACKUPS] Files deleted', deleted.length);
// await this.deleteRemoteFiles(deleted, abortController);
// }

// private async uploadAndCreate(
// localRootPath: string,
// added: Array<LocalFile>,
// tree: RemoteTree,
// abortController: AbortController
// ): Promise<void> {
// const batches = AddedFilesBatchCreator.run(added);

// for (const batch of batches) {
// if (abortController.signal.aborted) {
// return;
// }
// // eslint-disable-next-line no-await-in-loop
// await this.fileBatchUploader.run(
// localRootPath,
// tree,
// batch,
// abortController.signal
// );

// this.backed += batch.length;
// BackupsIPCRenderer.send('backups.progress-update', this.backed);
// }
// }

// private async uploadAndUpdate(
// modified: Map<LocalFile, File>,
// localTree: LocalTree,
// remoteTree: RemoteTree,
// abortController: AbortController
// ): Promise<void> {
// const batches = ModifiedFilesBatchCreator.run(modified);

// for (const batch of batches) {
// Logger.debug('Signal aborted', abortController.signal.aborted);
// if (abortController.signal.aborted) {
// return;
// }
// // eslint-disable-next-line no-await-in-loop
// await this.fileBatchUpdater.run(
// localTree.root,
// remoteTree,
// Array.from(batch.keys()),
// abortController.signal
// );

// this.backed += batch.size;
// BackupsIPCRenderer.send('backups.progress-update', this.backed);
// }
// }

// private async deleteRemoteFiles(
// deleted: Array<File>,
// abortController: AbortController
// ) {
// for (const file of deleted) {
// if (abortController.signal.aborted) {
// return;
// }

// // eslint-disable-next-line no-await-in-loop
// await this.remoteFileDeleter.run(file);
// }

// this.backed += deleted.length;
// BackupsIPCRenderer.send('backups.progress-update', this.backed);
// }
// }
53 changes: 30 additions & 23 deletions src/apps/main/device/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,15 @@ export async function getBackupsFromDevice(
async function postBackup(name: string): Promise<Backup> {
const deviceId = getDeviceId();

const res = await fetch(`${process.env.API_URL}/api/storage/folder`, {
const res = await fetch(`${process.env.API_URL}/storage/folder`, {
method: 'POST',
headers: getHeaders(true),
body: JSON.stringify({ parentFolderId: deviceId, folderName: name }),
});
if (res.ok) {
return res.json();
}
logger.error(res);
throw new Error('Post backup request wasnt successful');
}

Expand All @@ -227,33 +228,39 @@ async function createBackup(pathname: string): Promise<void> {
}

export async function addBackup(): Promise<void> {
const chosenItem = await getPathFromDialog();
if (!chosenItem || !chosenItem.path) {
return;
}
try {
const chosenItem = await getPathFromDialog();
if (!chosenItem || !chosenItem.path) {
return;
}

const chosenPath = chosenItem.path;
const backupList = configStore.get('backupList');
const chosenPath = chosenItem.path;
logger.debug(`[BACKUPS] Chosen item: ${chosenItem.path}`);

const existingBackup = backupList[chosenPath];
const backupList = configStore.get('backupList');

if (!existingBackup) {
return createBackup(chosenPath);
}
const existingBackup = backupList[chosenPath];

let folderStillExists;
try {
await fetchFolder(existingBackup.folderId);
folderStillExists = true;
} catch {
folderStillExists = false;
}
if (!existingBackup) {
return createBackup(chosenPath);
}

if (folderStillExists) {
backupList[chosenPath].enabled = true;
configStore.set('backupList', backupList);
} else {
return createBackup(chosenPath);
let folderStillExists;
try {
await fetchFolder(existingBackup.folderId);
folderStillExists = true;
} catch {
folderStillExists = false;
}

if (folderStillExists) {
backupList[chosenPath].enabled = true;
configStore.set('backupList', backupList);
} else {
return createBackup(chosenPath);
}
} catch (error) {
logger.error(error);
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/apps/renderer/localize/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@
"add-folders": "Click + to select the folders\n you want to back up",
"activate": "Back up your folders and files",
"view-backups": "View your backups",
"selected-folders-title": "Selected folders",
"select-folders": "Select folders to back up",
"last-backup-had-issues": "Last backup had some issues",
"see-issues": "See issues",
Expand All @@ -307,6 +308,8 @@
"explanation": "Folders you want to add to the next backup",
"no-folders": "No backups yet",
"done": "Done",
"cancel": "Cancel",
"save": "Save",
"stop-baking-up": {
"title": "Stop backing up ",
"explanation": "New files added to this folder will no longer backup in your Internxt Drive. Original files will remain on your computer",
Expand Down
2 changes: 1 addition & 1 deletion src/apps/renderer/pages/Settings/Backups/EnableBackups.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface EnableBackupsProps {

export function EnableBackups({ enable }: EnableBackupsProps) {
return (
<div className="flex flex-col items-center justify-center">
<div className="flex flex-col items-center justify-center h-full">
<DriveIcon className="mt-6" />
<h1 className="font-semibold">INTERNXT BACKUPS</h1>
<p className="mb-6 text-center">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default function BackupFolderSelector({
</div>
</div>
<div
className="border-l-neutral-30 h-44 overflow-y-auto rounded-lg border border-gray-20 bg-white"
className="border-l-neutral-30 h-44 overflow-y-auto rounded-lg border border-gray-20 bg-white dark:bg-black"
onClick={() => setSelectedBackup(null)}
role="none"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ export function BackupsList({
return (
<ul>
{backups.map((backup, index) => (
<li
onClick={(e) => {
<li role="row" aria-rowindex={index + 1} key={backup.folderId}
onClick={(e: React.MouseEvent<HTMLLIElement>) => {
e.stopPropagation();
setSelected(backup);
}}
Expand All @@ -28,10 +28,14 @@ export function BackupsList({
selected?.folderId === backup.folderId
? 'bg-primary text-white'
: index % 2 !== 0
? 'text-neutral-700 bg-white'
: 'bg-l-neutral-10 text-neutral-700'
? 'text-neutral-700 bg-white dark:bg-black'
: 'bg-l-neutral-10 text-neutral-700 dark:bg-black'
}`}
>
onClick={(e: React.MouseEvent<HTMLLIElement>) => {
e.stopPropagation();
setSelected(backup);
}}
>
<BackupListItem
backup={backup}
selected={selected?.folderId === backup.folderId}
Expand Down
Loading

0 comments on commit 3d47892

Please sign in to comment.