import { ProgressMessage, ResponseService, } from '../common/protocol/response-service'; import { DownloadProgress, TaskProgress, } from './cli-protocol/cc/arduino/cli/commands/v1/common_pb'; export interface InstallResponse { getProgress?(): DownloadProgress | undefined; getTaskProgress(): TaskProgress | undefined; } export namespace InstallWithProgress { export interface Options { /** * _unknown_ progress if falsy. */ readonly progressId?: string; readonly responseService: ResponseService; } export function createDataCallback({ responseService, progressId, }: InstallWithProgress.Options): (response: InstallResponse) => void { let localFile = ''; let localTotalSize = Number.NaN; return (response: InstallResponse) => { const download = response.getProgress ? response.getProgress() : undefined; const task = response.getTaskProgress(); if (!download && !task) { throw new Error( "Implementation error. Neither 'download' nor 'task' is available." ); } if (task && download) { throw new Error( "Implementation error. Both 'download' and 'task' are available." ); } if (task) { const message = task.getName() || task.getMessage(); if (message) { if (progressId) { responseService.reportProgress({ progressId, message, work: { done: Number.NaN, total: Number.NaN }, }); } responseService.appendToOutput({ chunk: `${message}\n` }); } } else if (download) { if (download.getFile() && !localFile) { localFile = download.getFile(); } if (download.getTotalSize() > 0 && Number.isNaN(localTotalSize)) { localTotalSize = download.getTotalSize(); } // This happens only once per file download. if (download.getTotalSize() && localFile) { responseService.appendToOutput({ chunk: `${localFile}\n` }); } if (progressId && localFile) { let work: ProgressMessage.Work | undefined = undefined; if (download.getDownloaded() > 0 && !Number.isNaN(localTotalSize)) { work = { total: localTotalSize, done: download.getDownloaded(), }; } responseService.reportProgress({ progressId, message: `Downloading ${localFile}`, work, }); } if (download.getCompleted()) { // Discard local state. if (progressId && !Number.isNaN(localTotalSize)) { responseService.reportProgress({ progressId, message: '', work: { done: Number.NaN, total: Number.NaN }, }); } localFile = ''; localTotalSize = Number.NaN; } } }; } }