Skip to content

Commit

Permalink
[PB-1029] fix: folder creation with name (internxt#387)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoanVicens authored Oct 5, 2023
1 parent 924e208 commit a185843
Show file tree
Hide file tree
Showing 75 changed files with 1,330 additions and 333 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@
}
},
"jest": {
"setupFilesAfterEnv": [
"jest-extended/all"
],
"globals": {
"ts-jest": {
"tsconfig": "tsconfig.test.json"
Expand Down
43 changes: 0 additions & 43 deletions src/test/main/thumbnails/extract-pdf-page.test.ts

This file was deleted.

20 changes: 12 additions & 8 deletions src/workers/sync-engine/BindingManager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import Logger from 'electron-log';
import { DependencyContainer } from './dependency-injection/DependencyContainer';
import { buildControllers } from './callbacks-controllers/buildControllers';
import { executeControllerWithFallback } from './callbacks-controllers/middlewares/executeControllerWithFallback';
import { FilePlaceholderId } from './modules/placeholders/domain/FilePlaceholderId';

export class BindingsManager {
private static readonly PROVIDER_NAME = 'Internxt';
Expand All @@ -26,11 +28,9 @@ export class BindingsManager {
controllers.delete
.execute(contentsId)
.then(() => {
Logger.debug('DELETE RESPONSE SUCCESSFUL');
callback(true);
})
.catch((error: Error) => {
Logger.debug('DELETE RESPONSE NOT SUCCESSFUL');
Logger.error(error);
callback(false);
});
Expand All @@ -43,11 +43,15 @@ export class BindingsManager {
contentsId: string,
callback: (response: boolean) => void
) => {
controllers.renameOrMoveFile.execute(
absolutePath,
contentsId,
callback
);
const fn = executeControllerWithFallback({
handler: controllers.renameOrMove.execute.bind(
controllers.renameOrMove
),
fallback: controllers.offline.renameOrMove.execute.bind(
controllers.offline.renameOrMove
),
});
fn(absolutePath, contentsId, callback);
},
notifyFileAddedCallback: (
absolutePath: string,
Expand All @@ -56,7 +60,7 @@ export class BindingsManager {
controllers.addFile.execute(absolutePath, callback);
},
fetchDataCallback: (
contentsId: string,
contentsId: FilePlaceholderId,
callback: (success: boolean, path: string) => void
) => {
controllers.downloadFile
Expand Down
19 changes: 15 additions & 4 deletions src/workers/sync-engine/callbacks-controllers/buildControllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@ import { AddController } from './controllers/AddController';
import { DeleteController } from './controllers/DeleteController';
import { DownloadFileController } from './controllers/DownloadFileController';
import { RenameOrMoveController } from './controllers/RenameOrMoveController';
import { OfflineRenameOrMoveController } from './controllers/offline/OfflineRenameOrMoveController';

export function buildControllers(container: DependencyContainer) {
const addFileController = new AddController(
container.absolutePathToRelativeConverter,
container.fileCreationOrchestrator,
container.folderCreator
container.folderCreator,
container.offline.folderCreator
);

const deleteController = new DeleteController(
container.fileDeleter,
container.folderDeleter
);

const renameOrMoveFileController = new RenameOrMoveController(
container.filePathFromAbsolutePathCreator,
const renameOrMoveController = new RenameOrMoveController(
container.absolutePathToRelativeConverter,
container.filePathUpdater,
container.folderPathUpdater,
deleteController
Expand All @@ -28,10 +31,18 @@ export function buildControllers(container: DependencyContainer) {
container.localRepositoryRefresher
);

const offlineRenameOrMoveController = new OfflineRenameOrMoveController(
container.absolutePathToRelativeConverter,
container.offline.folderPathUpdater
);

return {
addFile: addFileController,
renameOrMoveFile: renameOrMoveFileController,
renameOrMove: renameOrMoveController,
delete: deleteController,
downloadFile: downloadFileController,
offline: {
renameOrMove: offlineRenameOrMoveController,
},
} as const;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,36 @@ import Logger from 'electron-log';
import { CallbackController } from './CallbackController';
import { rawPathIsFolder } from '../helpers/rawPathIsFolder';
import { FolderCreator } from '../../modules/folders/application/FolderCreator';
import { MapObserver } from 'workers/sync-engine/modules/shared/domain/MapObserver';
import { FileCreationOrchestrator } from 'workers/sync-engine/modules/boundaryBridge/application/FileCreationOrchestrator';
import { MapObserver } from '../../modules/shared/domain/MapObserver';
import { FileCreationOrchestrator } from '../../modules/boundaryBridge/application/FileCreationOrchestrator';
import { OfflineFolderCreator } from '../../modules/folders/application/Offline/OfflineFolderCreator';
import { OfflineFolder } from '../../modules/folders/domain/OfflineFolder';
import { createFilePlaceholderId } from '../../modules/placeholders/domain/FilePlaceholderId';
import { createFolderPlaceholderId } from '../../modules/placeholders/domain/FolderPlaceholderId';
import { PlatformPathConverter } from '../../modules/shared/application/PlatformPathConverter';
import { AbsolutePathToRelativeConverter } from '../../modules/shared/application/AbsolutePathToRelativeConverter';

type Queue = Map<string, (acknowledge: boolean, id: string) => void>;
type FileCreationQueue = Map<
string,
(acknowledge: boolean, id: string) => void
>;
type FolderCreationQueue = Map<
OfflineFolder,
(acknowledge: boolean, id: string) => void
>;
type CreationCallback = (acknowledge: boolean, id: string) => void;

export class AddController extends CallbackController {
private readonly filesQueue: Queue;
private readonly foldersQueue: Queue;
private readonly filesQueue: FileCreationQueue;
private readonly foldersQueue: FolderCreationQueue;

private readonly observer: MapObserver;

constructor(
private readonly absolutePathToRelativeConverter: AbsolutePathToRelativeConverter,
private readonly fileCreationOrchestrator: FileCreationOrchestrator,
private readonly folderCreator: FolderCreator
private readonly folderCreator: FolderCreator,
private readonly offlineFolderCreator: OfflineFolderCreator
) {
super();

Expand All @@ -27,62 +43,93 @@ export class AddController extends CallbackController {
}

private createFile = async (
absolutePath: string,
posixRelativePath: string,
callback: (acknowledge: boolean, id: string) => void
) => {
try {
const contentsId = await this.fileCreationOrchestrator.run(absolutePath);
return callback(true, contentsId);
const contentsId = await this.fileCreationOrchestrator.run(
posixRelativePath
);
return callback(true, createFilePlaceholderId(contentsId));
} catch (error: unknown) {
Logger.error('Error when adding a file: ', error);
callback(false, '');
} finally {
this.filesQueue.delete(absolutePath);
this.filesQueue.delete(posixRelativePath);
}
};

private createFiles = async () => {
for (const [absolutePath, callback] of this.filesQueue) {
await this.createFile(absolutePath, callback);
for (const [posixRelativePath, callback] of this.filesQueue) {
await this.createFile(posixRelativePath, callback);
}
};

private createFolders = async () => {
for (const [absolutePath, callback] of this.foldersQueue) {
await this.createFolder(absolutePath, callback);
Logger.debug('FOLDERS TO CREATE', this.foldersQueue.size);
for (const [offlineFolder, callback] of this.foldersQueue) {
await this.createFolder(offlineFolder, callback);
}
};

private createFolder = async (
absolutePath: string,
offlineFolder: OfflineFolder,
callback: (acknowledge: boolean, id: string) => void
) => {
Logger.info('Creating folder', absolutePath);
Logger.info('Creating folder', offlineFolder);
try {
const folder = await this.folderCreator.run(absolutePath);
callback(true, folder.uuid);
await this.folderCreator.run(offlineFolder);
} catch (error: unknown) {
Logger.error('Error creating a folder: ', error);
callback(false, '');
} finally {
this.foldersQueue.delete(absolutePath);
this.foldersQueue.delete(offlineFolder);
}
};

private enqueueFolder = (
posixRelativePath: string,
callback: CreationCallback
) => {
try {
const offlineFolder = this.offlineFolderCreator.run(posixRelativePath);
callback(true, createFolderPlaceholderId(offlineFolder.uuid));
this.foldersQueue.set(offlineFolder, () => {
//no-op
});
} catch (error: unknown) {
Logger.error('Error on folder creation: ', error);
callback(false, '');
}
};

async execute(
absolutePath: string,
callback: (acknowledge: boolean, id: string) => void
callback: CreationCallback
): Promise<void> {
const win32RelativePath =
this.absolutePathToRelativeConverter.run(absolutePath);

const posixRelativePath =
PlatformPathConverter.winToPosix(win32RelativePath);

if (rawPathIsFolder(absolutePath)) {
this.foldersQueue.set(absolutePath, callback);
this.enqueueFolder(posixRelativePath, callback);
await this.createFolders();
await this.createFiles();
return;
}

Logger.debug('File is going to be queued: ', absolutePath);
this.filesQueue.set(absolutePath, callback);
this.filesQueue.set(posixRelativePath, callback);

if (this.foldersQueue.size === 0) {
this.createFiles();
Logger.debug(
'File is not going to be queued. Creating...',
posixRelativePath
);
await this.createFiles();
} else {
Logger.debug('File has been queued: ', posixRelativePath);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
import {
FilePlaceholderId,
isFilePlaceholderId,
} from '../../modules/placeholders/domain/FilePlaceholderId';
import {
FolderPlaceholderId,
isFolderPlaceholderId,
} from '../../modules/placeholders/domain/FolderPlaceholderId';

export abstract class CallbackController {
protected trim(id: string): string {
return id.replace(
Expand All @@ -6,12 +15,20 @@ export abstract class CallbackController {
''
);
}
protected isContentsId(id: string): boolean {

protected isFilePlaceholder(id: string): id is FilePlaceholderId {
// make sure the id is trimmed before comparing
// if it was already trimmed should not change its length
const trimmed = this.trim(id);

return isFilePlaceholderId(trimmed);
}

protected isFolderPlaceholder(id: string): id is FolderPlaceholderId {
// make sure the id is trimmed before comparing
// if it was already trimmed should not change its length
const trimmed = this.trim(id);

// TODO: need a better way to detect if its a file or a folder
return trimmed.length === 24;
return isFolderPlaceholderId(trimmed);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,18 @@ export class DeleteController extends CallbackController {
async execute(contentsId: string) {
const trimmedId = this.trim(contentsId);

if (this.isContentsId(trimmedId)) {
this.filesQueue.push(trimmedId);
if (this.isFilePlaceholder(trimmedId)) {
const [_, contentsId] = trimmedId.split(':');
this.filesQueue.push(contentsId);
return;
}

this.foldersQueue.push(trimmedId);
if (this.isFolderPlaceholder(trimmedId)) {
const [_, folderUuid] = trimmedId.split(':');
this.foldersQueue.push(folderUuid);
return;
}

throw new Error(`Placeholder Id not identified: ${trimmedId}`);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { FilePlaceholderId } from 'workers/sync-engine/modules/placeholders/domain/FilePlaceholderId';
import { ContentsDownloader } from '../../modules/contents/application/ContentsDownloader';
import { FileFinderByContentsId } from '../../modules/files/application/FileFinderByContentsId';
import { LocalRepositoryRepositoryRefresher } from '../../modules/files/application/LocalRepositoryRepositoryRefresher';
import { CallbackController } from './CallbackController';
import Logger from 'electron-log';

export class DownloadFileController extends CallbackController {
constructor(
Expand All @@ -18,12 +20,17 @@ export class DownloadFileController extends CallbackController {
return await this.downloader.run(file);
}

async execute(contentsId: string): Promise<string> {
async execute(contentsId: FilePlaceholderId): Promise<string> {
const trimmedId = this.trim(contentsId);

try {
return await this.action(trimmedId);
} catch {
const [_, contentsId] = trimmedId.split(':');
return await this.action(contentsId);
} catch (error: unknown) {
Logger.error(
'Error downloading a file, going to refresh and retry: ',
error
);
await this.localRepositoryRefresher.run();

return await new Promise((resolve, reject) => {
Expand Down
Loading

0 comments on commit a185843

Please sign in to comment.