diff --git a/src/apps/fuse/dependency-injection/virtual-drive/contents/builder.ts b/src/apps/fuse/dependency-injection/virtual-drive/contents/builder.ts index d18ee1ff5..b6fb13a9e 100644 --- a/src/apps/fuse/dependency-injection/virtual-drive/contents/builder.ts +++ b/src/apps/fuse/dependency-injection/virtual-drive/contents/builder.ts @@ -16,6 +16,7 @@ import { MoveOfflineContentsOnContentsUploaded } from '../../../../../context/vi import { LocalContentsMover } from '../../../../../context/virtual-drive/contents/application/LocalContentsMover'; import { AllLocalContentsDeleter } from '../../../../../context/virtual-drive/contents/application/AllLocalContentsDeleter'; import { MainProcessUploadProgressTracker } from '../../../../../context/shared/infrastructure/MainProcessUploadProgressTracker'; +import { MainProcessDownloadProgressTracker } from '../../../../../context/shared/infrastructure/MainProcessDownloadProgressTracker'; export async function buildContentsContainer( sharedContainer: SharedContainer @@ -44,10 +45,13 @@ export async function buildContentsContainer( 'downloaded' ); + const tracker = new MainProcessDownloadProgressTracker(); + const downloadContentsToPlainFile = new DownloadContentsToPlainFile( contentsManagerFactory, localFS, - eventBus + eventBus, + tracker ); const localContentChecker = new LocalContentChecker(localFS); diff --git a/src/apps/hydration-api/dependency-injection/contents/builder.ts b/src/apps/hydration-api/dependency-injection/contents/builder.ts index 32e6826c9..8876a20e3 100644 --- a/src/apps/hydration-api/dependency-injection/contents/builder.ts +++ b/src/apps/hydration-api/dependency-injection/contents/builder.ts @@ -8,6 +8,7 @@ import { FSLocalFileSystem } from '../../../../context/virtual-drive/contents/in import { DependencyInjectionEventBus } from '../common/eventBus'; import { FuseAppDataLocalFileContentsDirectoryProvider } from '../../../../context/virtual-drive/shared/infrastructure/LocalFileContentsDirectoryProviders/FuseAppDataLocalFileContentsDirectoryProvider'; import { LocalContentsDeleter } from '../../../../context/virtual-drive/contents/application/LocalContentsDeleter'; +import { MainProcessDownloadProgressTracker } from '../../../../context/shared/infrastructure/MainProcessDownloadProgressTracker'; export async function buildContentsContainer(): Promise { const user = DependencyInjectionUserProvider.get(); @@ -32,10 +33,13 @@ export async function buildContentsContainer(): Promise { 'downloaded' ); + const tracker = new MainProcessDownloadProgressTracker(); + const downloadContentsToPlainFile = new DownloadContentsToPlainFile( contentsManagerFactory, localFS, - eventBus + eventBus, + tracker ); const localContentsDeleter = new LocalContentsDeleter(localFS); diff --git a/src/context/shared/domain/DownloadProgressTracker.ts b/src/context/shared/domain/DownloadProgressTracker.ts index 17b4ae300..277a7cd57 100644 --- a/src/context/shared/domain/DownloadProgressTracker.ts +++ b/src/context/shared/domain/DownloadProgressTracker.ts @@ -1,6 +1,21 @@ export interface DownloadProgressTracker { - downloadStarted(name: string): Promise; - downloadUpdate(name: string, progress: number): Promise; - downloadFinished(name: string): Promise; - error(name: string): Promise; + downloadStarted(name: string, extension: string, size: number): Promise; + downloadUpdate( + name: string, + extension: string, + size: number, + progress: { + elapsedTime: number; + percentage: number; + } + ): Promise; + downloadFinished( + name: string, + extension: string, + size: number, + progress: { + elapsedTime: number; + } + ): Promise; + error(name: string, extension: string): Promise; } diff --git a/src/context/shared/infrastructure/MainProcessDownloadProgressTracker.ts b/src/context/shared/infrastructure/MainProcessDownloadProgressTracker.ts new file mode 100644 index 000000000..f3fd7a0e0 --- /dev/null +++ b/src/context/shared/infrastructure/MainProcessDownloadProgressTracker.ts @@ -0,0 +1,93 @@ +import { trackError, trackEvent } from '../../../apps/main/analytics/service'; +import { setTrayStatus } from '../../../apps/main/tray/tray'; +import { broadcastToWindows } from '../../../apps/main/windows'; +import { DownloadProgressTracker } from '../domain/DownloadProgressTracker'; +import { SyncMessenger } from '../domain/SyncMessenger'; + +export class MainProcessDownloadProgressTracker + extends SyncMessenger + implements DownloadProgressTracker +{ + async downloadStarted( + name: string, + extension: string, + size: number + ): Promise { + setTrayStatus('SYNCING'); + + trackEvent('Upload Started', { + file_name: name, + file_extension: extension, + file_size: size, + elapsedTimeMs: 0, + }); + + broadcastToWindows('sync-info-update', { + action: 'DOWNLOADING', + name: this.nameWithExtension(name, extension), + progress: 0, + }); + } + + async downloadUpdate( + name: string, + extension: string, + size: number, + progress: { elapsedTime: number; percentage: number } + ): Promise { + trackEvent('Upload Started', { + file_name: name, + file_extension: extension, + file_size: size, + elapsedTimeMs: progress.elapsedTime, + }); + + broadcastToWindows('sync-info-update', { + action: 'DOWNLOADING', + name: this.nameWithExtension(name, extension), + progress: progress.percentage, + }); + } + + async downloadFinished( + name: string, + extension: string, + size: number, + progress: { + elapsedTime: number; + } + ): Promise { + const nameWithExtension = this.nameWithExtension(name, extension); + + setTrayStatus('IDLE'); + + trackEvent('Upload Completed', { + file_name: name, + file_extension: extension, + file_size: size, + elapsedTimeMs: progress.elapsedTime, + }); + + broadcastToWindows('sync-info-update', { + action: 'UPLOADED', + name: nameWithExtension, + }); + } + + async error(name: string, extension: string): Promise { + const nameWithExtension = this.nameWithExtension(name, extension); + + // TODO: finish this + trackError('Upload Error', new Error(), { + itemType: 'File', + root: '', + from: name, + action: 'Upload', + }); + + broadcastToWindows('sync-info-update', { + action: 'DOWNLOAD_ERROR', + name: nameWithExtension, + }); + } +} diff --git a/src/context/virtual-drive/contents/application/DownloadContentsToPlainFile.ts b/src/context/virtual-drive/contents/application/DownloadContentsToPlainFile.ts index d94336df5..75563363e 100644 --- a/src/context/virtual-drive/contents/application/DownloadContentsToPlainFile.ts +++ b/src/context/virtual-drive/contents/application/DownloadContentsToPlainFile.ts @@ -18,19 +18,24 @@ export class DownloadContentsToPlainFile { private async registerEvents(downloader: ContentFileDownloader, file: File) { downloader.on('start', () => { - this.tracker.downloadStarted(file.nameWithExtension); + this.tracker.downloadStarted(file.name, file.type, file.size); }); - downloader.on('progress', (progress: number) => { - this.tracker.downloadUpdate(file.nameWithExtension, progress); + downloader.on('progress', (progress: number, elapsedTime: number) => { + this.tracker.downloadUpdate(file.name, file.type, file.size, { + elapsedTime, + percentage: progress, + }); }); downloader.on('error', () => { - this.tracker.error(file.nameWithExtension); + this.tracker.error(file.name, file.type); }); - downloader.on('finish', () => { - this.tracker.downloadFinished(file.nameWithExtension); + downloader.on('finish', (elapsedTime: number) => { + this.tracker.downloadFinished(file.name, file.type, file.size, { + elapsedTime, + }); }); } diff --git a/src/context/virtual-drive/contents/domain/contentHandlers/ContentFileDownloader.ts b/src/context/virtual-drive/contents/domain/contentHandlers/ContentFileDownloader.ts index 586057f85..89dcf62ff 100644 --- a/src/context/virtual-drive/contents/domain/contentHandlers/ContentFileDownloader.ts +++ b/src/context/virtual-drive/contents/domain/contentHandlers/ContentFileDownloader.ts @@ -3,7 +3,7 @@ import { File, FileAttributes } from '../../../files/domain/File'; export type FileDownloadEvents = { start: () => void; - progress: (progress: number) => void; + progress: (progress: number, elapsedTime: number) => void; finish: (fileId: FileAttributes['contentsId']) => void; error: (error: Error) => void; }; diff --git a/src/context/virtual-drive/contents/infrastructure/download/EnvironmentContentFileDownloader.ts b/src/context/virtual-drive/contents/infrastructure/download/EnvironmentContentFileDownloader.ts index 5744672bd..d9dea7b72 100644 --- a/src/context/virtual-drive/contents/infrastructure/download/EnvironmentContentFileDownloader.ts +++ b/src/context/virtual-drive/contents/infrastructure/download/EnvironmentContentFileDownloader.ts @@ -44,7 +44,7 @@ export class EnvironmentContentFileDownloader implements ContentFileDownloader { file.contentsId, { progressCallback: (progress: number) => { - this.eventEmitter.emit('progress', progress); + this.eventEmitter.emit('progress', progress, this.elapsedTime()); }, finishedCallback: async (err: Error, stream: Readable) => { this.stopwatch.finish(); @@ -53,7 +53,7 @@ export class EnvironmentContentFileDownloader implements ContentFileDownloader { this.eventEmitter.emit('error', err); return reject(err); } - this.eventEmitter.emit('finish'); + this.eventEmitter.emit('finish', this.elapsedTime()); resolve(stream); }, diff --git a/tests/context/virtual-drive/shared/__mock__/DownloadProgressTrackerMock.ts b/tests/context/virtual-drive/shared/__mock__/DownloadProgressTrackerMock.ts index c6fd7f983..ec43c5397 100644 --- a/tests/context/virtual-drive/shared/__mock__/DownloadProgressTrackerMock.ts +++ b/tests/context/virtual-drive/shared/__mock__/DownloadProgressTrackerMock.ts @@ -6,16 +6,33 @@ export class DownloadProgressTrackerMock implements DownloadProgressTracker { readonly downloadFinishedMock = jest.fn(); readonly errorMock = jest.fn(); - downloadStarted(name: string): Promise { - return this.downloadStartedMock(name); + downloadStarted( + name: string, + extension: string, + size: number + ): Promise { + return this.downloadStartedMock(name, extension, size); } - downloadUpdate(name: string, progress: number): Promise { - return this.downloadUpdateMock(name, progress); + + downloadUpdate( + name: string, + extension: string, + size: number, + progress: { elapsedTime: number; percentage: number } + ): Promise { + return this.downloadUpdateMock(name, extension, size, progress); } - downloadFinished(name: string): Promise { - return this.downloadFinishedMock(name); + + downloadFinished( + name: string, + extension: string, + size: number, + progress: { elapsedTime: number } + ): Promise { + return this.downloadFinishedMock(name, extension, size, progress); } - error(name: string): Promise { - return this.errorMock(name); + + error(name: string, extension: string): Promise { + return this.errorMock(name, extension); } }