Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release v2.2.1 #522

Merged
merged 5 commits into from
Nov 5, 2024
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
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.2.0",
"version": "2.2.1",
"author": "Internxt <[email protected]>",
"description": "Internxt Drive client UI",
"license": "AGPL-3.0",
Expand Down
2 changes: 1 addition & 1 deletion release/app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "internxt-drive",
"version": "2.2.0",
"version": "2.2.1",
"description": "Internxt Drive client UI",
"main": "./dist/main/main.js",
"author": "Internxt <[email protected]>",
Expand Down
26 changes: 13 additions & 13 deletions src/apps/backups/Backups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,11 @@
info: BackupInfo,
abortController: AbortController
): Promise<DriveDesktopError | undefined> {
Logger.info('[BACKUPS] Backing:', info);

const localTreeEither = await this.localTreeBuilder.run(
info.pathname as AbsolutePath
);

if (localTreeEither.isLeft()) {
Logger.error('[BACKUPS] local tree is left', localTreeEither);
return localTreeEither.getLeft();
}

Expand Down Expand Up @@ -175,17 +172,20 @@
const batches = AddedFilesBatchCreator.run(added);

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

this.backed += batch.length;

Logger.debug('[Backed]', this.backed);
Expand Down Expand Up @@ -290,7 +290,7 @@
continue;
}

const folder = await this.simpleFolderCreator.run(

Check warning on line 293 in src/apps/backups/Backups.ts

View workflow job for this annotation

GitHub Actions / 🧪 Lint and test

Unexpected `await` inside a loop
relativePath,
parent.id
);
Expand Down
2 changes: 1 addition & 1 deletion src/apps/backups/batches/GroupFilesBySize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { LocalFile } from '../../../context/local/localFile/domain/LocalFile';

