Skip to content

Commit

Permalink
Merge pull request #455 from internxt/update-content-sync
Browse files Browse the repository at this point in the history
[_]: feat/update-content-sync
  • Loading branch information
miguelsw authored Feb 9, 2024
2 parents a75c9b1 + 0fc762c commit 8097851
Show file tree
Hide file tree
Showing 15 changed files with 199 additions and 33 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@
"@iconscout/react-unicons": "^1.1.6",
"@internxt/inxt-js": "^2.0.8",
"@internxt/lib": "^1.1.6",
"@internxt/sdk": "^1.4.33",
"@internxt/sdk": "^1.4.68",
"@phosphor-icons/react": "2.0.9",
"@radix-ui/react-select": "^1.2.2",
"@sentry/electron": "^4.5.0",
Expand Down
15 changes: 10 additions & 5 deletions src/apps/sync-engine/BindingManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,10 +284,15 @@ export class BindingsManager {
}

private async polling(): Promise<void> {
Logger.info('[SYNC ENGINE] Monitoring polling...');
const fileInPendingPaths =
(await this.container.virtualDrive.getPlaceholderWithStatePending()) as Array<string>;
Logger.info('[SYNC ENGINE] fileInPendingPaths', fileInPendingPaths);
await this.container.fileSyncOrchestrator.run(fileInPendingPaths);
try {
Logger.info('[SYNC ENGINE] Monitoring polling...');

const fileInPendingPaths =
(await this.container.virtualDrive.getPlaceholderWithStatePending()) as Array<string>;
Logger.info('[SYNC ENGINE] fileInPendingPaths', fileInPendingPaths);
await this.container.fileSyncOrchestrator.run(fileInPendingPaths);
} catch (error) {
Logger.error('[SYNC ENGINE] Polling', error);
}
}
}
7 changes: 7 additions & 0 deletions src/apps/sync-engine/dependency-injection/files/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { DependencyInjectionHttpClientsProvider } from '../common/clients';
import { FileSyncronizer } from '../../../../context/virtual-drive/files/application/FileSyncronizer';
import { FilePlaceholderConverter } from '../../../../context/virtual-drive/files/application/FIlePlaceholderConverter';
import { FileSyncStatusUpdater } from '../../../../context/virtual-drive/files/application/FileSyncStatusUpdater';
import { FileContentsUpdater } from '../../../../context/virtual-drive/files/application/FileContentsUpdater';

