feat: add Nex and Gopher listeners
Reuses md2txt's existing nex and text renderers (both already ship unmodified) -- rendered unwrapped gemtext still works for Gemini/Spartan clients that wrap themselves, but Nex and Gopher clients don't, so those two get the classic 80-column pre-wrap instead. Neither protocol has a redirect status of its own, so Site.resolve_flat() follows the /foo.md -> /foo canonical bounce and the WML-card-only -> parent redirect server-side and hands back real content directly, rather than leaving the two new listeners to invent a redirect convention that doesn't exist on the wire. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
12956a5034
commit
0b67069760
8 changed files with 290 additions and 13 deletions
25
README.md
25
README.md
|
|
@ -1,16 +1,19 @@
|
|||
# smolweb
|
||||
|
||||
Serve a folder of Markdown as [Gemini](https://geminiprotocol.net/) capsules,
|
||||
[Spartan](https://portal.mozz.us/gemini/spartan.mozz.us/) capsules, and HTTP
|
||||
pages content-negotiated between WML (WAP 1.x) and XHTML-MP (WAP 2.0 and
|
||||
modern browsers) — all rendered on the fly, no build step.
|
||||
[Spartan](https://portal.mozz.us/gemini/spartan.mozz.us/) capsules,
|
||||
[Nex](https://nightfall.city/nex/info/specification.txt) and
|
||||
[Gopher](https://www.rfc-editor.org/rfc/rfc1436) documents, and HTTP pages
|
||||
content-negotiated between WML (WAP 1.x) and XHTML-MP (WAP 2.0 and modern
|
||||
browsers) — all rendered on the fly, no build step.
|
||||
|
||||
```bash
|
||||
smolweb --root ./content --host example.com
|
||||
```
|
||||
|
||||
Every listener binds by default: Gemini on `:1965` (TLS), Spartan on `:300`,
|
||||
HTTP on `:8080`. An empty address disables one:
|
||||
HTTP on `:8080`, Nex on `:1900`, Gopher on `:70`. An empty address disables
|
||||
one:
|
||||
|
||||
```bash
|
||||
smolweb --root ./content --host example.com --spartan ""
|
||||
|
|
@ -21,9 +24,19 @@ smolweb --root ./content --host example.com --spartan ""
|
|||
Markdown is parsed once per file (cached by mtime, re-parsed the moment the
|
||||
file changes) and rendered into every format from the same source:
|
||||
|
||||
- **gemtext** via [md2txt](https://code.randogoth.com/randogoth/md2txt)'s `gemini` renderer.
|
||||
- **gemtext**, **Nex**, and **Gopher text** via [md2txt](https://code.randogoth.com/randogoth/md2txt)'s `gemini`, `nex`, and `text` renderers respectively.
|
||||
- **WML** and **XHTML-MP** via [wapdown](https://code.randogoth.com/randogoth/wapdown).
|
||||
|
||||
Gemini and Spartan clients wrap gemtext themselves, so it's rendered
|
||||
unwrapped (`width=0`). Nex and Gopher clients don't, so those two are
|
||||
pre-wrapped at the classic 80-column convention instead.
|
||||
|
||||
Neither Nex nor Gopher has a redirect status of its own, so the `/foo.md ->
|
||||
/foo` canonical-URL bounce and the WML-card-only-path-redirects-to-its-
|
||||
parent behaviour (see below) are both resolved server-side instead of
|
||||
bounced back to the client — the client always gets real content back
|
||||
directly, on the first request.
|
||||
|
||||
Both libraries read the same leading `---` frontmatter block independently
|
||||
and ignore keys they don't recognise, so one file can freely mix wapdown's
|
||||
deck-structure keys (`title`, `split_level`, `deck_per_card`, ...) with
|
||||
|
|
@ -53,6 +66,8 @@ A document with `deck_per_card: true` gets its own URL space for WML only:
|
|||
`/trail/weather` serves one card's own deck directly. Gemini, Spartan, and
|
||||
an HTTP client negotiating gemtext/XHTML-MP all redirect `/trail/weather`
|
||||
back to `/trail` instead — that URL space only ever makes sense for WML.
|
||||
Nex and Gopher serve `/trail`'s own content directly for the same request,
|
||||
since neither has a redirect status to bounce with.
|
||||
|
||||
## HTTP content negotiation
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue