From b4a78335e15924582ddb244fcdc761ed756cf3ee Mon Sep 17 00:00:00 2001 From: "odippel@ypsilon.net" Date: Tue, 18 Aug 2026 11:19:37 +0200 Subject: [PATCH] adding optional user pages / html files --- docs/src/man/man1/mtconnect-agent.1.adoc | 1 + lib/python/mtc/agent.py | 14 ++++++++++++++ lib/python/mtc/http_agent.py | 8 ++++++++ 3 files changed, 23 insertions(+) diff --git a/docs/src/man/man1/mtconnect-agent.1.adoc b/docs/src/man/man1/mtconnect-agent.1.adoc index 22daa5fb126..8be084caaf3 100644 --- a/docs/src/man/man1/mtconnect-agent.1.adoc +++ b/docs/src/man/man1/mtconnect-agent.1.adoc @@ -64,6 +64,7 @@ All configuration is read from the *[MTCONNECT]* section: *TRANSPORT*:: Comma-separated list of *http*, *mqtt*, *shdr* (default *http*). *HTTP_PORT*:: Embedded HTTP agent port (default 5000). *HTTP_BIND*:: Interface to bind (default 127.0.0.1; use 0.0.0.0 for the LAN). +*USER_PAGES*:: Path to optional user pages / html files. *SHDR_PORT*:: Port for the SHDR adapter when *shdr* is in *TRANSPORT* (default 7878). SHDR feeds an external MTConnect agent (e.g. cppagent) `|id|value` lines; configure that agent with a Devices.xml from *--dump-probe*. diff --git a/lib/python/mtc/agent.py b/lib/python/mtc/agent.py index 16a17885518..bf0ad0bbd18 100644 --- a/lib/python/mtc/agent.py +++ b/lib/python/mtc/agent.py @@ -68,6 +68,10 @@ def __init__(self, ini_path, buffer_size=131072): self._last_in_spindle = None self._last_values = {} self._lock = threading.Lock() + self.user_pages = self.ini.find("MTCONNECT", "USER_PAGES", "") + if self.user_pages and self.user_pages[0] != "/": + # use relativ path + self.user_pages = os.path.join(os.path.dirname(ini_path), self.user_pages) # -- data collection ----------------------------------------------------- @@ -112,6 +116,16 @@ def extension_schema(self): with open(path, "rb") as fh: return fh.read(), "application/xml" + def user_page(self, name): + """Return (bytes, content_type) for a served user file, or None.""" + if not self.user_pages: + return None + path = os.path.realpath(os.path.join(self.user_pages, name)) + if path.startswith(self.user_pages) and os.path.isfile(path): + with open(path, "r") as fh: + return fh.read(), "text/html" + return None + def model_file(self, name): """Return (bytes, content_type) for a served mesh, or None.""" ref = self.models.served.get(name) diff --git a/lib/python/mtc/http_agent.py b/lib/python/mtc/http_agent.py index 0e5e8f2fea2..df1dc75fd54 100644 --- a/lib/python/mtc/http_agent.py +++ b/lib/python/mtc/http_agent.py @@ -96,6 +96,14 @@ def do_GET(self): else: data, content_type = result self._send(data, content_type=content_type) + elif route.startswith(f"/html/"): + result = agent.user_page(route[len("/html/"):]) + if result is None: + self._send(_error_document("NOT_FOUND", + "no such file: %s" % route), status=404) + else: + data, content_type = result + self._send(data, content_type=content_type) else: self._send(_error_document("UNSUPPORTED", "unsupported request: %s" % route), status=404)