Repository navigation
literouter v0.5.0
v0.5.0 — The Desktop App
Highlights
- literouter is now an application you install and double-click. It starts the gateway, opens the web console in your browser, and lives in the system tray. No window of its own — the console is the interface. Tray menu: Show opens the console, Exit stops the gateway.
- The gateway runs inside the app's process.
literouter.coreis a library, so the app links it and callsstart()/stop()directly instead of spawningliterouter serveas a child. That is what makes one implementation instead of three: a supervised child would needposix_spawn/CreateProcessW,kill/GenerateConsoleCtrlEvent,waitpid/WaitForSingleObjectand a pipe on every platform. - A gateway that is already running is adopted, not fought over. If you have
literouter servegoing, the app opens its console, keeps the icon, and leaves that gateway alone on exit — it did not start it. Detection asks the instance (GET /__literouter/status), soport: 0works: only the instance knows what the kernel gave it. - A macOS
.appbundle. Unzip, drag to Applications, double-click. Gets its own Dock icon and a Gatekeeper identity that can be granted per app.ditto -c -k --sequesterRsrcpacks it, because a plainzip -rof a.appis a known way to ship a bundle that will not launch. - A Windows installer. Installs to
Program Files, adds Start-menu entries, uninstalls from Apps & features. It does not edit PATH unless asked, does not add firewall rules, and does not register a service. - Autostart is opt-in and user-scoped. Nothing is written on first launch.
literouter-tray --autostartadds a login entry in a location you can delete by hand without elevation — XDG autostart,~/Library/LaunchAgents, or the Windows Startup folder. Never a system service.
Fixed
- Streamed answers were paced by Nagle. Neither the server socket nor the upstream socket set
TCP_NODELAY, which is httplib's default. Measured on loopback against a relay answering in 0.1 ms: a buffered request took 42 ms instead of 0.7 ms, and a streamed answer 42.15 ms instead of 0.90 ms. Both legs now set it. Group 4c guards the upstream leg against the burst-write relay that actually reproduces it — the existingStreamstub pauses 5 ms per chunk, which is longer than the delayed-ACK timer, so it passed even with the bug present. - TLS certificate paths were passed to OpenSSL as UTF-8 bytes. The config stores UTF-8; OpenSSL's PEM loaders decode through the ANSI code page on Windows, so a certificate under a directory named in Chinese failed at bind time with a message that named neither the path nor the reason.
pathFromUtf8andpathForCApimake the two conversions explicit — and they are not interchangeable, becausepathToUtf8produces exactly the bytes those APIs cannot read. - stdout was left in the CRT's text mode on Windows, turning every
\nin--jsonoutput into\r\n. A CR inside a JSON string value is either invalid JSON or a silently different value, and the consumers arejq, CI, and the Docker healthcheck.
Changed
- The raw-socket test groups run on Windows. Groups 12 (hanging relay), 23 (request deadline) and 20 (connection reuse) were wrapped in
#ifndef _WIN32because their stubs speak raw sockets. Those are the failover and pooling paths — the parts with the most to go wrong — so the platform with the least coverage was the one where a failover bug would be hardest to find.core/tests/lr_test_socket.hprovides the same vocabulary with Winsock behind it. trayis a workspace member. It has to be:corepins its dependencies withworkspace = true, which mcpp only resolves inside the workspace that declares them. The cost is that a full workspace build now pulls eui-neo's graphics closure;mcpp build -p core -p clistill builds only the headless pair.
Upgrade Notes
- The configuration schema is unchanged and needs no migration. Existing
config.jsonfiles load and behave exactly as before. - If you use the command-line gateway, nothing about it changed. The install scripts still install
literouterand still take--service/-Servicefor a headless service. - The desktop app and the CLI are independent: installing one does not touch the other, and both read the same config.
- New artifacts this release adds:
literouter-<version>-macos-arm64-app.zip,literouter-<version>-windows-x86_64-setup.exe, andliterouter-trayinside the Linux tarball. - macOS Intel is still not published;
install.shrefuses it with a pointer to Rosetta or building from source.
Known Limits
- The tray menu has two entries. EUI-NEO hard-codes Show / separator / Exit in all three of its backends and exposes only two booleans. Starting and stopping follow the process lifetime instead, and autostart is a command-line flag rather than a menu item.
Showcannot report failure. EUI-NEO'sopenUrlrunsxdg-open … &throughstd::system(), so it returns success as soon as the fork happens, whether or not a browser appears. The app calls it and does not pretend the result means anything.- The Windows and macOS packaging steps have not run on this machine. ISCC is Windows-only and
ditto/codesignare macOS-only; they were verified structurally (the plist parses, the.isshas every required section and its staged path rewriting resolves) and execute for the first time in this release workflow.
Installation
Desktop app — download from the GitHub Release:
| Platform | File |
|---|---|
| macOS (Apple Silicon) | literouter-0.5.0-macos-arm64-app.zip |
| Windows (x86_64) | literouter-0.5.0-windows-x86_64-setup.exe |
| Linux (x86_64) | literouter-0.5.0-linux-x86_64.tar.gz (run the literouter-tray inside) |
Command-line gateway — unchanged:
curl -fsSL https://raw.githubusercontent.com/YangQi0408/literouter/main/scripts/install.sh | bashThen open http://127.0.0.1:8787/ui/.