export async function buildFilesContainer(
folderContainer: FoldersContainer,
Expand Down Expand Up @@ -124,6 +125,11 @@ export async function buildFilesContainer(

const fileSyncStatusUpdater = new FileSyncStatusUpdater(localFileSystem);

const fileContentsUpdater = new FileContentsUpdater(
repository,
remoteFileSystem
);

const fileSyncronizer = new FileSyncronizer(
repository,
fileSyncStatusUpdater,
Expand All @@ -132,6 +138,7 @@ export async function buildFilesContainer(
sharedContainer.absolutePathToRelativeConverter,
folderContainer.folderCreator,
folderContainer.offline.folderCreator,
fileContentsUpdater,
folderContainer.foldersFatherSyncStatusUpdater
);

Expand Down
1 change: 1 addition & 0 deletions src/context/shared/domain/ServerFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ export type ServerFile = {
userId: number;
status: ServerFileStatus;
plainName?: string;
uuid?: string;
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@ export class FileSyncOrchestrator {
private readonly fileSyncronizer: FileSyncronizer
) {}

run(absolutePaths: string[]): Promise<void[]> {
return Promise.all(
absolutePaths.map(async (absolutePath) => {
await this.fileSyncronizer.run(
absolutePath,
this.contentsUploader.run.bind(this.contentsUploader)
);
})
);
async run(absolutePaths: string[]): Promise<void> {
for (const absolutePath of absolutePaths) {
await this.fileSyncronizer.run(
absolutePath,
this.contentsUploader.run.bind(this.contentsUploader)
);
}
}
}
31 changes: 20 additions & 11 deletions src/context/virtual-drive/files/application/FileContentsUpdater.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
// import { FileRepository } from '../domain/FileRepository';
// import { RemoteFileSystem } from '../domain/file-systems/RemoteFileSystem';
import { File } from '../domain/File';
import { FileRepository } from '../domain/FileRepository';
import { RemoteFileSystem } from '../domain/file-systems/RemoteFileSystem';
import Logger from 'electron-log';

// export class FileContentsUpdater {
// constructor(
// private readonly repository: FileRepository,
// private readonly remote: RemoteFileSystem
// ) {}
export class FileContentsUpdater {
constructor(
private readonly repository: FileRepository,
private readonly remote: RemoteFileSystem
) {}

// async run(file: File): Promise<void> {
// await this.local.updateSyncStatus(file);
// }
// }
async run(
file: File,
contentsId: File['contentsId'],
size: File['size']
): Promise<File> {
Logger.info('Replace', file, contentsId, size);
await this.remote.replace(file, contentsId, size);
Logger.info('Updated', file, contentsId, size);
return this.repository.updateContentsAndSize(file, contentsId, size);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ export function createFileFromServerFile(
updatedAt: server.updatedAt,
path: relativePath,
status: server.status,
uuid: server.uuid,
});
}
58 changes: 52 additions & 6 deletions src/context/virtual-drive/files/application/FileSyncronizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ import { File } from '../domain/File';
import { FileSyncStatusUpdater } from './FileSyncStatusUpdater';
import { FilePlaceholderConverter } from './FIlePlaceholderConverter';
import { FoldersFatherSyncStatusUpdater } from '../../folders/application/FoldersFatherSyncStatusUpdater';
import { FileContentsUpdater } from './FileContentsUpdater';

export class FileSyncronizer {
// queue of files to be uploaded
private filePath: string | undefined;
private foldersPathQueue: string[] = [];
constructor(
private readonly repository: FileRepository,
private readonly fileSyncStatusUpdater: FileSyncStatusUpdater,
Expand All @@ -25,13 +29,15 @@ export class FileSyncronizer {
private readonly absolutePathToRelativeConverter: AbsolutePathToRelativeConverter,
private readonly folderCreator: FolderCreator,
private readonly offlineFolderCreator: OfflineFolderCreator,
private readonly fileContentsUpdater: FileContentsUpdater,
private readonly foldersFatherSyncStatusUpdater: FoldersFatherSyncStatusUpdater
) {}

async run(
absolutePath: string,
upload: (path: string) => Promise<RemoteFileContents>
) {
): Promise<void> {
this.filePath = absolutePath;
const win32RelativePath =
this.absolutePathToRelativeConverter.run(absolutePath);

Expand All @@ -45,9 +51,31 @@ export class FileSyncronizer {
status: FileStatuses.EXISTS,
});

await this.sync(
existingFile,
absolutePath,
posixRelativePath,
path,
upload
);
}

private async sync(
existingFile: File | undefined,
absolutePath: string,
posixRelativePath: string,
path: FilePath,
upload: (path: string) => Promise<RemoteFileContents>
) {
if (existingFile) {
if (this.hasDifferentSize(existingFile, absolutePath)) {
return;
const contents = await upload(posixRelativePath);
existingFile = await this.fileContentsUpdater.run(
existingFile,
contents.id,
contents.size
);
Logger.info('existingFile ', existingFile);
}
await this.convertAndUpdateSyncStatus(existingFile);
} else {
Expand All @@ -62,6 +90,7 @@ export class FileSyncronizer {
attemps = 3
) => {
try {
await new Promise((resolve) => setTimeout(resolve, 2000));
const fileContents = await upload(posixRelativePath);
const createdFile = await this.fileCreator.run(filePath, fileContents);
await this.convertAndUpdateSyncStatus(createdFile);
Expand Down Expand Up @@ -93,15 +122,17 @@ export class FileSyncronizer {
const posixDir =
PlatformPathConverter.getFatherPathPosix(posixRelativePath);
try {
await new Promise((resolve) => setTimeout(resolve, 1000));
await new Promise((resolve) => setTimeout(resolve, 4000));
await this.runFolderCreator(posixDir);
} catch (error) {
Logger.error('Error creating folder father creation:', error);
if (error instanceof FolderNotFoundError) {
this.foldersPathQueue.push(posixDir);
// father created
await this.createFolderFather(posixDir);
// child created
await this.runFolderCreator(posixDir);
Logger.info('Creating child', posixDir);
await this.retryFolderCreation(posixDir);
} else {
Logger.error(
'Error creating folder father creation inside catch:',
Expand All @@ -118,7 +149,22 @@ export class FileSyncronizer {
}

private async convertAndUpdateSyncStatus(file: File) {
await this.filePlaceholderConverter.run(file);
await this.fileSyncStatusUpdater.run(file);
await Promise.all([
this.filePlaceholderConverter.run(file),
this.fileSyncStatusUpdater.run(file),
]);
}

private retryFolderCreation = async (posixDir: string, attemps = 3) => {
try {
await new Promise((resolve) => setTimeout(resolve, 4000));
await this.runFolderCreator(posixDir);
} catch (error) {
Logger.error('Error creating folder father creation:', error);
if (attemps > 0) {
await this.retryFolderCreation(posixDir, attemps - 1);
return;
}
}
};
}
19 changes: 18 additions & 1 deletion src/context/virtual-drive/files/domain/File.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { FileRenamedDomainEvent } from './events/FileRenamedDomainEvent';
import { FilePlaceholderId, createFilePlaceholderId } from './PlaceholderId';

export type FileAttributes = {
uuid?: string;
contentsId: string;
folderId: number;
createdAt: string;
Expand All @@ -27,17 +28,22 @@ export type FileAttributes = {

export class File extends AggregateRoot {
private constructor(
private _uuid: string,
private _contentsId: ContentsId,
private _folderId: number,
private _path: FilePath,
private readonly _size: FileSize,
private _size: FileSize,
public createdAt: Date,
public updatedAt: Date,
private _status: FileStatus
) {
super();
}

public get uuid(): string {
return this._uuid;
}

public get contentsId() {
return this._contentsId.value;
}
Expand Down Expand Up @@ -80,6 +86,7 @@ export class File extends AggregateRoot {

static from(attributes: FileAttributes): File {
return new File(
attributes.uuid ?? '',
new ContentsId(attributes.contentsId),
attributes.folderId,
new FilePath(attributes.path),
Expand All @@ -97,6 +104,7 @@ export class File extends AggregateRoot {
path: FilePath
): File {
const file = new File(
'', // we should generate a uuid here
new ContentsId(contentsId),
folder.id,
path,
Expand Down Expand Up @@ -183,8 +191,17 @@ export class File extends AggregateRoot {
return this._status.is(status);
}

replaceContestsAndSize(contentsId: string, size: number) {
this._contentsId = new ContentsId(contentsId);
this._size = new FileSize(size);
this.updatedAt = new Date();

return this;
}

attributes(): FileAttributes {
return {
uuid: this._uuid,
contentsId: this.contentsId,
folderId: this.folderId,
createdAt: this.createdAt.toISOString(),
Expand Down
6 changes: 6 additions & 0 deletions src/context/virtual-drive/files/domain/FileRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,10 @@ export interface FileRepository {
add(file: File): Promise<void>;

update(file: File): Promise<void>;

updateContentsAndSize(
file: File,
newContentsId: File['contentsId'],
newSize: File['size']
): Promise<File>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { DomainEvent } from '../../../../shared/domain/DomainEvent';

export type CreatedWebdavFileDomainEventAttributes = {
readonly size: number;
readonly type: string;
readonly path: string;
};

export class FileUpdateContentDomainEvent extends DomainEvent {
static readonly EVENT_NAME = 'file.update.content';

readonly size: number;
readonly contentId: string;

constructor({
aggregateId,
eventId,
size,
contentId,
}: {
aggregateId: string;
eventId?: string;
size: number;
contentId: string;
}) {
super({
eventName: FileUpdateContentDomainEvent.EVENT_NAME,
aggregateId,
eventId,
});
this.size = size;
this.contentId = contentId;
}

toPrimitives() {
const { size, contentId } = this;

return { size, contentId };
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,10 @@ export interface RemoteFileSystem {
move(file: File): Promise<void>;

rename(file: File): Promise<void>;

replace(
file: File,
newContentsId: File['contentsId'],
newSize: File['size']
): Promise<void>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,19 @@ export class InMemoryFileRepository implements FileRepository {

return this.add(file);
}

async updateContentsAndSize(
file: File,
newContentsId: File['contentsId'],
newSize: File['size']
): Promise<File> {
if (!this.files.has(file.contentsId)) {
throw new Error('File not found');
}

const updatedFile = file.replaceContestsAndSize(newContentsId, newSize);
this.files.set(updatedFile.contentsId, updatedFile.attributes());
this.files.delete(file.contentsId);
return updatedFile;
}
}
Loading

0 comments on commit 8097851

Please sign in to comment.