Skip to content

Commit

Permalink
[PB-1918] feat: allow to edit files append content (#475)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoanVicens authored Mar 25, 2024
1 parent b43a5b6 commit f9f753a
Show file tree
Hide file tree
Showing 62 changed files with 783 additions and 222 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@
"node": ">=18.0.0 <19.0.0",
"npm": ">=7.x"
},
"engines": {
"engines": {
"node": ">=18.0.0 <19.0.0"
},
"browserslist": [],
Expand Down
45 changes: 25 additions & 20 deletions src/apps/fuse/FuseApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { WriteCallback } from './callbacks/WriteCallback';
import { ReleaseCallback } from './callbacks/ReleaseCallback';
import { FuseDependencyContainer } from './dependency-injection/FuseDependencyContainer';
import { ensureFolderExists } from './../shared/fs/ensure-folder-exists';
import { mountPromise, unmountFusedDirectory, unmountPromise } from './helpers';

// eslint-disable-next-line @typescript-eslint/no-var-requires
const fuse = require('@gcas/fuse');
Expand Down Expand Up @@ -42,7 +43,8 @@ export class FuseApp {
this.fuseContainer.offlineDriveContainer
);
const renameOrMove = new RenameOrMoveCallback(
this.fuseContainer.virtualDriveContainer
this.fuseContainer.virtualDriveContainer,
this.fuseContainer.offlineDriveContainer
);
const create = new CreateCallback(this.fuseContainer.offlineDriveContainer);
const makeDirectory = new MakeDirectoryCallback(
Expand Down Expand Up @@ -85,39 +87,42 @@ export class FuseApp {
maxRead: FuseApp.MAX_INT_32,
});

this._fuse.mount((err: any) => {
if (err) {
try {
await mountPromise(this._fuse);
} catch {
try {
await unmountFusedDirectory(this.paths.root);
await mountPromise(this._fuse);
} catch (err) {
Logger.error(`[FUSE] mount error: ${err}`);
}
});
}
}

async stop(): Promise<void> {
this._fuse?.unmount((err: any) => {
if (err) {
Logger.error(`[FUSE] unmount error: ${err}`);
}
});
await unmountPromise(this._fuse);
}

async clearCache(): Promise<void> {
await this.fuseContainer.virtualDriveContainer.allLocalContentsDeleter.run();
}

async update(): Promise<void> {
Logger.info('[FUSE] Updating tree');
try {
const tree =
await this.fuseContainer.virtualDriveContainer.existingNodesTreeBuilder.run();

const tree =
await this.fuseContainer.virtualDriveContainer.existingNodesTreeBuilder.run();
await this.fuseContainer.virtualDriveContainer.repositoryPopulator.run(
tree.files
);

await this.fuseContainer.virtualDriveContainer.repositoryPopulator.run(
tree.files
);
await this.fuseContainer.virtualDriveContainer.folderRepositoryInitiator.run(
tree.folders
);

await this.fuseContainer.virtualDriveContainer.folderRepositoryInitiator.run(
tree.folders
);

Logger.info('[FUSE] Tree updated successfully');
Logger.info('[FUSE] Tree updated successfully');
} catch (err) {
Logger.error('[FUSE] Updating the tree ', err);
}
}
}
4 changes: 4 additions & 0 deletions src/apps/fuse/callbacks/FuseCallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ export abstract class NotifyFuseCallback extends FuseCallback<undefined> {
if (result.isLeft()) {
const error = result.getLeft();

if (this.debug.output) {
Logger.debug(`${this.name} ${error}`);
}

return callback(error.code);
}

Expand Down
23 changes: 20 additions & 3 deletions src/apps/fuse/callbacks/RenameOrMoveCallback.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import { OfflineDriveDependencyContainer } from '../dependency-injection/offline/OfflineDriveDependencyContainer';
import { VirtualDriveDependencyContainer } from '../dependency-injection/virtual-drive/VirtualDriveDependencyContainer';
import { NotifyFuseCallback } from './FuseCallback';
import { FuseNoSuchFileOrDirectoryError } from './FuseErrors';
import { RenameOrMoveFile } from './RenameOrMoveFile';
import { RenameOrMoveFolder } from './RenameOrMoveFolder';
import { UploadOnRename } from './UploadOnRename';

export class RenameOrMoveCallback extends NotifyFuseCallback {
private readonly updateFile: RenameOrMoveFile;
private readonly updateFolder: RenameOrMoveFolder;
private readonly uploadOnRename: UploadOnRename;

constructor(container: VirtualDriveDependencyContainer) {
constructor(
virtual: VirtualDriveDependencyContainer,
offline: OfflineDriveDependencyContainer
) {
super('Rename Or Move');

this.updateFile = new RenameOrMoveFile(container);
this.updateFolder = new RenameOrMoveFolder(container);
this.updateFile = new RenameOrMoveFile(virtual);
this.updateFolder = new RenameOrMoveFolder(virtual);
this.uploadOnRename = new UploadOnRename(offline, virtual);
}

async execute(src: string, dest: string) {
Expand All @@ -36,6 +43,16 @@ export class RenameOrMoveCallback extends NotifyFuseCallback {
return this.right();
}

const offlineUploadEither = await this.uploadOnRename.run(src, dest);

if (offlineUploadEither.isLeft()) {
return this.left(offlineUploadEither.getLeft());
}

if (offlineUploadEither.getRight() === 'success') {
return this.right();
}

return this.left(new FuseNoSuchFileOrDirectoryError(src));
}
}
39 changes: 39 additions & 0 deletions src/apps/fuse/callbacks/UploadOnRename.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { OfflineDriveDependencyContainer } from '../dependency-injection/offline/OfflineDriveDependencyContainer';
import { VirtualDriveDependencyContainer } from '../dependency-injection/virtual-drive/VirtualDriveDependencyContainer';
import { FileStatuses } from '../../../context/virtual-drive/files/domain/FileStatus';
import { Either, right } from '../../../context/shared/domain/Either';
import { FuseError } from './FuseErrors';

type Result = 'no-op' | 'success';

export class UploadOnRename {
private static readonly NO_OP: Result = 'no-op';
private static readonly SUCCESS: Result = 'success';
constructor(
private readonly offline: OfflineDriveDependencyContainer,
private readonly virtual: VirtualDriveDependencyContainer
) {}

async run(src: string, dest: string): Promise<Either<FuseError, Result>> {
const offlineFile = await this.offline.offlineFileSearcher.run({
path: src,
});

const virtualFile = await this.virtual.filesSearcher.run({
path: dest,
status: FileStatuses.EXISTS,
});

if (!offlineFile || !virtualFile) {
return right(UploadOnRename.NO_OP);
}

await this.offline.offlineContentsUploader.run(
offlineFile.id,
offlineFile.path,
virtualFile.contentsId
);

return right(UploadOnRename.SUCCESS);
}
}
5 changes: 4 additions & 1 deletion src/apps/fuse/callbacks/WriteCallback.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { OfflineDriveDependencyContainer } from '../dependency-injection/offline/OfflineDriveDependencyContainer';
import Logger from 'electron-log';

export class WriteCallback {
constructor(private readonly container: OfflineDriveDependencyContainer) {}
Expand All @@ -8,9 +9,11 @@ export class WriteCallback {
_fd: string,
buffer: Buffer,
len: number,
_pos: number,
pos: number,
cb: (a: number) => void
) {
Logger.debug('WRITE: ', path, len, pos);

await this.container.offlineContentsAppender.run(path, buffer);

return cb(len);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ export class VirtualDriveDependencyContainerFactory {
const contentsContainer = await buildContentsContainer(sharedContainer);
const filesContainer = await buildFilesContainer(
tree.files,
folderContainer,
sharedContainer
folderContainer
);

const container = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { FilePathUpdater } from '../../../../../context/virtual-drive/files/appl
import { FileCreator } from '../../../../../context/virtual-drive/files/application/FileCreator';
import { SameFileWasMoved } from '../../../../../context/virtual-drive/files/application/SameFileWasMoved';
import { FileDeleter } from '../../../../../context/virtual-drive/files/application/FileDeleter';
import { CreateFileOnOfflineFileUploaded } from '../../../../../context/virtual-drive/files/application/CreateFileOnOfflineFileUplodaded';
import { CreateFileOnOfflineFileUploaded } from '../../../../../context/virtual-drive/files/application/event-subsribers/CreateFileOnOfflineFileUplodaded';
import { FileRepositoryInitializer } from '../../../../../context/virtual-drive/files/application/FileRepositoryInitializer';
import { SyncFileMessenger } from '../../../../../context/virtual-drive/files/domain/SyncFileMessenger';
import { FilesSearcherByPartialMatch } from '../../../../../context/virtual-drive/files/application/search-all/FilesSearcherByPartialMatch';
Expand Down
20 changes: 12 additions & 8 deletions src/apps/fuse/dependency-injection/virtual-drive/files/builder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import crypt from '../../../../../context/shared/infrastructure/crypt';
import { CreateFileOnOfflineFileUploaded } from '../../../../../context/virtual-drive/files/application/CreateFileOnOfflineFileUplodaded';
import { CreateFileOnOfflineFileUploaded } from '../../../../../context/virtual-drive/files/application/event-subsribers/CreateFileOnOfflineFileUplodaded';
import { FileCreator } from '../../../../../context/virtual-drive/files/application/FileCreator';
import { FileDeleter } from '../../../../../context/virtual-drive/files/application/FileDeleter';
import { FilePathUpdater } from '../../../../../context/virtual-drive/files/application/FilePathUpdater';
Expand All @@ -17,16 +17,15 @@ import { DependencyInjectionEventRepository } from '../../common/eventRepository
import { DependencyInjectionStorageSdk } from '../../common/sdk';
import { DependencyInjectionUserProvider } from '../../common/user';
import { FoldersContainer } from '../folders/FoldersContainer';
import { SharedContainer } from '../shared/SharedContainer';
import { FilesContainer } from './FilesContainer';
import { InMemoryFileRepositorySingleton } from '../../../../shared/dependency-injection/virtual-drive/files/InMemoryFileRepositorySingleton';
import { SingleFileMatchingSearcher } from '../../../../../context/virtual-drive/files/application/SingleFileMatchingSearcher';
import { FilesSearcherByPartialMatch } from '../../../../../context/virtual-drive/files/application/search-all/FilesSearcherByPartialMatch';
import { FileOverrider } from '../../../../../context/virtual-drive/files/application/override/FileOverrider';

export async function buildFilesContainer(
initialFiles: Array<File>,
folderContainer: FoldersContainer,
sharedContainer: SharedContainer
folderContainer: FoldersContainer
): Promise<FilesContainer> {
const repository = InMemoryFileRepositorySingleton.instance;
const eventRepository = DependencyInjectionEventRepository.get();
Expand Down Expand Up @@ -54,9 +53,7 @@ export async function buildFilesContainer(
crypt,
user.bucket
);
const localFileSystem = new FuseLocalFileSystem(
sharedContainer.relativePathToAbsoluteConverter
);
const localFileSystem = new FuseLocalFileSystem();

const singleFileMatchingSearcher = new SingleFileMatchingSearcher(repository);

Expand Down Expand Up @@ -92,8 +89,15 @@ export async function buildFilesContainer(
syncFileMessenger
);

const fileOverrider = new FileOverrider(
remoteFileSystem,
repository,
eventBus
);

const createFileOnOfflineFileUploaded = new CreateFileOnOfflineFileUploaded(
fileCreator
fileCreator,
fileOverrider
);

const filesSearcherByPartialMatch = new FilesSearcherByPartialMatch(
Expand Down
46 changes: 46 additions & 0 deletions src/apps/fuse/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { exec } from 'child_process';
import Fuse from 'fuse-native';

export function unmountFusedDirectory(mountPoint: string): Promise<string> {
return new Promise((resolve, reject) => {
exec(`umount ${mountPoint}`, (error, stdout: string, stderr: string) => {
if (error) {
reject(error);
return;
}
if (stderr) {
// If there's anything in stderr, it usually indicates an error
reject(new Error(stderr));
return;
}

resolve(stdout);
});
});
}

export function mountPromise(fuse: Fuse): Promise<void> {
return new Promise((resolve, reject) => {
fuse.mount((err: unknown) => {
if (err) {
reject(err);
return;
}

resolve();
});
});
}

export function unmountPromise(fuse: Fuse): Promise<void> {
return new Promise((resolve, reject) => {
fuse.unmount((err: unknown) => {
if (err) {
reject(err);
return;
}

resolve();
});
});
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CreateFilePlaceholderOnDeletionFailed } from '../../../../context/virtual-drive/files/application/CreateFilePlaceholderOnDeletionFailed';
import { CreateFilePlaceholderOnDeletionFailed } from '../../../../context/virtual-drive/files/application/event-subsribers/CreateFilePlaceholderOnDeletionFailed';
import { FileCreator } from '../../../../context/virtual-drive/files/application/FileCreator';
import { FileDeleter } from '../../../../context/virtual-drive/files/application/FileDeleter';
import { FilePathUpdater } from '../../../../context/virtual-drive/files/application/FilePathUpdater';
Expand Down
2 changes: 1 addition & 1 deletion src/apps/sync-engine/dependency-injection/files/builder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import crypt from '../../../../context/shared/infrastructure/crypt';
import { CreateFilePlaceholderOnDeletionFailed } from '../../../../context/virtual-drive/files/application/CreateFilePlaceholderOnDeletionFailed';
import { CreateFilePlaceholderOnDeletionFailed } from '../../../../context/virtual-drive/files/application/event-subsribers/CreateFilePlaceholderOnDeletionFailed';
import { FileCreator } from '../../../../context/virtual-drive/files/application/FileCreator';
import { FileDeleter } from '../../../../context/virtual-drive/files/application/FileDeleter';
import { FilePathUpdater } from '../../../../context/virtual-drive/files/application/FilePathUpdater';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ export class OfflineContentsUploader {
private readonly eventBus: EventBus
) {}

async run(name: OfflineContentsName, path: FilePath): Promise<string> {
async run(
name: OfflineContentsName,
path: FilePath,
replaces?: string
): Promise<string> {
const { contents, stream, abortSignal } = await this.repository.read(name);

const uploader = this.contentsManagersFactory.uploader(
Expand All @@ -32,6 +36,7 @@ export class OfflineContentsUploader {
offlineContentsPath: contents.absolutePath,
size: contents.size,
path: path.value,
replaces,
});

await this.eventBus.publish([contentsUploadedEvent]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@ export class OfflineContentsUploadedDomainEvent extends DomainEvent {
readonly size: number;
readonly path: string;
readonly offlineContentsPath: string;
readonly replaces: string | undefined;

constructor({
aggregateId,
size,
path,
offlineContentsPath,
replaces,
}: {
aggregateId: string;
size: number;
path: string;
offlineContentsPath: string;
replaces?: string;
}) {
super({
aggregateId,
Expand All @@ -26,6 +29,7 @@ export class OfflineContentsUploadedDomainEvent extends DomainEvent {
this.size = size;
this.path = path;
this.offlineContentsPath = offlineContentsPath;
this.replaces = replaces;
}

toPrimitives() {
Expand All @@ -34,6 +38,7 @@ export class OfflineContentsUploadedDomainEvent extends DomainEvent {
size: this.size,
path: this.path,
offlineContentsPath: this.offlineContentsPath,
replaces: this.replaces,
};
}
}
Loading

0 comments on commit f9f753a

Please sign in to comment.