private async Task DownloadBookAsync(BookDataContext bookdb, BookData book, FilenameAndFormatData file) { Uri uri; var fileName = FileWizards.UriWizard.FixupUrl(file.FileName); var status = Uri.TryCreate(fileName, UriKind.Absolute, out uri); if (!status) { var md = new MessageDialog($"Internal error: {fileName} is invalid") { Title = "Can't download file", }; await md.ShowAsync(); return; } // Uri is e.g. http://www.gutenberg.org/ebooks/14.epub.noimages var folder = await FolderMethods.EnsureDownloadFolder(); var(outfilename, ext) = FileWizards.UriWizard.GetUriFilename(uri); var preferredFilename = book.GetBestTitleForFilename() + ext; var collisionOption = PCLStorage.CreationCollisionOption.FailIfExists; var exists = await folder.CheckExistsAsync(preferredFilename); if (exists == PCLStorage.ExistenceCheckResult.FileExists) { var md = new ContentDialog() { Content = $"Already downloaded file {preferredFilename}", Title = "File exists", PrimaryButtonText = "Skip", SecondaryButtonText = "Delete existing file", }; var command = await md.ShowAsync(); switch (command) { case ContentDialogResult.Primary: return; case ContentDialogResult.Secondary: collisionOption = PCLStorage.CreationCollisionOption.ReplaceExisting; break; } } PCLStorage.IFile outfile; try { outfile = await folder.CreateFileAsync(preferredFilename, collisionOption); } catch (Exception ex) { var md = new MessageDialog($"Already downloaded file {preferredFilename} {ex.Message}") { Title = "File already exists", }; await md.ShowAsync(); return; } // Just do a quick download.... try { EnableDownloadProgressPanel(true); uiDownloadButton.Visibility = Visibility.Collapsed; uiCancelDownloadButton.Visibility = Visibility.Visible; cts = new CancellationTokenSource(); ulong totalLength = 0; uiDownloadProgress.IsIndeterminate = true; uiDownloadProgress.ShowError = false; var getTask = hc.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead); #if NEVER_EVER_DEFINED getTask.Progress += async(response, progress) => { await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { if (totalLength == 0 && progress.TotalBytesToReceive.HasValue && progress.TotalBytesToReceive.Value > 0) { // Now we know how many bytes we will get! uiDownloadProgress.IsIndeterminate = false; uiDownloadProgress.Minimum = 0; uiDownloadProgress.Maximum = progress.TotalBytesToReceive.Value; uiDownloadProgress.Value = 0; totalLength = progress.TotalBytesToReceive.Value; } if (progress.BytesReceived > 0) { uiDownloadProgress.Value = progress.BytesReceived; } NotifyUser($"GET Progress: stage {progress.Stage} bytes={progress.BytesReceived} of {progress.TotalBytesToReceive}"); }); }; #endif // Get some level of progress.... var responseMessage = await getTask; var contentLengthHeader = responseMessage.Content.Headers.ContentLength; if (totalLength == 0 && contentLengthHeader.HasValue && contentLengthHeader.Value > 0) { // Now we know how many bytes we will get! uiDownloadProgress.IsIndeterminate = false; uiDownloadProgress.Minimum = 0; uiDownloadProgress.Maximum = contentLengthHeader.Value; uiDownloadProgress.Value = 0; totalLength = (ulong)contentLengthHeader.Value; } NotifyUser($"GET Progress: stage Got Headers"); var stream = await responseMessage.Content.ReadAsStreamAsync(); // gest entire buffer at once. byte[] tbuffer = new byte[8 * 1024]; List <byte> buffer = new List <byte>(); int nbytes = 0; int progress = 0; while ((nbytes = await stream.ReadAsync(tbuffer, 0, tbuffer.Length)) > 0) { for (int i = 0; i < nbytes; i++) { buffer.Add(tbuffer[i]); } await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { progress += nbytes; uiDownloadProgress.Value = progress; NotifyUser($"GET Progress: bytes={progress} of {totalLength}\n"); }); } //var buffer = await bufferTask.AsTask(cts.Token); uiDownloadProgress.Value = buffer.Count; bool isOk = responseMessage.IsSuccessStatusCode; if (isOk) { NotifyUser($"GET complete with {buffer.Count} bytes"); if (buffer.Count > 2000) { uiDownloadFinished.Visibility = Visibility.Visible; uiDownloadFinishedShowButton.Visibility = Visibility.Collapsed; await outfile.WriteBytesAsync(buffer); CommonQueries.DownloadedBookEnsureFileMarkedAsDownloaded(bookdb, book.BookId, folder.Path, outfile.Name); uiDownloadFinishedShowButton.Visibility = Visibility.Visible; } else { var md = new MessageDialog($"Download file error -- too small") { Title = "Corrupt downloaded file", }; await md.ShowAsync(); } NotifyUser($"Download complete -- file size {buffer.Count} bytes"); } else { NotifyUser($"Failed to download file; error {responseMessage.ReasonPhrase} length {buffer.Count}"); uiDownloadFinished.Visibility = Visibility.Visible; uiDownloadFinishedShowButton.Visibility = Visibility.Collapsed; } uiDownloadProgress.IsIndeterminate = false; uiDownloadProgress.Value = 0; EnableDownloadProgressPanel(false); } catch (Exception ex) { NotifyUser($"Unable to download file because {ex.Message}"); await outfile.DeleteAsync(); uiDownloadProgress.IsIndeterminate = false; uiDownloadProgress.ShowError = true; EnableDownloadProgressPanel(false); } finally { uiDownloadButton.Visibility = Visibility.Visible; uiCancelDownloadButton.Visibility = Visibility.Collapsed; } }
private static async Task <BookData> InsertFileIntoDatabase(BookDataContext bookdb, IFolder folder, string filename, bool getFullData = false) { BookData bookData = null; if (bookdb == null) { bookdb = BookDataContext.Get(); } string fullfname = $"{folder.Path}\\{filename}"; var wd = new WizardData() { FilePath = fullfname, FileName = filename }; try { wd = await GutenbergFileWizard.GetDataAsync(wd, getFullData); if (!string.IsNullOrEmpty(wd.BookId)) { bookData = CommonQueries.BookGet(bookdb, wd.BookId); //TODO: when I drop a book that's been added to the database because it was // in a bookmark file (which should happen reasonably often!) // then the bookData here is non-null, but also not really filled in well. if (bookData == null || bookData.BookSource.StartsWith(BookData.BookSourceBookMarkFile)) { if (wd.BD != null) { // Gotcha! Add to the main book database! if (!string.IsNullOrEmpty(wd.BD.BookId)) { wd.BD.Files.Add(new FilenameAndFormatData() { FileName = filename, BookId = wd.BookId, MimeType = "application/epub+zip" }); wd.BD.BookSource = BookData.BookSourceUser; // Add in possible data from the bookData set by the user if (bookData != null) { wd.BD.NavigationData = bookData.NavigationData; wd.BD.Review = bookData.Review; wd.BD.Notes = bookData.Notes; //TODO: now get this book into the database. // via some kind of merge?? } else { CommonQueries.BookAdd(bookdb, wd.BD, CommonQueries.ExistHandling.IfNotExists); CommonQueries.BookSaveChanges(bookdb); bookData = wd.BD; } } else { App.Error($"ERROR: {filename} ({wd.BookId}) was unable to wizard read and get ID"); } } else { App.Error($"ERROR: {filename} ({wd.BookId}) was unable to wizard read"); } } else { System.Diagnostics.Debug.WriteLine($"{filename}({wd.BookId}) is {bookData.GetBestTitleForFilename()}"); } var fullpath = folder.Path; if (fullpath.Contains(@"AppX\Assets\PreinstalledBooks")) { // Whoops. The initial database might incorrectly have a developer path hard-coded. // Replace with correct location. fullpath = $"PreinstalledBooks:"; } CommonQueries.DownloadedBookEnsureFileMarkedAsDownloaded(bookdb, wd.BookId, fullpath, filename); } else { App.Error($"{filename} with id {wd.BookId} is not a known type of e-book"); } } catch (Exception) { App.Error($"{filename} is not a readable e-book"); } return(bookData); }