Skip to content
Merged
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
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "internxt-drive",
"version": "2.6.5",
"version": "2.6.6",
"author": "Internxt <hello@internxt.com>",
"description": "Internxt client UI",
"main": "./dist/main/main.js",
Expand Down
2 changes: 1 addition & 1 deletion src/apps/backups/folders/create-folders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export async function createFolders({ ctx, added, tree }: TProps) {

for (const path of sortedAdded) {
try {
await scheduleRequest({ ctx, fn: () => createFolder(ctx, path, tree) });
await scheduleRequest({ ctx, path, fn: () => createFolder(ctx, path, tree) });
} catch (error) {
ctx.logger.error({ msg: 'Error creating folder', path, error });
}
Expand Down
2 changes: 1 addition & 1 deletion src/apps/backups/folders/delete-folders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export async function deleteFolders({ ctx, deleted }: TProps) {
const path = folder.absolutePath;

try {
await scheduleRequest({ ctx, fn: () => deleteFolderByUuid({ ctx, uuid: folder.uuid, path }) });
await scheduleRequest({ ctx, path, fn: () => deleteFolderByUuid({ ctx, uuid: folder.uuid, path }) });
} catch (error) {
ctx.logger.error({ msg: 'Error deleting folder', path, error });
}
Expand Down
2 changes: 1 addition & 1 deletion src/apps/backups/process-files/create-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export async function createFiles({ ctx, remoteTree, added }: Props) {
const path = local.path;

try {
await scheduleRequest({ ctx, fn: () => createFile(ctx, path, remoteTree) });
await scheduleRequest({ ctx, path, fn: () => createFile(ctx, path, remoteTree) });
} catch (error) {
ctx.logger.error({ msg: 'Error creating file', path, error });
}
Expand Down
2 changes: 1 addition & 1 deletion src/apps/backups/process-files/delete-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export async function deleteFiles({ ctx, deleted }: TProps) {
const path = file.absolutePath;

try {
await scheduleRequest({ ctx, fn: () => deleteFileByUuid({ ctx, uuid: file.uuid, path }) });
await scheduleRequest({ ctx, path, fn: () => deleteFileByUuid({ ctx, uuid: file.uuid, path }) });
} catch (error) {
ctx.logger.error({ msg: 'Error deleting folder', path, error });
}
Expand Down
2 changes: 1 addition & 1 deletion src/apps/backups/process-files/replace-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export async function replaceFiles({ ctx, modified }: Props) {
const path = local.path;

try {
await scheduleRequest({ ctx, fn: () => Sync.Actions.replaceFile({ ctx, path, uuid: remote.uuid }) });
await scheduleRequest({ ctx, path, fn: () => Sync.Actions.replaceFile({ ctx, path, uuid: remote.uuid }) });
} catch (error) {
ctx.logger.error({ msg: 'Error replacing file', path, error });
}
Expand Down
6 changes: 4 additions & 2 deletions src/apps/backups/schedule-request.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import { isBottleneckStop } from '@/infra/drive-server-wip/in/helpers/error-helpers';
import { tracker } from '../main/background-processes/backups/BackupsProcessTracker/BackupsProcessTracker';
import { BackupsContext } from './BackupInfo';
import { AbsolutePath } from '@internxt/drive-desktop-core/build/backend';

type Props = {
ctx: BackupsContext;
path: AbsolutePath;
fn: () => Promise<unknown>;
};

export async function scheduleRequest({ ctx, fn }: Props) {
export async function scheduleRequest({ ctx, path, fn }: Props) {
try {
await ctx.backupsBottleneck.schedule(() => fn());
} catch (error) {
if (isBottleneckStop({ error })) return;

throw error;
} finally {
tracker.currentProcessed();
tracker.currentProcessed(path);
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AbsolutePath } from '@internxt/drive-desktop-core/build/backend';
import { BackupInfo } from '../../../../backups/BackupInfo';
import { broadcastToWindows } from '../../../windows';
import { BackupsStatus } from '../BackupsProcessStatus/BackupsStatus';
Expand All @@ -17,10 +18,16 @@ export class BackupsProcessTracker {

private abortController: AbortController | undefined;

notify() {
notify(path?: AbsolutePath) {
if (this.abortController && !this.abortController.signal.aborted) {
logger.debug({ tag: 'BACKUPS', msg: 'Progress', progress: this.progress() });
broadcastToWindows({ name: 'backup-progress', data: this.progress() });
logger.debug({
tag: 'BACKUPS',
msg: 'Progress',
...(path && { path }),
total: this.current.total,
processed: this.current.processed,
});
}
}

Expand All @@ -43,9 +50,9 @@ export class BackupsProcessTracker {
this.notify();
}

currentProcessed() {
currentProcessed(path: AbsolutePath) {
this.current.processed++;
this.notify();
this.notify(path);
}

setStatus(status: BackupsStatus) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { call, calls, mockProps, partialSpyOn } from '@/tests/vitest/utils.helper.test';
import { loadVirtualDrive } from './load-virtual-drive';
import { VirtualDrive } from '@/node-win/virtual-drive';
import { NodeWin } from '@/infra/node-win/node-win.module';
import * as addSyncIssue from '../../issues';
import { RegisterSyncRootError } from '@/infra/node-win/services/register-sync-root';
import { loggerMock } from '@/tests/vitest/mocks.helper.test';
import { Addon } from '@/node-win/addon-wrapper';

describe('load-virtual-drive', () => {
partialSpyOn(VirtualDrive, 'createSyncRootFolder');
const NodeWinRegisterSyncRootMock = partialSpyOn(NodeWin, 'registerSyncRoot');
const AddonRegisterSyncRootMock = partialSpyOn(Addon, 'registerSyncRoot');
const getSyncRootFromPathMock = partialSpyOn(Addon, 'getSyncRootFromPath');
const unregisterSyncRootMock = partialSpyOn(Addon, 'unregisterSyncRoot');
const connectSyncRootMock = partialSpyOn(Addon, 'connectSyncRoot');
const addSyncIssueMock = partialSpyOn(addSyncIssue, 'addSyncIssue');

const props = mockProps<typeof loadVirtualDrive>({ ctx: { providerId: 'syncRootId' } });

beforeEach(() => {
getSyncRootFromPathMock.mockResolvedValue({ id: 'oldSyncRootId' });
connectSyncRootMock.mockReturnValue(1n);
});

it('should add sync issue if register sync root gives UNKNOWN error', async () => {
// Given
NodeWinRegisterSyncRootMock.mockResolvedValue(new RegisterSyncRootError('UNKNOWN'));
// When
const connectionkey = await loadVirtualDrive(props);
// Then
expect(connectionkey).toBeUndefined();
call(addSyncIssueMock).toMatchObject({ error: 'CANNOT_REGISTER_VIRTUAL_DRIVE' });
call(loggerMock.error).toMatchObject({ msg: 'Error loading virtual drive' });
});

it('should add sync issue if there is no old sync root registered when ACCESS_DENIED', async () => {
// Given
NodeWinRegisterSyncRootMock.mockResolvedValue(new RegisterSyncRootError('ACCESS_DENIED'));
getSyncRootFromPathMock.mockRejectedValue(new Error());
// When
const connectionkey = await loadVirtualDrive(props);
// Then
expect(connectionkey).toBeUndefined();
call(addSyncIssueMock).toMatchObject({ error: 'CANNOT_REGISTER_VIRTUAL_DRIVE' });
calls(loggerMock.error).toMatchObject([{ msg: 'Error getting sync root from path' }, { msg: 'Error loading virtual drive' }]);
});

it('should unregister and register if there is an old sync root registered when ACCESS_DENIED', async () => {
// Given
NodeWinRegisterSyncRootMock.mockResolvedValue(new RegisterSyncRootError('ACCESS_DENIED'));
// When
const connectionkey = await loadVirtualDrive(props);
// Then
expect(connectionkey).toBe(1n);
call(unregisterSyncRootMock).toStrictEqual({ providerId: 'oldSyncRootId' });
call(AddonRegisterSyncRootMock).toMatchObject({ providerId: 'syncRootId' });
calls(loggerMock.error).toHaveLength(0);
});

it('should register and connect if no error happens', async () => {
// Given
NodeWinRegisterSyncRootMock.mockResolvedValue(undefined);
// When
const connectionkey = await loadVirtualDrive(props);
// Then
expect(connectionkey).toBe(1n);
calls(unregisterSyncRootMock).toHaveLength(0);
calls(AddonRegisterSyncRootMock).toHaveLength(0);
calls(loggerMock.error).toHaveLength(0);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Addon } from '@/node-win/addon-wrapper';
import { addSyncIssue } from '../../issues';
import { VirtualDrive } from '@/node-win/virtual-drive';
import { SyncContext } from '@/apps/sync-engine/config';
import { NodeWin } from '@/infra/node-win/node-win.module';

type Props = {
ctx: SyncContext;
};

export async function loadVirtualDrive({ ctx }: Props) {
try {
await VirtualDrive.createSyncRootFolder({ rootPath: ctx.rootPath });

const error = await NodeWin.registerSyncRoot({ ctx });
const info = await getSyncRootFromPath(ctx);

if (error) {
if (error.code !== 'ACCESS_DENIED') throw error;
if (!info) throw error;

await Addon.unregisterSyncRoot({ providerId: info.id });
await Addon.registerSyncRoot({ rootPath: ctx.rootPath, providerId: ctx.providerId, providerName: ctx.providerName });
}

const connectionKey = Addon.connectSyncRoot({ ctx });
ctx.logger.debug({ msg: 'Connection key', connectionKey });
return connectionKey;
} catch (error) {
addSyncIssue({ error: 'CANNOT_REGISTER_VIRTUAL_DRIVE', name: ctx.rootPath });
ctx.logger.error({ msg: 'Error loading virtual drive', error });
return;
}
}

async function getSyncRootFromPath(ctx: SyncContext) {
try {
const info = await Addon.getSyncRootFromPath({ path: ctx.rootPath });
ctx.logger.debug({ msg: 'Sync root from path', info });
return info;
} catch (error) {
ctx.logger.error({ msg: 'Error getting sync root from path', error });
return;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,14 @@ import { call, calls, mockProps, partialSpyOn } from 'tests/vitest/utils.helper.
import { workers } from '@/apps/main/remote-sync/store';
import * as scheduleSync from './schedule-sync';
import { RecoverySyncModule } from '@/backend/features/sync/recovery-sync/recovery-sync.module';
import { Addon } from '@/node-win/addon-wrapper';
import * as addSyncIssue from '../../issues';
import * as refreshItemPlaceholders from '@/apps/sync-engine/refresh-item-placeholders';
import { VirtualDrive } from '@/node-win/virtual-drive';
import * as initWatcher from '@/node-win/watcher/watcher';
import * as addPendingItems from '@/apps/sync-engine/in/add-pending-items';
import * as loadVirtualDrive from './load-virtual-drive';
import { loggerMock } from '@/tests/vitest/mocks.helper.test';

describe('spawn-sync-engine-worker', () => {
const createSyncRootFolderMock = partialSpyOn(VirtualDrive, 'createSyncRootFolder');
const registerSyncRootMock = partialSpyOn(Addon, 'registerSyncRoot');
const connectSyncRootMock = partialSpyOn(Addon, 'connectSyncRoot');
const addSyncIssueMock = partialSpyOn(addSyncIssue, 'addSyncIssue');
const loadVirtualDriveMock = partialSpyOn(loadVirtualDrive, 'loadVirtualDrive');
const scheduleSyncMock = partialSpyOn(scheduleSync, 'scheduleSync');
const recoverySyncMock = partialSpyOn(RecoverySyncModule, 'recoverySync');
const refreshItemPlaceholdersMock = partialSpyOn(refreshItemPlaceholders, 'refreshItemPlaceholders');
Expand All @@ -28,25 +24,32 @@ describe('spawn-sync-engine-worker', () => {
workers.clear();
});

it('should add issue if register sync root fails', async () => {
it('should catch errors', async () => {
// Given
registerSyncRootMock.mockRejectedValue(new Error('message'));
loadVirtualDriveMock.mockRejectedValue(new Error());
// When
await spawnSyncEngineWorker(props);
// Then
call(addSyncIssueMock).toMatchObject({ error: 'CANNOT_REGISTER_VIRTUAL_DRIVE' });
call(loggerMock.error).toMatchObject({ msg: 'Error loading sync engine worker' });
});

it('should start sync engine process if register sync root success', async () => {
it('should skip if load virtual drive fails', async () => {
// Given
registerSyncRootMock.mockResolvedValue(undefined);
loadVirtualDriveMock.mockResolvedValue(undefined);
// When
await spawnSyncEngineWorker(props);
// Then
calls(addSyncIssueMock).toHaveLength(0);
calls(createSyncRootFolderMock).toHaveLength(1);
calls(registerSyncRootMock).toHaveLength(1);
calls(connectSyncRootMock).toHaveLength(1);
calls(loggerMock.error).toHaveLength(0);
calls(refreshItemPlaceholdersMock).toHaveLength(0);
});

it('should start sync engine process if load virtual drive success', async () => {
// Given
loadVirtualDriveMock.mockResolvedValue(1n);
// When
await spawnSyncEngineWorker(props);
// Then
calls(loggerMock.error).toHaveLength(0);
calls(refreshItemPlaceholdersMock).toHaveLength(1);
calls(scheduleSyncMock).toHaveLength(1);
calls(recoverySyncMock).toHaveLength(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ import { WorkerConfig, workers } from '@/apps/main/remote-sync/store';
import { scheduleSync } from './schedule-sync';
import { addRemoteSyncManager } from '@/apps/main/remote-sync/handlers';
import { RecoverySyncModule } from '@/backend/features/sync/recovery-sync/recovery-sync.module';
import { Addon } from '@/node-win/addon-wrapper';
import { addSyncIssue } from '../../issues';
import { refreshItemPlaceholders } from '@/apps/sync-engine/refresh-item-placeholders';
import { addPendingItems } from '@/apps/sync-engine/in/add-pending-items';
import { initWatcher } from '@/node-win/watcher/watcher';
import { VirtualDrive } from '@/node-win/virtual-drive';
import { refreshWorkspaceToken } from '@/apps/sync-engine/refresh-workspace-token';
import { loadVirtualDrive } from './load-virtual-drive';

type TProps = {
ctx: SyncContext;
Expand All @@ -18,18 +16,9 @@ type TProps = {
export async function spawnSyncEngineWorker({ ctx }: TProps) {
ctx.logger.debug({ msg: 'Spawn sync engine worker' });

let connectionKey: bigint;

try {
try {
await VirtualDrive.createSyncRootFolder({ rootPath: ctx.rootPath });
await Addon.registerSyncRoot({ rootPath: ctx.rootPath, providerId: ctx.providerId, providerName: ctx.providerName });
connectionKey = Addon.connectSyncRoot({ ctx });
ctx.logger.debug({ msg: 'Connection key', connectionKey });
} catch (error) {
addSyncIssue({ error: 'CANNOT_REGISTER_VIRTUAL_DRIVE', name: ctx.rootPath });
throw error;
}
const connectionKey = await loadVirtualDrive({ ctx });
if (!connectionKey) return;

/**
* Jonathan Arce v2.5.1
Expand Down
4 changes: 2 additions & 2 deletions src/apps/renderer/hooks/backups/useBackupProgress.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ export function useBackupProgress() {
const [percentualProgress, setPercentualProgress] = useState<number>(0);

useEffect(() => {
const removeListener = window.electron.onBackupProgress(setBackupProgress);
const removeListener = globalThis.window.electron.onBackupProgress(setBackupProgress);

window.electron.getLastBackupProgress();
void globalThis.window.electron.getLastBackupProgress();

return removeListener;
}, []);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { abs } from '@/context/local/localFile/infrastructure/AbsolutePath';
import { NodeWin } from '@/infra/node-win/node-win.module';
import { FileUuid } from '@/apps/main/database/entities/DriveFile';
import * as createFile from './create-file';
import { GetFileInfoError } from '@/infra/node-win/services/item-identity/get-file-info';
import { GetFileInfoError } from '@/infra/node-win/services/get-file-info';
import { loggerMock } from '@/tests/vitest/mocks.helper.test';

describe('create-pending-files', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { abs } from '@/context/local/localFile/infrastructure/AbsolutePath';
import { NodeWin } from '@/infra/node-win/node-win.module';
import { FolderUuid } from '@/apps/main/database/entities/DriveFolder';
import * as createFolder from './create-folder';
import { GetFolderInfoError } from '@/infra/node-win/services/item-identity/get-folder-info';
import { GetFolderInfoError } from '@/infra/node-win/services/get-folder-info';
import { loggerMock } from '@/tests/vitest/mocks.helper.test';
import * as createPendingItems from './create-pending-items';

Expand Down
6 changes: 4 additions & 2 deletions src/infra/node-win/node-win.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { getFileInfo } from './services/item-identity/get-file-info';
import { getFolderInfo } from './services/item-identity/get-folder-info';
import { getFileInfo } from './services/get-file-info';
import { getFolderInfo } from './services/get-folder-info';
import { registerSyncRoot } from './services/register-sync-root';

export const NodeWin = {
registerSyncRoot,
getFileInfo,
getFolderInfo,
};
Loading
Loading