Source code for bookbuilderpy.resources._resource_server

"""An internal web server for serving persistent resources."""
from http.server import BaseHTTPRequestHandler, HTTPServer
from importlib import resources  # nosem
from threading import Thread


def _get_file(name: str) -> bytes | None:
    """
    Get a file from the resource server.

    :param name: the file name
    :return: the file contents
    """
    if not name:
        return None

    while name[0] == "/":
        name = name[1:]
        if not name:
            return None

    i = name.rfind("?")
    if i >= 0:
        name = name[:i]
    i = name.rfind("#")
    if i >= 0:
        name = name[:i]
    i = name.rfind("/")
    if i >= 0:
        name = name[i + 1:]
    fn = name.strip()
    if not name:
        return None

    pack = str(__package__)
    if resources.is_resource(package=pack, name=fn):
        with resources.open_binary(package=pack,
                                   resource=fn) as stream:
            return stream.read()

    return None


class _SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
    """The internal server for obtaining resources."""

    # noinspection PyPep8Naming
    def do_GET(self) -> None:  # noqa
        """Get the resource."""
        # noinspection PyUnresolvedReferences
        res = _get_file(self.path)
        if res:
            self.send_response(200)
            self.end_headers()
            self.wfile.write(res)
        else:
            self.send_response(404)
            self.end_headers()


[docs]class ResourceServer: """The resource server.""" def __init__(self): """Initialize the server.""" self.__httpd = HTTPServer(("localhost", 0), _SimpleHTTPRequestHandler) self.__thread = Thread(target=self.__serve) def __serve(self) -> None: """Start the server and serve.""" self.__httpd.serve_forever()
[docs] def get_server(self) -> str: """ Get the server address. :return: the server address :rtype: str """ return f"http://localhost:{self.__httpd.socket.getsockname()[1]}/"
[docs] def get_mathjax_url(self) -> str: """ Get the mathjax url. :return: the mathjax url :rtype: str """ return f"{self.get_server()}mathjax.js"
def __enter__(self): """Start the resource server.""" self.__thread.start() return self def __exit__(self, exception_type, exception_value, traceback) -> bool: """ Close and exist the server. :param exception_type: ignored :param exception_value: ignored :param traceback: ignored :returns: `True` to suppress an exception, `False` to rethrow it """ self.__httpd.shutdown() del self.__httpd self.__thread.join() del self.__thread return exception_type is None