export class GroupFilesBySize {
static small(files: Array<LocalFile>) {
return files.filter((file) => file.isSmall());
return files.filter((file) => file.isSmall() && file);
}

static medium(files: Array<LocalFile>) {
Expand Down
4 changes: 2 additions & 2 deletions src/apps/backups/diff/DiffFilesCalculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { AbsolutePath } from '../../../context/local/localFile/infrastructure/Ab
import { LocalTree } from '../../../context/local/localTree/domain/LocalTree';
import { File } from '../../../context/virtual-drive/files/domain/File';
import { RemoteTree } from '../../../context/virtual-drive/remoteTree/domain/RemoteTree';
import { relative } from '../utils/relative';
import { relativeV2 } from '../utils/relative';
import Logger from 'electron-log';

export type FilesDiff = {
Expand All @@ -24,7 +24,7 @@ export class DiffFilesCalculator {
const rootPath = local.root.path;

local.files.forEach((local) => {
const remotePath = relative(rootPath, local.path);
const remotePath = relativeV2(rootPath, local.path);

const remoteExists = remote.has(remotePath);

Expand Down
1 change: 0 additions & 1 deletion src/apps/main/remote-sync/RemoteSyncManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,6 @@ export class RemoteSyncManager {
}

private addLastSyncingFinishedTimestamp() {
if (this.status !== 'SYNCING') return;
Logger.info('Adding last syncing finished timestamp');
this.lastSyncingFinishedTimestamp = new Date();
}
Expand Down
21 changes: 5 additions & 16 deletions src/apps/main/remote-sync/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,20 +198,8 @@ ipcMain.handle('START_REMOTE_SYNC', async () => {
setIsProcessing(false);
});

ipcMain.handle('FORCE_REFRESH_BACKUPS', async () => {
Logger.info('Received start remote sync event');
const deviceUuid = configStore.get('deviceUuid');
const backupsFolder: RemoteSyncedFolder[] =
await remoteSyncManager.getFolderChildren(deviceUuid);
setIsProcessing(true);
await Promise.all(
backupsFolder.map(async (folder) => {
if (!folder.id) return;
await sleep(200);
await startRemoteSync(folder.id);
})
);
setIsProcessing(false);
ipcMain.handle('FORCE_REFRESH_BACKUPS', async (_, folderId: number) => {
await startRemoteSync(folderId);
});

remoteSyncManager.onStatusChange((newStatus) => {
Expand Down Expand Up @@ -247,7 +235,8 @@ export async function updateRemoteSync(): Promise<void> {
Logger.info('Last files sync at', lastFilesSyncAt);
const folderId = lastFilesSyncAt ? undefined : userData?.root_folder_id;
await startRemoteSync(folderId);
const isSyncing = await checkSyncEngineInProcess(2_000);
const isSyncing = await checkSyncEngineInProcess(5000);
Logger.info('Is syncing', isSyncing);
if (isSyncing) {
Logger.info('Remote sync is already running');
return;
Expand All @@ -261,7 +250,7 @@ export async function fallbackRemoteSync(): Promise<void> {

ipcMain.handle('SYNC_MANUALLY', async () => {
Logger.info('[Manual Sync] Received manual sync event');
const isSyncing = await checkSyncEngineInProcess(5_000);
const isSyncing = await checkSyncEngineInProcess(5000);
if (isSyncing) return;
await updateRemoteSync();
await fallbackRemoteSync();
Expand Down
6 changes: 4 additions & 2 deletions src/apps/renderer/localize/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,8 @@
"file-does-not-exist": "File doesn't exist",
"file-too-big": "Max upload size is 20GB. Please try smaller files.",
"file-non-extension": "Files without extensions are not supported.",
"duplicated-node": "It appears that there are duplicate file or folder names in this directory. Please rename one of them to ensure synchronization"
"duplicated-node": "It appears that there are duplicate file or folder names in this directory. Please rename one of them to ensure synchronization",
"not-enough-space": "You have not enough space to complete the operation"
},
"error-messages": {
"no-internet": "Looks like you are not connected to the internet, we'll try again later",
Expand All @@ -379,7 +380,8 @@
"file-does-not-exist": "This file was present when we compared your local folder with your Internxt drive but disappeared when we tried to access it. If you deleted this file, don't worry, this error should dissapear the next time the sync process starts.",
"file-too-big": "Max upload size is 20GB. Please try smaller files.",
"file-non-extension": "Files without extensions are not supported. Not synchronized.",
"duplicated-node": "There are two elements (file or folder) with the same name on a folder. Rename one of them to sync them both"
"duplicated-node": "There are two elements (file or folder) with the same name on a folder. Rename one of them to sync them both",
"not-enough-space": "You have not enough space to complete the operation"
},
"report-modal": {
"actions": {
Expand Down
6 changes: 4 additions & 2 deletions src/apps/renderer/localize/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,8 @@
"file-does-not-exist": "El archivo no existe",
"file-too-big": "El tamaño máximo de carga es de 20GB. Por favor, intenta con archivos más pequeños.",
"file-non-extension": "Archivos sin extensión no son soportados",
"duplicated-node": "Hay un conflicto con el elemento"
"duplicated-node": "Hay un conflicto con el elemento",
"not-enough-space": "No tienes suficiente espacio para completar la operación."
},
"error-messages": {
"no-internet": "No estás conectado a Internet, lo intentaremos más tarde",
Expand All @@ -378,7 +379,8 @@
"file-does-not-exist": "Este archivo estaba presente cuando comparamos su carpeta local con su unidad Internxt, pero desapareció cuando intentamos acceder a él. Si has eliminado este archivo, no te preocupes, este error debería desaparecer la próxima vez que se inicie el proceso de sincronización",
"file-too-big": "El tamaño máximo de carga es de 20GB. Por favor, intenta con archivos más pequeños.",
"file-non-extension": "Los archivos sin extensiones no son soportados. No sincronizado",
"duplicated-node": "Hay dos elementos (archivo o carpeta) con el mismo nombre en una carpeta. Cambia el nombre de uno de ellos para sincronizar ambos."
"duplicated-node": "Hay dos elementos (archivo o carpeta) con el mismo nombre en una carpeta. Cambia el nombre de uno de ellos para sincronizar ambos.",
"not-enough-space": "No tienes suficiente espacio para completar la operación."
},
"report-modal": {
"actions": {
Expand Down
6 changes: 4 additions & 2 deletions src/apps/renderer/localize/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,8 @@
"no-permission": "Permissions insuffisantes",
"file-does-not-exist": "Le fichier n'existe pas",
"file-too-big": "La taille maximale de téléchargement est de 20 GB. Veuillez essayer des fichiers plus petits.",
"duplicated-node": "Il y a un conflit avec l'élément."
"duplicated-node": "Il y a un conflit avec l'élément.",
"not-enough-space": "Vous n'avez pas assez d'espace pour compléter l'opération."
},
"error-messages": {
"no-internet": "Il semble que vous ne soyez pas connecté à l'internet, nous réessayerons plus tard",
Expand All @@ -373,7 +374,8 @@
"file-does-not-exist": "Ce fichier était présent lorsque nous avons comparé votre dossier local avec votre disque interne, mais il a disparu lorsque nous avons essayé d'y accéder. Si vous avez supprimé ce fichier, ne vous inquiétez pas, cette erreur devrait disparaître au prochain démarrage du processus de synchronisation.",
"file-too-big": "La taille maximale de téléchargement est de 20 GB. Veuillez essayer des fichiers plus petits.",
"file-non-extension": "Les archives sans extensions ne sont pas supportées. Non synchronisées",
"duplicated-node": "Il y a deux éléments (fichier ou dossier) avec le même nom dans un dossier. Renommez l'un d'eux pour les synchroniser tous les deux."
"duplicated-node": "Il y a deux éléments (fichier ou dossier) avec le même nom dans un dossier. Renommez l'un d'eux pour les synchroniser tous les deux.",
"not-enough-space": "Vous n'avez pas assez d'espace pour compléter l'opération."
},
"report-modal": {
"actions": {
Expand Down
2 changes: 1 addition & 1 deletion src/apps/shared/IPC/events/sync-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export type SyncEngineInvocableFunctions = {
folders: DriveFolder[];
}>;
START_REMOTE_SYNC: () => Promise<void>;
FORCE_REFRESH_BACKUPS: () => Promise<void>;
FORCE_REFRESH_BACKUPS: (folderId: number) => Promise<void>;
};

// TODO: change how errors are reported to the ui
Expand Down
11 changes: 10 additions & 1 deletion src/apps/sync-engine/BindingManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export class BindingsManager {

private queueManager: QueueManager | null = null;
private lastHydrated = '';
private lastMoved = '';

constructor(
private readonly container: DependencyContainer,
Expand Down Expand Up @@ -108,11 +109,18 @@ export class BindingsManager {
try {
Logger.debug('Path received from rename callback', absolutePath);

if (this.lastMoved === absolutePath) {
Logger.debug('Same file moved');
this.lastMoved = '';
callback(true);
return;
}

const isTempFile = await isTemporaryFile(absolutePath);

Logger.debug('[isTemporaryFile]', isTempFile);

if (isTempFile) {
if (isTempFile && !contentsId.startsWith('FOLDER')) {
Logger.debug('File is temporary, skipping');
callback(true);
return;
Expand All @@ -128,6 +136,7 @@ export class BindingsManager {
});
fn(absolutePath, contentsId, callback);
Logger.debug('Finish Rename', absolutePath);
this.lastMoved = absolutePath;
} catch (error) {
Logger.error('Error during rename or move operation', error);
}
Expand Down
86 changes: 66 additions & 20 deletions src/apps/sync-engine/dependency-injection/common/QueueManager.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
/* eslint-disable no-await-in-loop */
import {
HandleAction,
IQueueManager,
QueueItem,
HandleActions,
typeQueue,
} from 'virtual-drive/dist';
import Logger from 'electron-log';
import fs from 'fs';
import _ from 'lodash';

export type QueueHandler = {
handleAdd: HandleAction;
Expand Down Expand Up @@ -37,8 +40,10 @@ export class QueueManager implements IQueueManager {
changeSize: false,
};

private readonly notify: QueueManagerCallback;
private enqueueTimeout: NodeJS.Timeout | null = null;
private enqueueDelay = 2000;

private readonly notify: QueueManagerCallback;
private readonly persistPath: string;

actions: HandleActions;
Expand Down Expand Up @@ -96,6 +101,7 @@ export class QueueManager implements IQueueManager {
this.queues = JSON.parse(data);
}
}

public clearQueue(): void {
this.queues = {
add: [],
Expand All @@ -116,15 +122,26 @@ export class QueueManager implements IQueueManager {
Logger.debug('Task already exists in queue. Skipping.');
return;
}

this.queues[task.type].push(task);
this.sortQueue(task.type);
this.saveQueueStateToFile();
if (!this.isProcessing[task.type]) {
this.processQueue(task.type);
this.resetEnqueueTimeout();
}

private resetEnqueueTimeout(): void {
if (this.enqueueTimeout) {
clearTimeout(this.enqueueTimeout);
}

// Inicia el temporizador de espera
this.enqueueTimeout = setTimeout(() => {
Logger.debug('Processing all tasks');
this.processAll();
}, this.enqueueDelay);
}

private sortQueue(type: string): void {
private sortQueue(type: typeQueue): void {
this.queues[type].sort((a, b) => {
if (a.isFolder && b.isFolder) {
return 0;
Expand All @@ -139,32 +156,61 @@ export class QueueManager implements IQueueManager {
});
}

private async processQueue(type: string): Promise<void> {
if (this.isProcessing[type]) {
return;
}
private async processQueue(type: typeQueue): Promise<void> {
if (this.isProcessing[type]) return;

this.isProcessing[type] = true;
const start = Date.now();
Logger.debug(`[TIME] Processing ${type} tasks started at ${start}`);

if (type === typeQueue.add) {
await this.processInChunks(type, 5);
} else {
await this.processSequentially(type);
}

this.isProcessing[type] = false;
const end = Date.now();
Logger.debug(`[TIME] Processing ${type} tasks ended at ${end}`);
Logger.debug(`[TIME] Processing ${type} tasks took ${end - start}ms`);
}

private async processInChunks(
type: typeQueue,
chunkSize: number
): Promise<void> {
const chunks = _.chunk(this.queues[type], chunkSize);

for (const chunk of chunks) {
await Promise.all(chunk.map((task) => this.processTask(type, task)));
this.queues[type] = this.queues[type].slice(chunk.length);
}
}

private async processSequentially(type: typeQueue): Promise<void> {
while (this.queues[type].length > 0) {
const task = this.queues[type].shift();
this.saveQueueStateToFile();
if (task) {
Logger.debug(`Processing ${type} task: ${JSON.stringify(task)}`);
Logger.debug(`Tasks length: ${this.queues[type].length}`);
try {
await this.actions[task.type](task);
} catch (error) {
Logger.error(`Failed to process ${type} task:`, task, error);
}
}

if (task) await this.processTask(type, task);
}
}

private async processTask(type: typeQueue, task: QueueItem): Promise<void> {
Logger.debug(`Processing ${type} task: ${JSON.stringify(task)}`);
try {
await this.actions[task.type](task);
} catch (error) {
Logger.error(`Failed to process ${type} task:`, task, error);
}
this.isProcessing[type] = false;
}

public async processAll(): Promise<void> {
const taskTypes = Object.keys(this.queues);
const taskTypes = Object.keys(this.queues) as typeQueue[];
await this.notify.onTaskProcessing();
await Promise.all(taskTypes.map((type) => this.processQueue(type)));
await Promise.all(
taskTypes.map((type: typeQueue) => this.processQueue(type))
);
await this.notify.onTaskSuccess();
}
}
Loading
Loading