Files
MeshCore/scripts/generate_room_web_html.py
T
mikecarper 21194b9825 Fix compile and capacity blockers in the full release matrix
Resolve Serial macro and ESP-NOW wrapper compilation errors. Preserve queue, neighbor, advert-history and Room post capacities while using qualified RTC, PSRAM and word-only IRAM storage on constrained ESP32 targets. Reduce Full infrastructure flash through lossless Room web compression, compact crypto and unused exception metadata removal.

Add focused native regressions for storage ownership, exact protocol output, OTA proofs and build policy. Keep physical flash sizes, OTA slots and RAM guard formulas unchanged.
2026-10-24 05:38:23 -07:00

94 lines
3.2 KiB
Python

#!/usr/bin/env python3
"""Losslessly package the Room Server page for browser gzip decoding.
RoomWebHtml.h remains the reviewed page source and native UI fixture. Only
Room Server's ESP32 WebConfig callback references the compressed asset. Other
roles and nRF52 builds do not include either page in their firmware.
"""
from __future__ import annotations
import argparse
import gzip
import hashlib
from pathlib import Path
import re
import zlib
SOURCE = "src/helpers/esp32/RoomWebHtml.h"
OUTPUT = "src/helpers/esp32/RoomWebHtmlGzip.h"
MARKER = "// room-page-source-sha256: "
def source_page(header: str) -> bytes:
matches = re.findall(
r'static const char ROOM_WEB_HTML\[\] PROGMEM = R"roomhtml\(([\s\S]*?)\)roomhtml";',
header,
)
if len(matches) != 1:
raise ValueError("expected one RoomWebHtml.h page source")
return matches[0].encode("ascii")
def page_bytes(header: str) -> bytes:
matches = re.findall(
r"static const uint8_t ROOM_WEB_HTML_GZ\[\] PROGMEM = \{([\s\S]*?)\};", header
)
if len(matches) != 1:
raise ValueError("expected one compressed Room page")
return bytes(int(value, 16) for value in re.findall(r"0x([0-9a-f]{2})", matches[0]))
def render(raw: bytes, encoded: bytes) -> str:
if gzip.decompress(encoded) != raw:
raise ValueError("compressed Room page differs from source")
digest = hashlib.sha256(raw).hexdigest()
lines = [
"// Auto-generated by scripts/generate_room_web_html.py; DO NOT EDIT.",
"// Lossless gzip of RoomWebHtml.h, decoded by the browser.",
MARKER + digest,
"#pragma once",
"#include <stdint.h>",
"#include <pgmspace.h>",
"",
"static const uint8_t ROOM_WEB_HTML_GZ[] PROGMEM = {",
]
for index in range(0, len(encoded), 16):
lines.append(" " + "".join("0x%02x," % value for value in encoded[index:index + 16]))
lines.extend(["};", ""])
return "\n".join(lines)
def generate(root: Path, *, check: bool = False) -> bool:
raw = source_page((root / SOURCE).read_text(encoding="ascii"))
destination = root / OUTPUT
existing = destination.read_text(encoding="ascii") if destination.exists() else ""
# Validate the actual bytes rather than trusting a marker or file mtime.
try:
encoded = page_bytes(existing)
intact = gzip.decompress(encoded) == raw and render(raw, encoded) == existing
except (ValueError, OSError, EOFError, zlib.error):
intact = False
if intact:
return False
if check:
raise ValueError("compressed Room page is missing, stale or invalid; regenerate it")
from zopfli_compress import gzip_compress
encoded = gzip_compress(raw)
destination.write_text(render(raw, encoded), encoding="ascii")
print("Room Web HTML: %d source bytes -> %d gzip bytes" % (len(raw), len(encoded)))
return True
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--check", action="store_true")
arguments = parser.parse_args()
root = Path(__file__).resolve().parents[1] if "__file__" in globals() else Path.cwd()
generate(root, check=arguments.check)
if __name__ == "__main__":
main()
elif "Import" in globals():
generate(Path.cwd())