A fork of https://github.com/crosspoint-reader/crosspoint-reader
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: use pre-compressed HTML pages (#861)

## Summary

Pre-compress the HTML file to save flash space. I'm using `gzip` because
it's supported everywhere (indeed, we are using the same optimization on
[llama.cpp server](https://github.com/ggml-org/llama.cpp), our HTML page
is huge 😅 ).

This free up ~40KB flash space.

Some users suggested using `brotli` which is known to further reduce 20%
in size, but it doesn't supported by firefox (only supports if served
via HTTPS), and some reverse proxy like nginx doesn't support it out of
the box (unrelated in this context, but just mention for completeness)

```
PR:
RAM: [=== ] 31.0% (used 101700 bytes from 327680 bytes)
Flash: [==========] 95.5% (used 6259244 bytes from 6553600 bytes)

master:
RAM: [=== ] 31.0% (used 101700 bytes from 327680 bytes)
Flash: [==========] 96.2% (used 6302416 bytes from 6553600 bytes)
```

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? **PARTIALLY**, only the
python part

authored by

Xuan-Son Nguyen and committed by
GitHub
5816ab2a 2c0a1055

+34 -4
+24 -1
scripts/build_html.py
··· 1 1 import os 2 2 import re 3 + import gzip 3 4 4 5 SRC_DIR = "src" 5 6 ··· 40 41 41 42 # minified = regex.sub("\g<1>", html_content) 42 43 minified = minify_html(html_content) 44 + 45 + # Compress with gzip (compresslevel 9 is maximum compression) 46 + # IMPORTANT: we don't use brotli because Firefox doesn't support brotli with insecured context (only supported on HTTPS) 47 + compressed = gzip.compress(minified.encode('utf-8'), compresslevel=9) 48 + 43 49 base_name = f"{os.path.splitext(file)[0]}Html" 44 50 header_path = os.path.join(root, f"{base_name}.generated.h") 45 51 46 52 with open(header_path, "w", encoding="utf-8") as h: 47 53 h.write(f"// THIS FILE IS AUTOGENERATED, DO NOT EDIT MANUALLY\n\n") 48 54 h.write(f"#pragma once\n") 49 - h.write(f'constexpr char {base_name}[] PROGMEM = R"rawliteral({minified})rawliteral";\n') 55 + h.write(f"#include <cstddef>\n\n") 56 + 57 + # Write the compressed data as a byte array 58 + h.write(f"constexpr char {base_name}[] PROGMEM = {{\n") 59 + 60 + # Write bytes in rows of 16 61 + for i in range(0, len(compressed), 16): 62 + chunk = compressed[i:i+16] 63 + hex_values = ', '.join(f'0x{b:02x}' for b in chunk) 64 + h.write(f" {hex_values},\n") 65 + 66 + h.write(f"}};\n\n") 67 + h.write(f"constexpr size_t {base_name}CompressedSize = {len(compressed)};\n") 68 + h.write(f"constexpr size_t {base_name}OriginalSize = {len(minified)};\n") 50 69 51 70 print(f"Generated: {header_path}") 71 + print(f" Original: {len(html_content)} bytes") 72 + print(f" Minified: {len(minified)} bytes ({100*len(minified)/len(html_content):.1f}%)") 73 + print(f" Compressed: {len(compressed)} bytes ({100*len(compressed)/len(html_content):.1f}%)") 74 +
+10 -3
src/network/CrossPointWebServer.cpp
··· 293 293 return status; 294 294 } 295 295 296 + static void sendHtmlContent(WebServer* server, const char* data, size_t len) { 297 + server->sendHeader("Content-Encoding", "gzip"); 298 + server->send_P(200, "text/html", data, len); 299 + } 300 + 296 301 void CrossPointWebServer::handleRoot() const { 297 - server->send(200, "text/html", HomePageHtml); 302 + sendHtmlContent(server.get(), HomePageHtml, sizeof(HomePageHtml)); 298 303 LOG_DBG("WEB", "Served root page"); 299 304 } 300 305 ··· 385 390 return lower.endsWith(".epub"); 386 391 } 387 392 388 - void CrossPointWebServer::handleFileList() const { server->send(200, "text/html", FilesPageHtml); } 393 + void CrossPointWebServer::handleFileList() const { 394 + sendHtmlContent(server.get(), FilesPageHtml, sizeof(FilesPageHtml)); 395 + } 389 396 390 397 void CrossPointWebServer::handleFileListData() const { 391 398 // Get current path from query string (default to root) ··· 989 996 } 990 997 991 998 void CrossPointWebServer::handleSettingsPage() const { 992 - server->send(200, "text/html", SettingsPageHtml); 999 + sendHtmlContent(server.get(), SettingsPageHtml, sizeof(SettingsPageHtml)); 993 1000 LOG_DBG("WEB", "Served settings page"); 994 1001 } 995 1002