Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ dependencies = [
"WebSockets",

# HTML2PDF dependencies
"html2pdf4doc >= 0.0.23",
"html2pdf4doc >= 0.0.24",

# Robot Framework dependencies
"robotframework >= 4.0.0",
Expand Down
48 changes: 44 additions & 4 deletions strictdoc/export/html2pdf/pdf_print_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,53 @@
"""

import os.path
from subprocess import CompletedProcess, TimeoutExpired, run
from subprocess import CalledProcessError, CompletedProcess, TimeoutExpired, run
from typing import List, Tuple

from html2pdf4doc.main import HPDExitCode

from strictdoc.core.project_config import ProjectConfig
from strictdoc.helpers.timing import measure_performance


class PDFPrintDriverException(Exception):
def __init__(self, exception: Exception):
super().__init__()
self.exception: Exception = exception

def get_server_user_message(self) -> str:
"""
Provide a user-friendly message that describes the underlying exception/error.
"""

if self.is_could_not_detect_chrome():
return "HTML2PDF could not detect an existing Chrome installation."

if self.is_timeout_error():
return "HTML2PDF timeout error."

if self.is_js_success_timeout():
return "HTML2PDF.js success timeout error."

return "HTML2PDF internal error."

def is_timeout_error(self) -> bool:
return isinstance(self.exception, TimeoutExpired)

def is_could_not_detect_chrome(self) -> bool:
return (
isinstance(self.exception, CalledProcessError)
and self.exception.returncode == HPDExitCode.COULD_NOT_FIND_CHROME
)

def is_js_success_timeout(self) -> bool:
return (
isinstance(self.exception, CalledProcessError)
and self.exception.returncode
== HPDExitCode.DID_NOT_RECEIVE_SUCCESS_STATUS_FROM_HTML2PDF4DOC_JS
)


class PDFPrintDriver:
@staticmethod
def get_pdf_from_html(
Expand Down Expand Up @@ -52,7 +92,7 @@ def get_pdf_from_html(
_: CompletedProcess[bytes] = run(
cmd,
capture_output=False,
check=False,
check=True,
)
except TimeoutExpired:
raise TimeoutError from None
except Exception as e_:
raise PDFPrintDriverException(e_) from e_
16 changes: 11 additions & 5 deletions strictdoc/server/routers/main_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,10 @@
from strictdoc.export.html.html_templates import HTMLTemplates, JinjaEnvironment
from strictdoc.export.html.renderers.link_renderer import LinkRenderer
from strictdoc.export.html.renderers.markup_renderer import MarkupRenderer
from strictdoc.export.html2pdf.pdf_print_driver import PDFPrintDriver
from strictdoc.export.html2pdf.pdf_print_driver import (
PDFPrintDriver,
PDFPrintDriverException,
)
from strictdoc.export.json.json_generator import JSONGenerator
from strictdoc.helpers.cast import assert_cast
from strictdoc.helpers.file_modification_time import (
Expand All @@ -134,7 +137,7 @@

HTTP_STATUS_BAD_REQUEST = 400
HTTP_STATUS_PRECONDITION_FAILED = 412
HTTP_STATUS_GATEWAY_TIMEOUT = 504
HTTP_STATUS_INTERNAL_SERVER_ERROR = 500

AUTOCOMPLETE_LIMIT = 50

Expand Down Expand Up @@ -2148,6 +2151,9 @@ def get_export_html2pdf(document_mid: str) -> Response: # noqa: ARG001
path_to_output_pdf = os.path.join(
project_config.export_output_html_root, "html", "_temp.pdf"
)

# FIXME: Add this print driver to a service bus object to make it
# unit-testable.
pdf_print_driver = PDFPrintDriver()
with open(path_to_output_html, mode="w", encoding="utf8") as temp_file_:
temp_file_.write(document_content)
Expand All @@ -2158,10 +2164,10 @@ def get_export_html2pdf(document_mid: str) -> Response: # noqa: ARG001
project_config,
[(path_to_output_html, path_to_output_pdf)],
)
except TimeoutError: # pragma: no cover
except PDFPrintDriverException as e_: # pragma: no cover
return Response(
content="HTML2PDF timeout error.",
status_code=HTTP_STATUS_GATEWAY_TIMEOUT,
content=e_.get_server_user_message(),
status_code=HTTP_STATUS_INTERNAL_SERVER_ERROR,
)

return FileResponse(
Expand Down