/// <summary>
        /// Downloads Google Docs file.
        /// </summary>
        /// <param name="file">Meta-information about file to download.</param>
        /// <param name="context">Provides context for task execution, like logger object and
        ///     cancellation token.</param>
        /// <returns>An information about downloaded file.</returns>
        public async Task <DownloadedFile> Run(File file, ITaskContext context)
        {
            if (!this.exportFormats.ContainsKey(file.MimeType) || (this.exportFormats[file.MimeType].Count == 0))
            {
                context.Log.LogError($"Unknown export format for file MIME type {file.MimeType}.");
                return(null);
            }

            // Just take first available export format for now.
            var exportFormat  = this.exportFormats[file.MimeType][0];
            var exportRequest = this.service.Files.Export(file.Id, exportFormat);

            await this.semaphore.WaitAsync();

            context.Log.LogDebugMessage(
                $"Starting to download '{file.Name}' Google Docs file, export format is {exportFormat}.");

            try
            {
                var resultStream = await GoogleRequestHelper.Execute(
                    exportRequest.ExecuteAsStreamAsync,
                    context.CancellationToken,
                    GoogleRequestHelper.Cooldown *Utils.Constants.DownloadThreadsCount);

                var mimeParts = exportFormat.Split('/', '+');
                var extension = mimeParts[mimeParts.Length - 1];
                switch (extension)
                {
                case "vnd.openxmlformats-officedocument.presentationml.presentation":
                    extension = "pptx";
                    break;

                case "xml":
                    extension = "svg";
                    break;
                }

                var fileName = FileDownloadUtils.GetFileName(file, this.directories) + "." + extension;
                using (var fileStream = new FileStream(fileName, FileMode.Create))
                {
                    await resultStream.CopyToAsync(fileStream, 4096, context.CancellationToken);
                }

                var fileInfo = FileDownloadUtils.CorrectFileTimes(file, fileName);
                context.Log.LogDebugMessage(
                    $"File '{file.Name}' downloading finished, saved as '{fileInfo.FullName}'.");
                return(new DownloadedFile(file, fileInfo.FullName));
            }
            catch (Exception e)
            {
                if (context.CancellationToken.IsCancellationRequested)
                {
                    throw;
                }

                context.Fail($"File '{file.Name}' downloading failed.", e);

                throw;
            }
            finally
            {
                this.semaphore.Release();
            }
        }
Example #2
0
        /// <summary>
        /// Downloads binary (non-"Google Docs") file.
        /// </summary>
        /// <param name="service">Google Drive service used to download a file.</param>
        /// <param name="file">Meta-information about file to download.</param>
        /// <param name="semaphore">Semaphore used to throttle downloading process.</param>
        /// <param name="unitsOfWork">Abstract units of work assigned to download this file. Used in progress reporting.</param>
        /// <param name="directories">Dictionary that contains possible directories to save a file.</param>
        /// <returns>Information about downloaded file, null if downloading failed.</returns>
        /// <exception cref="InternalErrorException">Something is wrong with downloader code itself.</exception>
        public async Task <DownloadedFile> DownloadBinaryFile(
            DriveService service,
            File file,
            AsyncSemaphore semaphore,
            int unitsOfWork,
            IDictionary <File, IEnumerable <DirectoryInfo> > directories)
        {
            this.Info       = file.Name;
            this.Estimation = unitsOfWork;

            if (file.Size.HasValue && (file.Size.Value == 0))
            {
                try
                {
                    var fileName = FileDownloadUtils.GetFileName(file, directories);
                    System.IO.File.Create(fileName);
                    this.Done();
                    return(new DownloadedFile(file, fileName));
                }
                catch (Exception e)
                {
                    this.Log.LogError($"Saving zero-length file '{file.Name}' error.", e);
                    this.StatusAccumulator.FailureOccurred();
                    throw;
                }
            }

            var request = service.Files.Get(file.Id);

            request.MediaDownloader.ProgressChanged += downloadProgress =>
            {
                switch (downloadProgress.Status)
                {
                case DownloadStatus.NotStarted:
                    break;

                case DownloadStatus.Downloading:
                    this.Progress = (int)(downloadProgress.BytesDownloaded * unitsOfWork / (file.Size ?? 1));
                    break;

                case DownloadStatus.Completed:
                    this.Progress = this.Estimation;
                    break;

                case DownloadStatus.Failed:
                    this.Progress = this.Estimation;
                    if (!this.CancellationToken.IsCancellationRequested)
                    {
                        this.Status = Status.Error;
                        this.Log.LogError($"Downloading file '{file.Name}' error.", downloadProgress.Exception);
                        this.StatusAccumulator.FailureOccurred();
                    }

                    break;

                default:
                    throw new InternalErrorException("DownloadStatus enum contains unknown value.");
                }
            };

            await semaphore.WaitAsync();

            this.Log.LogDebugMessage($"Starting to download '{file.Name}' binary file.");

            try
            {
                var fileName = FileDownloadUtils.GetFileName(file, directories);
                using (var fileStream = new FileStream(fileName, FileMode.Create))
                {
                    await GoogleRequestHelper.Execute(
                        ct => request.DownloadAsync(fileStream, ct),
                        this.CancellationToken,
                        GoogleRequestHelper.Cooldown *Utils.Constants.DownloadThreadsCount);
                }

                var fileInfo = FileDownloadUtils.CorrectFileTimes(file, fileName);
                this.Log.LogDebugMessage($"File '{file.Name}' downloading finished, saved as {fileInfo.FullName}.");
                this.StatusAccumulator.SuccessItem();
                this.Done();
                return(new DownloadedFile(file, fileInfo.FullName));
            }
            catch (Exception e)
            {
                if (this.CancellationToken.IsCancellationRequested)
                {
                    throw;
                }

                this.Log.LogError($"Downloading file '{file.Name}' error.", e);
                this.StatusAccumulator.FailureOccurred();

                throw;
            }
            finally
            {
                semaphore.Release();
            }
        }