Bloom.WebLibraryIntegration.BloomS3Client.DownloadBook C# (CSharp) Method

DownloadBook() public method

Warning, if the book already exists in the location, this is going to delete it an over-write it. So it's up to the caller to check the sanity of that.
public DownloadBook ( string bucketName, string storageKeyOfBookFolder, string pathToDestinationParentDirectory, IProgressDialog downloadProgress = null ) : string
bucketName string
storageKeyOfBookFolder string
pathToDestinationParentDirectory string
downloadProgress IProgressDialog
return string
        public string DownloadBook(string bucketName, string storageKeyOfBookFolder, string pathToDestinationParentDirectory,
			IProgressDialog downloadProgress = null)
        {
            //review: should we instead save to a newly created folder so that we don't have to worry about the
            //other folder existing already? Todo: add a test for that first.

            // We need to download individual files to avoid downloading unwanted files (PDFs and thumbs.db to
            // be specific).  See https://silbloom.myjetbrains.com/youtrack/issue/BL-2312.  So we need the list
            // of items, not just the count.
            var matching = GetMatchingItems(bucketName, storageKeyOfBookFolder);
            var totalItems = CountDesiredFiles(matching);
            if(totalItems == 0)
                throw new DirectoryNotFoundException("The book we tried to download is no longer in the BloomLibrary");

            Debug.Assert(matching.S3Objects[0].Key.StartsWith(storageKeyOfBookFolder + "/"));

            // Get the top-level directory name of the book from the first object key.
            var bookFolderName = matching.S3Objects[0].Key.Substring(storageKeyOfBookFolder.Length + 1);
            while(bookFolderName.Contains("/"))
                bookFolderName = Path.GetDirectoryName(bookFolderName);

            // Amazon.S3 appears to truncate titles at 50 characters when building directory and filenames.  This means
            // that relative paths can be as long as 117 characters (2 * 50 + 2 for slashes + 15 for .BloomBookOrder).
            // So our temporary folder must be no more than 140 characters (allow some margin) since paths can be a
            // maximum of 260 characters in Windows.  (More margin than that may be needed because there's no guarantee
            // that image filenames are no longer than 65 characters.)  See https://jira.sil.org/browse/BL-1160.
            using(var tempDestination = new TemporaryFolder("BDS_" + Guid.NewGuid()))
            {
                var tempDirectory = Path.Combine(tempDestination.FolderPath, bookFolderName);
                if(downloadProgress != null)
                    downloadProgress.Invoke((Action) (() => { downloadProgress.ProgressRangeMaximum = totalItems; }));
                int booksDownloaded = 0;
                using(var transferUtility = new TransferUtility(_amazonS3))
                {
                    for(int i = 0; i < matching.S3Objects.Count; ++i)
                    {
                        var objKey = matching.S3Objects[i].Key;
                        if(AvoidThisFile(objKey))
                            continue;
                        // Removing the book's prefix from the object key, then using the remainder of the key
                        // in the filepath allows for nested subdirectories.
                        var filepath = objKey.Substring(storageKeyOfBookFolder.Length + 1);
                        // Download this file then bump progress.
                        var req = new TransferUtilityDownloadRequest()
                        {
                            BucketName = bucketName,
                            Key = objKey,
                            FilePath = Path.Combine(tempDestination.FolderPath, filepath)
                        };
                        transferUtility.Download(req);
                        ++booksDownloaded;
                        if(downloadProgress != null)
                            downloadProgress.Invoke((Action) (() => { downloadProgress.Progress = booksDownloaded; }));
                    }
                    var destinationPath = Path.Combine(pathToDestinationParentDirectory, bookFolderName);

                    //clear out anything existing on our target
                    var didDelete = false;
                    if(Directory.Exists(destinationPath))
                    {
                        try
                        {
                            SIL.IO.RobustIO.DeleteDirectory(destinationPath, true);
                            didDelete = true;
                        }
                        catch(IOException)
                        {
                            // can't delete it...see if we can copy into it.
                        }
                    }

                    //if we're on the same volume, we can just move it. Else copy it.
                    // It's important that books appear as nearly complete as possible, because a file watcher will very soon add the new
                    // book to the list of downloaded books the user can make new ones from, once it appears in the target directory.
                    bool done = false;
                    if(didDelete && PathUtilities.PathsAreOnSameVolume(pathToDestinationParentDirectory, tempDirectory))
                    {
                        try
                        {
                            SIL.IO.RobustIO.MoveDirectory(tempDirectory, destinationPath);
                            done = true;
                        }
                        catch(IOException)
                        {
                            // If moving didn't work we'll just try copying
                        }
                        catch(UnauthorizedAccessException)
                        {
                        }
                    }
                    if(!done)
                        done = CopyDirectory(tempDirectory, destinationPath);
                    if(!done)
                    {
                        var msg = LocalizationManager.GetString("Download.CopyFailed",
                            "Bloom downloaded the book but had problems making it available in Bloom. Please restart your computer and try again. If you get this message again, please click the 'Details' button and report the problem to the Bloom developers");
                        // The exception doesn't add much useful information but it triggers a version of the dialog with a Details button
                        // that leads to the yellow box and an easy way to send the report.
                        ErrorReport.NotifyUserOfProblem(new ApplicationException("File Copy problem"), msg);
                    }
                    return destinationPath;
                }
            }
        }

Usage Example

Example #1
0
        /// <summary>
        /// Internal for testing because it's not yet clear this is the appropriate public routine.
        /// Probably some API gets a list of BloomInfo objects from the parse.com data, and we pass one of
        /// them as the argument for the public method.
        /// </summary>
        /// <param name="bucket"></param>
        /// <param name="s3BookId"></param>
        /// <param name="dest"></param>
        /// <returns></returns>
        internal string DownloadBook(string bucket, string s3BookId, string dest)
        {
            var destinationPath = _s3Client.DownloadBook(bucket, s3BookId, dest, _progressDialog);

            if (BookDownLoaded != null)
            {
                var bookInfo = new BookInfo(destinationPath, false);                 // A downloaded book is a template, so never editable.
                BookDownLoaded(this, new BookDownloadedEventArgs()
                {
                    BookDetails = bookInfo
                });
            }
            // Books in the library should generally show as locked-down, so new users are automatically in localization mode.
            // Occasionally we may want to upload a new authoring template, that is, a 'book' that is suitableForMakingShells.
            // Such books should not be locked down.
            // So, we try to lock it. What we want to do is Book.RecordedAsLockedDown = true; Book.Save().
            // But all kinds of things have to be set up before we can create a Book. So we duplicate a few bits of code.
            var htmlFile = BookStorage.FindBookHtmlInFolder(destinationPath);

            if (htmlFile == "")
            {
                return(destinationPath);                //argh! we can't lock it.
            }
            var xmlDomFromHtmlFile = XmlHtmlConverter.GetXmlDomFromHtmlFile(htmlFile, false);
            var dom = new HtmlDom(xmlDomFromHtmlFile);

            if (!BookMetaData.FromString(MetaDataText(destinationPath)).IsSuitableForMakingShells)
            {
                dom.RecordAsLockedDown(true);
                XmlHtmlConverter.SaveDOMAsHtml5(dom.RawDom, htmlFile);
            }

            return(destinationPath);
        }
All Usage Examples Of Bloom.WebLibraryIntegration.BloomS3Client::DownloadBook