Beispiel #1
0
 public static int HandleSilentDownload(DownloadBookOptions options)
 {
     // This task will be all the program does. We need to do enough setup so that
     // the download code can work, then tear it down.
     Program.SetUpErrorHandling();
     try
     {
         using (var applicationContainer = new ApplicationContainer())
         {
             Program.SetUpLocalization(applicationContainer);
             Browser.SetUpXulRunner();
             Browser.XulRunnerShutdown += Program.OnXulRunnerShutdown;
             LocalizationManager.SetUILanguage(Settings.Default.UserInterfaceLanguage, false);
             var transfer = new BookTransfer(new BloomParseClient(), ProjectContext.CreateBloomS3Client(),
                                             applicationContainer.BookThumbNailer, new BookDownloadStartingEvent()) /*not hooked to anything*/;
             // Since Bloom is not a normal console app, when run from a command line, the new command prompt
             // appears at once. The extra newlines here are attempting to separate this from our output.
             Console.WriteLine("\nstarting download");
             transfer.HandleDownloadWithoutProgress(options.Url, options.DestinationPath);
             Console.WriteLine(("\ndownload complete\n"));
         }
         return(0);
     }
     catch (Exception ex)
     {
         Debug.WriteLine(ex.Message);
         Console.WriteLine(ex.Message);
         Console.WriteLine(ex.StackTrace);
         return(1);
     }
 }
Beispiel #2
0
        /// <summary>
        /// Review: this is fragile and expensive. We're doing real internet traffic and creating real objects on S3 and parse.com
        /// which (to a very small extent) costs us real money. This will be slow. Also, under S3 eventual consistency rules,
        /// there is no guarantee that the data we just created will actually be retrievable immediately.
        /// </summary>
        /// <param name="bookName"></param>
        /// <param name="id"></param>
        /// <param name="uploader"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public Tuple <string, string> UploadAndDownLoadNewBook(string bookName, string id, string uploader, string data, bool isTemplate = false)
        {
            //  Create a book folder with meta.json that includes an uploader and id and some other files.
            var originalBookFolder = MakeBook(bookName, id, uploader, data, true);

            if (isTemplate)
            {
                var metadata = BookMetaData.FromFolder(originalBookFolder);
                metadata.IsSuitableForMakingShells = true;
                metadata.WriteToFolder(originalBookFolder);
            }
            // The files that actually get uploaded omit some of the ones in the folder.
            // The only omitted one that messes up current unit tests is meta.bak
            var filesToUpload = Directory.GetFiles(originalBookFolder).Where(p => !p.EndsWith(".bak") && !p.Contains(BookStorage.PrefixForCorruptHtmFiles));
            int fileCount     = filesToUpload.Count();

            Login();
            //HashSet<string> notifications = new HashSet<string>();

            var progress = new SIL.Progress.StringBuilderProgress();
            var s3Id     = _transfer.UploadBook(originalBookFolder, progress);

            var uploadMessages = progress.Text.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);

            var expectedFileCount = fileCount + 2;             // should get one per file, plus one for metadata, plus one for book order

#if DEBUG
            ++expectedFileCount;                // and if in debug mode, then plus one for S3 ID
#endif
            Assert.That(uploadMessages.Length, Is.EqualTo(expectedFileCount));
            Assert.That(progress.Text, Does.Contain(
                            LocalizationManager.GetString("PublishTab.Upload.UploadingBookMetadata", "Uploading book metadata",
                                                          "In this step, Bloom is uploading things like title, languages, & topic tags to the bloomlibrary.org database.")));
            Assert.That(progress.Text, Does.Contain(Path.GetFileName(filesToUpload.First())));

            _transfer.WaitUntilS3DataIsOnServer(BloomS3Client.UnitTestBucketName, originalBookFolder);
            var dest = _workFolderPath.CombineForPath("output");
            Directory.CreateDirectory(dest);
            _downloadedBooks.Clear();
            var url           = BookTransfer.BloomS3UrlPrefix + BloomS3Client.UnitTestBucketName + "/" + s3Id;
            var newBookFolder = _transfer.HandleDownloadWithoutProgress(url, dest);

            Assert.That(Directory.GetFiles(newBookFolder).Length, Is.EqualTo(fileCount + 1));             // book order is added during upload

            Assert.That(_downloadedBooks.Count, Is.EqualTo(1));
            Assert.That(_downloadedBooks[0].FolderPath, Is.EqualTo(newBookFolder));
            // Todo: verify that metadata was transferred to Parse.com
            return(new Tuple <string, string>(originalBookFolder, newBookFolder));
        }
        private void ProcessOneBook(Book book)
        {
            try
            {
                _logger.TrackEvent("ProcessOneBook Start");
                string message = $"Processing: {book.BaseUrl}";
                Console.Out.WriteLine(message);
                _logger.LogVerbose(message);

                var initialUpdates = new UpdateOperation();
                initialUpdates.UpdateField(Book.kHarvestStateField, Book.HarvestState.InProgress.ToString());
                initialUpdates.UpdateField(Book.kHarvesterIdField, this.Identifier);

                var startTime = new Parse.Model.Date(DateTime.UtcNow);
                initialUpdates.UpdateField("harvestStartedAt", startTime.ToJson());

                _parseClient.UpdateObject(book.GetParseClassName(), book.ObjectId, initialUpdates.ToJson());

                // Download the book
                _logger.TrackEvent("Download Book");
                string decodedUrl      = HttpUtility.UrlDecode(book.BaseUrl);
                string urlWithoutTitle = RemoveBookTitleFromBaseUrl(decodedUrl);
                string downloadRootDir = Path.Combine(Path.GetTempPath(), Path.Combine("BloomHarvester", this.Identifier));
                _logger.LogVerbose("Download Dir: {0}", downloadRootDir);
                string downloadBookDir = _transfer.HandleDownloadWithoutProgress(urlWithoutTitle, downloadRootDir);

                // Process the book
                var finalUpdates = new UpdateOperation();
                var warnings     = FindBookWarnings(book);
                finalUpdates.UpdateField(Book.kWarningsField, Book.ToJson(warnings));

                // ENHANCE: Do more processing here
                _logger.TrackEvent("Upload Book");

                UploadBook(decodedUrl, downloadBookDir);

                // Write the updates
                finalUpdates.UpdateField(Book.kHarvestStateField, Book.HarvestState.Done.ToString());
                _parseClient.UpdateObject(book.GetParseClassName(), book.ObjectId, finalUpdates.ToJson());

                _logger.TrackEvent("ProcessOneBook End - Success");
            }
            catch (Exception e)
            {
                YouTrackIssueConnector.SubmitToYouTrack(e, $"Unhandled exception thrown while processing book \"{book.BaseUrl}\"");

                // Attempt to write to Parse that processing failed
                if (!String.IsNullOrEmpty(book?.ObjectId))
                {
                    try
                    {
                        var onErrorUpdates = new UpdateOperation();
                        onErrorUpdates.UpdateField(Book.kHarvestStateField, $"\"{Book.HarvestState.Failed.ToString()}\"");
                        onErrorUpdates.UpdateField(Book.kHarvesterIdField, this.Identifier);
                        _parseClient.UpdateObject(book.GetParseClassName(), book.ObjectId, onErrorUpdates.ToJson());
                    }
                    catch (Exception)
                    {
                        // If it fails, just let it be and throw the first exception rather than the nested exception.
                    }
                }
                throw;
            }
        }