private SimulatedPageFile MakeFinalHtmlForPdfMaker() { if (_currentlyLoadedBook == null) { _currentlyLoadedBook = BookSelection.CurrentSelection; } PdfFilePath = GetPdfPath(Path.GetFileName(_currentlyLoadedBook.FolderPath)); var orientationChanging = BookSelection.CurrentSelection.GetLayout().SizeAndOrientation.IsLandScape != PageLayout.SizeAndOrientation.IsLandScape; var dom = BookSelection.CurrentSelection.GetDomForPrinting(BookletPortion, _currentBookCollectionSelection.CurrentSelection, _bookServer, orientationChanging, PageLayout); AddStylesheetClasses(dom.RawDom); PageLayout.UpdatePageSplitMode(dom.RawDom); if (_currentlyLoadedBook.FullBleed && !GetPrintingWithFullBleed()) { ClipBookToRemoveFullBleed(dom); } XmlHtmlConverter.MakeXmlishTagsSafeForInterpretationAsHtml(dom.RawDom); dom.UseOriginalImages = true; // don't want low-res images or transparency in PDF. return(BloomServer.MakeSimulatedPageFileInBookFolder(dom, source: BloomServer.SimulatedPageFileSource.Pub)); }
public ProjectContext(string projectSettingsPath, IContainer parentContainer) { BuildSubContainerForThisProject(projectSettingsPath, parentContainer); ProjectWindow = _scope.Resolve <Shell>(); string collectionDirectory = Path.GetDirectoryName(projectSettingsPath); //should we save a link to this in the list of collections? var collectionSettings = _scope.Resolve <CollectionSettings>(); if (collectionSettings.IsSourceCollection) { AddShortCutInComputersBloomCollections(collectionDirectory); } if (Path.GetFileNameWithoutExtension(projectSettingsPath).ToLower().Contains("web")) { BookCollection editableCollection = _scope.Resolve <BookCollection.Factory>()(collectionDirectory, BookCollection.CollectionType.TheOneEditableCollection); var sourceCollectionsList = _scope.Resolve <SourceCollectionsList>(); _bloomServer = new BloomServer(_scope.Resolve <CollectionSettings>(), editableCollection, sourceCollectionsList, _scope.Resolve <HtmlThumbNailer>()); _bloomServer.Start(); } else { if (Settings.Default.ImageHandler != "off") { _imageServer = _scope.Resolve <ImageServer>(); _imageServer.StartWithSetupIfNeeded(); } } }
internal static BloomServer GetTestServer() { var server = new BloomServer(new RuntimeImageProcessor(new BookRenamedEvent()), GetTestBookSelection(), s_collectionSettings, GetTestFileLocator()); server.StartListening(); return(server); }
public void CanRetrieveContentOfFakeTempFile_ButOnlyUntilDisposed() { using (var server = CreateBloomServer()) { var html = @"<html ><head></head><body>here it is</body></html>"; var dom = new HtmlDom(html); dom.BaseForRelativePaths = _folder.Path.ToLocalhost(); string url; using (var fakeTempFile = BloomServer.MakeSimulatedPageFileInBookFolder(dom)) { url = fakeTempFile.Key; var transaction = new PretendRequestInfo(url); // Execute server.MakeReply(transaction); // Verify // Whitespace inserted by CreateHtml5StringFromXml seems to vary across versions and platforms. // I would rather verify the actual output, but don't want this test to be fragile, and the // main point is that we get a file with the DOM content. Assert.That(transaction.ReplyContents, Is.EqualTo(dom.getHtmlStringDisplayOnly())); } server.DoIdleTasksIfNoActivity(); var transactionFail = new PretendRequestInfo(url); // Execute server.MakeReply(transactionFail); // Verify Assert.That(transactionFail.StatusCode, Is.EqualTo(404)); } }
public void Setup() { // as long as we're only using one, fixed port number, we need to prevent unit test runner // from running these tests in parallel. Monitor.Enter(_portMonitor); _server = new BloomServer(new BookSelection()); }
public static string GetString(BloomServer server, string endPoint, string query = "", ContentType returnType = ContentType.Text, EndpointHandler handler = null, string endOfUrlForTest = null) { if (handler != null) { server.ApiHandler.RegisterEndpointHandler(endPoint, handler, true); } server.StartListening(); var client = new WebClientWithTimeout { Timeout = 3000, }; client.Headers[HttpRequestHeader.ContentType] = returnType == ContentType.Text ? "text/plain" : "application/json"; if (endOfUrlForTest != null) { return(client.DownloadString(BloomServer.ServerUrlWithBloomPrefixEndingInSlash + "api/" + endOfUrlForTest)); } else { if (!string.IsNullOrEmpty(query)) { query = "?" + query; } return(client.DownloadString(BloomServer.ServerUrlWithBloomPrefixEndingInSlash + "api/" + endPoint + query)); } }
/// <summary> /// Sets up the Bloom server and registers the Problem Report API handler to it /// </summary> private void SetupApiHandler(BookSelection bookSelection) { _server = new BloomServer(bookSelection); var controller = new ProblemReportApi(bookSelection); controller.RegisterWithApiHandler(_server.ApiHandler); }
public void TearDown() { if (_server != null) { _server.Dispose(); _server = null; } }
private static string AdjustPossibleLocalHostPathToFilePath(string path) { if (!path.StartsWith("localhost/", StringComparison.InvariantCulture)) { return(path); } return(BloomServer.LocalHostPathToFilePath(path)); }
public void Setup() { _bookSelection = new BookSelection(); _bookSelection.SelectBook(new Bloom.Book.Book()); _server = new BloomServer(_bookSelection); var controller = new ReadersApi(_bookSelection, null); controller.RegisterWithApiHandler(_server.ApiHandler); }
public void InitialSetup() { var bookSelection = new BookSelection(); bookSelection.SelectBook(new Bloom.Book.Book()); _server = new BloomServer(bookSelection); var controller = new FileIOApi(bookSelection); controller.RegisterWithApiHandler(_server.ApiHandler); }
public void ServerKnowsDifferenceBetweenRealAndThumbVideos(BloomServer.SimulatedPageFileSource source, bool expectVideo) { using (var server = CreateBloomServer()) { const string html = @"<html ><head></head><body> <div class='bloom-page'> <div id='1' class='bloom-videoContainer bloom-noVideoSelected bloom-leadingElement bloom-selected'> <video> <source src='video/randommp4filename.mp4#t=0.0,4.6'> </source> </video> </div> <div class='otherStuff'> </div> <div id='2' class='bloom-videoContainer'> <video> <source src='video/otherrandomfilename.mp4'> </source> </video> </div> <div id='3' class='bloom-videoContainer bloom-noVideoSelected bloom-leadingElement bloom-selected'> </div> </div> <div class='afterStuff'> </div> </body></html>" ; var dom = new HtmlDom(html) { BaseForRelativePaths = _folder.Path.ToLocalhost() }; using (var fakeTempFile = BloomServer.MakeSimulatedPageFileInBookFolder(dom, true, true, source)) { var url = fakeTempFile.Key; var transaction = new PretendRequestInfo(url); // Execute server.MakeReply(transaction); // Verify var contents = transaction.ReplyContents; if (expectVideo) { AssertThatXmlIn.String(contents).HasSpecifiedNumberOfMatchesForXpath("//div[contains(@class,'bloom-videoContainer')]", 3); AssertThatXmlIn.String(contents).HasNoMatchForXpath("//div[contains(@class,'bloom-imageContainer')]"); } else { AssertThatXmlIn.String(contents).HasSpecifiedNumberOfMatchesForXpath("//div[contains(@class,'bloom-imageContainer')]", 3); AssertThatXmlIn.String(contents).HasNoMatchForXpath("//div[contains(@class,'bloom-videoContainer')]"); } } } }
/// ------------------------------------------------------------------------------------ public void Dispose() { _scope.Dispose(); _scope = null; if (_bloomServer != null) { _bloomServer.Dispose(); } _bloomServer = null; if (_imageServer != null) { _imageServer.Dispose(); } _imageServer = null; }
public static string PostString(BloomServer server, string endPoint, string data, ContentType returnType, EndpointHandler handler = null) { if (handler != null) { server.ApiHandler.RegisterEndpointHandler(endPoint, handler, true); } server.StartListening(); var client = new WebClientWithTimeout { Timeout = 3000 }; client.Headers[HttpRequestHeader.ContentType] = returnType == ContentType.Text ? "text/plain" : "application/json"; return(client.UploadString(BloomServer.ServerUrlWithBloomPrefixEndingInSlash + "api/" + endPoint, "POST", data)); }
private PretendRequestInfo CreateServerMakeSimPageMakeReply(HtmlDom dom, bool simulateCallingFromJavascript = false) { PretendRequestInfo transaction; using (var server = CreateBloomServer()) { using (var fakeTempFile = BloomServer.MakeSimulatedPageFileInBookFolder(dom, simulateCallingFromJavascript)) { var url = fakeTempFile.Key; transaction = new PretendRequestInfo(url, forPrinting: false, forSrcAttr: simulateCallingFromJavascript); // Execute server.MakeReply(transaction); } } return(transaction); }
private void ShowBook(bool updatePreview = true) { if (_bookSelection.CurrentSelection == null || !_visible) { HidePreview(); } else { Debug.WriteLine("LibraryBookView.ShowBook() currentselection ok"); _readmeBrowser.Visible = false; _splitContainerForPreviewAndAboutBrowsers.Visible = true; if (updatePreview && !TroubleShooterDialog.SuppressBookPreview) { var previewDom = _bookSelection.CurrentSelection.GetPreviewHtmlFileForWholeBook(); XmlHtmlConverter.MakeXmlishTagsSafeForInterpretationAsHtml(previewDom.RawDom); var fakeTempFile = BloomServer.MakeSimulatedPageFileInBookFolder(previewDom, setAsCurrentPageForDebugging: false, source: BloomServer.SimulatedPageFileSource.Preview); _reactBookPreviewControl.Props = new { initialBookPreviewUrl = fakeTempFile.Key }; // need this for initial selection _webSocketServer.SendString("bookStatus", "changeBook", fakeTempFile.Key); // need this for changing selection display _webSocketServer.SendEvent("bookStatus", "reload"); // need this for changing selection's book info display if team collection _reactBookPreviewControl.Visible = true; RecordAndCleanupFakeFiles(fakeTempFile); } _splitContainerForPreviewAndAboutBrowsers.Panel2Collapsed = true; if (_bookSelection.CurrentSelection.HasAboutBookInformationToShow) { if (RobustFile.Exists(_bookSelection.CurrentSelection.AboutBookHtmlPath)) { _splitContainerForPreviewAndAboutBrowsers.Panel2Collapsed = false; _readmeBrowser.Navigate(_bookSelection.CurrentSelection.AboutBookHtmlPath, false); _readmeBrowser.Visible = true; } else if (RobustFile.Exists(_bookSelection.CurrentSelection.AboutBookMdPath)) { _splitContainerForPreviewAndAboutBrowsers.Panel2Collapsed = false; var md = new Markdown(); var contents = RobustFile.ReadAllText(_bookSelection.CurrentSelection.AboutBookMdPath); _readmeBrowser.NavigateRawHtml(string.Format("<html><head><meta charset=\"utf-8\"/></head><body>{0}</body></html>", md.Transform(contents))); _readmeBrowser.Visible = true; } } _reshowPending = false; } }
public void OneTimeSetUp() { _server = new BloomServer(new BookSelection()); }
public void Teardown() { _server.Dispose(); _server = null; Monitor.Exit(_portMonitor); }
/// <summary> /// Returns true if it make some attempt at an image, false if navigation is currently suppressed. /// </summary> /// <param name="order"></param> /// <param name="browser"></param> /// <param name="thumbnail"></param> /// <returns></returns> private bool CreateThumbNail(ThumbnailOrder order, GeckoWebBrowser browser, out Image thumbnail) { // runs on threadpool thread _currentOrder = order; thumbnail = null; using (var temp = BloomServer.MakeSimulatedPageFileInBookFolder(order.Document, source: BloomServer.SimulatedPageFileSource.Thumb)) { order.Done = false; browser.Tag = order; Color coverColor; ImageUtils.TryCssColorFromString(Book.Book.GetCoverColorFromDom(order.Document.RawDom), out coverColor); if (!OpenTempFileInBrowser(browser, temp.Key)) { return(false); } var browserSize = SetWidthAndHeight(browser); if (browserSize.Height == 0) //happens when we run into the as-yet-unreproduced-or-fixed bl-254 { return(false); // will try again later } try { Logger.WriteMinorEvent("HtmlThumNailer ({2}): browser.GetBitmap({0},{1})", browserSize.Width, (uint)browserSize.Height, Thread.CurrentThread.ManagedThreadId); //BUG (April 2013) found that the initial call to GetBitMap always had a zero width, leading to an exception which //the user doesn't see and then all is well. So at the moment, we avoid the exception, and just leave with //the placeholder thumbnail. if (browserSize.Width == 0 || browserSize.Height == 0) { var paperSizeName = GetPaperSizeName(order.Document.RawDom); throw new ApplicationException("Problem getting thumbnail browser for document with Paper Size: " + paperSizeName); } int topOfCoverImage = -1; int bottomOfCoverImage = -1; _syncControl.Invoke((Action)(() => { Guard.AgainstNull(browser.Document.ActiveElement, "browser.Document.ActiveElement"); var div = browser.Document.ActiveElement.EvaluateXPath("//div[contains(@class, 'bloom-imageContainer')]").GetNodes().FirstOrDefault() as GeckoHtmlElement; if (div != null) { // Note that div.GetBoundingClientRect() returns nothing useful in Geckofx60: these values appear to work okay. topOfCoverImage = div.OffsetTop; bottomOfCoverImage = topOfCoverImage + div.OffsetHeight; } })); using (Image fullsizeImage = CreateImage(browser, coverColor, topOfCoverImage, bottomOfCoverImage)) { if (_disposed) { return(false); } thumbnail = MakeThumbNail(fullsizeImage, order.Options); return(true); } } catch (Exception error) { Logger.WriteEvent("HtmlThumbNailer ({0}) got {1}", Thread.CurrentThread.ManagedThreadId, error.Message); Logger.WriteEvent("Disposing of all browsers in hopes of getting a fresh start on life"); foreach (var browserCacheForDifferentPaperSize in _browserCacheForDifferentPaperSizes) { try { Logger.WriteEvent("Disposing of browser {0}", browserCacheForDifferentPaperSize.Key); browserCacheForDifferentPaperSize.Value.Dispose(); } catch (Exception e2) { Logger.WriteEvent( "While trying to dispose of thumbnailer browsers as a result of an exception, go another: " + e2.Message); } } _browserCacheForDifferentPaperSizes.Clear(); #if DEBUG _syncControl.Invoke((Action)(() => Debug.Fail(error.Message))); #endif } } return(false); }
public virtual void OneTimeSetup() { s_collectionSettings = new CollectionSettings(); s_testServer = GetTestServer(); }
public void OneTimeTearDown() { _server?.Dispose(); _server = null; }
private void ShowNotifyDialog(string severity, string messageText, Exception exception, string reportButtonLabel, string secondaryButtonLabel) { // Before we do anything that might be "risky", put the problem in the log. ProblemReportApi.LogProblem(exception, messageText, severity); // ENHANCE: Allow the caller to pass in the control, which would be at the front of this. //System.Windows.Forms.Control control = Form.ActiveForm ?? FatalExceptionHandler.ControlOnUIThread; var control = GetControlToUse(); var isSyncRequired = false; SafeInvoke.InvokeIfPossible("Show Error Reporter", control, isSyncRequired, () => { // Uses a browser dialog to show the problem report try { StartupScreenManager.CloseSplashScreen(); // if it's still up, it'll be on top of the dialog var message = GetMessage(messageText, exception); if (!Api.BloomServer.ServerIsListening) { // There's no hope of using the HtmlErrorReporter dialog if our server is not yet running. // We'll likely get errors, maybe Javascript alerts, that won't lead to a clean fallback to // the exception handler below. Besides, failure of HtmlErrorReporter in these circumstances // is expected; we just want to cleanly report the original problem, not to report a // failure of error handling. // Note: HtmlErrorReporter supports up to 3 buttons (OK, Report, and [Secondary action]), but the fallback reporter only supports a max of two. // Well, just going to have to drop the secondary action. ShowFallbackProblemDialog(severity, exception, messageText, null, false); return; } object props = new { level = ProblemLevel.kNotify, reportLabel = reportButtonLabel, secondaryLabel = secondaryButtonLabel, message = message }; // Precondition: we must be on the UI thread for Gecko to work. using (var dlg = BrowserDialogFactory.CreateReactDialog("problemReportBundle", props)) { dlg.FormBorderStyle = FormBorderStyle.FixedToolWindow; // Allows the window to be dragged around dlg.ControlBox = true; // Add controls like the X button back to the top bar dlg.Text = ""; // Remove the title from the WinForms top bar dlg.Width = 620; // 360px was experimentally determined as what was needed for the longest known text for NotifyUserOfProblem // (which is "Before saving, Bloom did an integrity check of your book [...]" from BookStorage.cs) // You can make this height taller if need be. // A scrollbar will appear if the height is not tall enough for the text dlg.Height = 360; // ShowDialog will cause this thread to be blocked (because it spins up a modal) until the dialog is closed. BloomServer.RegisterThreadBlocking(); try { dlg.ShowDialog(); // Take action if the user clicked a button other than Close if (dlg.CloseSource == "closedByAlternateButton" && OnSecondaryActionPressed != null) { OnSecondaryActionPressed(exception, message); } else if (dlg.CloseSource == "closedByReportButton") { if (OnReportButtonPressed != null) { OnReportButtonPressed(exception, message); } else { DefaultOnReportPressed(exception, message); } } // Note: With the way LibPalaso's ErrorReport is designed, // its intention is that after OnShowDetails is invoked and closed, you will not come back to the Notify Dialog // This code has been implemented to follow that model // // But now that we have more options, it might be nice to come back to this dialog. // If so, you'd need to add/update some code in this section. } finally { ResetToDefaults(); BloomServer.RegisterThreadUnblocked(); } } } catch (Exception errorReporterException) { Logger.WriteError("*** HtmlErrorReporter threw an exception trying to display", errorReporterException); // At this point our problem reporter has failed for some reason, so we want the old WinForms handler // to report both the original error for which we tried to open our dialog and this new one where // the dialog itself failed. // In order to do that, we create a new exception with the original exception (if there was one) as the // inner exception. We include the message of the exception we just caught. Then we call the // old WinForms fatal exception report directly. // In any case, both of the errors will be logged by now. var message = "Bloom's error reporting failed: " + errorReporterException.Message; // Fallback to Winforms in case of trouble getting the browser to work var fallbackReporter = new WinFormsErrorReporter(); // Food for thought: is it really fatal of the Notify Dialog had an exception? Maybe NonFatal makes more sense fallbackReporter.ReportFatalException(new ApplicationException(message, exception ?? errorReporterException)); } }); }