aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorJeff Halter <868228+jhalter@users.noreply.github.com>2026-08-23 12:44:53 -0700
committerJeff Halter <868228+jhalter@users.noreply.github.com>2026-08-23 12:44:53 -0700
commit68f615cc6e6ac177109db5b3be4f9767c9cfd1a8 (patch)
tree37380267c1356e67783e9273495bfa099048486c /docs
parent4df6b97311e321c1ef178efce905307b10ce6fa7 (diff)
Add feed-backed threaded news imports
Diffstat (limited to 'docs')
-rw-r--r--docs/feed-backed-news.md129
-rw-r--r--docs/text-encoding.md40
2 files changed, 155 insertions, 14 deletions
diff --git a/docs/feed-backed-news.md b/docs/feed-backed-news.md
new file mode 100644
index 0000000..8edcf79
--- /dev/null
+++ b/docs/feed-backed-news.md
@@ -0,0 +1,129 @@
+# Feed-backed threaded news
+
+Mobius can import a public RSS or Atom feed into an existing Hotline news
+category. This is useful for project announcements, Sparkle appcasts, and
+GitHub release feeds.
+
+When a user opens a mapped category, Mobius checks its source and adds entries
+it has not seen before as ordinary root articles. Imported articles live in
+`ThreadedNews.yaml`, alongside locally posted articles and replies. The category
+continues to work as ordinary Hotline news: authorized users can post roots,
+reply, and delete any article.
+
+## Configure a category
+
+First, create the target as an ordinary news category with a Hotline client.
+Every component in `CategoryPath`, including the final category, must already
+exist before the server starts.
+
+Then add a mapping to `config.yaml` and restart Mobius:
+
+```yaml
+NewsFeeds:
+ - CategoryPath: ["Software Updates", "Afterglow"]
+ URL: "https://morphing.cloud/afterglow/appcast.xml"
+
+ - CategoryPath: ["Software Updates", "Mobius"]
+ URL: "https://github.com/jhalter/mobius/releases.atom"
+```
+
+`CategoryPath` is the complete path from the root of threaded news to the
+existing category. `URL` must be an absolute public `http` or `https` URL and
+cannot contain embedded credentials. Only one feed may map to a category.
+
+Mobius detects RSS and Atom automatically. Sparkle appcasts are RSS; GitHub's
+`releases.atom` endpoints are Atom. JSON Feed and provider-specific APIs are not
+supported.
+
+## Import behavior
+
+Every article-list request for the mapped category performs a source check.
+Mobius sends the saved `ETag` and `Last-Modified` values when the source
+provides them, allowing an unchanged source to answer with a small `304 Not
+Modified` response. Concurrent requests for the same category share one
+in-flight check.
+
+On a successful response, Mobius:
+
+1. Finds entries not previously observed from that URL.
+2. Converts HTML descriptions to plain text and retains useful source, release
+ notes, and enclosure links.
+3. Imports new entries oldest-first as ordinary root articles.
+4. Saves the articles and import metadata together in one atomic update to
+ `ThreadedNews.yaml`.
+
+An entry needs a stable identity: a GUID or Atom ID, an HTTP(S) article link,
+or an HTTP(S) enclosure URL, in that order. Entries without any of these are
+skipped and logged. Mobius intentionally does not derive identities from titles
+or bodies because an edited entry could then be mistaken for a new article.
+
+Once an identity has been imported, later changes to that entry's title,
+author, date, or body are ignored. If an imported article is deleted locally,
+its identity remains in the seen set, so the feed does not recreate it. Items
+also remain in Hotline when they disappear from the source. This prevents a
+feed's rolling window from rolling articles out of the Hotline category.
+
+The initial import can only include entries returned by the source. Mobius does
+not paginate GitHub or reconstruct older releases that are already absent from
+its Atom feed.
+
+## Failures and limits
+
+A network error, timeout, non-success HTTP response, invalid feed, or failed
+disk write is logged. Mobius still returns the category's current local article
+list, including an empty list before the first successful import. A later
+category load tries the source again. Requests time out after 10 seconds and a
+response body may be at most 2 MiB.
+
+The Hotline protocol limits the complete encoded article-list payload for one
+category to 65,535 bytes. This listing contains article metadata—not article
+bodies—so the practical capacity depends mostly on the number and encoded
+length of titles and authors. Mobius checks the full list after each candidate
+article. It saves the oldest prefix that fits and stops before an addition
+would exceed the limit. It does not save new HTTP validators while unseen
+entries remain, so the next category load fetches and retries them. Mobius does
+not prune local or imported articles automatically; split a large source across
+categories when a category approaches this protocol limit.
+
+Individual imported titles and authors are limited to 255 encoded bytes, and
+article bodies to 65,535 encoded bytes, matching Hotline's field sizes.
+
+## Durable state and backups
+
+Feed history is part of each category in `ThreadedNews.yaml` under a YAML-only
+`FeedState` key. It records the current source URL, HTTP validators, and hashes
+of identities that have already been imported. This metadata is not sent to
+Hotline clients. Back up `ThreadedNews.yaml` as usual; there are no additional
+feed state or cache files.
+
+Changing a category's URL clears its HTTP validators but retains its seen
+history. Identity hashes include the source URL, so the new source can import
+its entries even if it uses the same GUID values. Switching back to a previous
+URL does not duplicate entries that URL imported earlier.
+
+The earlier experimental `FeedNewsState.yaml` and `FeedNewsCache.json` formats
+are not migrated or read. If they exist from a development build, Mobius
+ignores them; their contents do not participate in this feature.
+
+## Text encoding
+
+Feed parsers produce UTF-8 text. Mobius converts each entry once, when it is
+imported, according to the server-wide `Encoding` setting. The default
+`macintosh` setting converts to Mac Roman and replaces unsupported characters;
+`utf8` stores UTF-8 unchanged. Existing imported articles are ordinary raw-byte
+news data, so changing `Encoding` affects only future imports and does not
+rewrite history.
+
+## Troubleshooting
+
+- If startup fails, verify that every mapped path already exists and ends at a
+ news category rather than a bundle. Also check for duplicate paths and
+ invalid or credential-bearing URLs.
+- If new entries do not appear, open the category and inspect the server log.
+ Confirm that the URL is public RSS or Atom and that entries have stable IDs,
+ links, or enclosures.
+- If old releases are missing on the first import, inspect the source feed. Its
+ published window is the initial cutoff; Mobius does not use pagination or a
+ provider API.
+- If a source is unavailable, existing local news remains usable and the next
+ category load retries it.
diff --git a/docs/text-encoding.md b/docs/text-encoding.md
index 71bdada..f299b51 100644
--- a/docs/text-encoding.md
+++ b/docs/text-encoding.md
@@ -2,7 +2,7 @@
## Background
-The Hotline protocol was designed for classic Mac OS, which used an encoding called Mac Roman for text. Modern operating systems use UTF-8 instead. Mobius automatically translates between these two encodings so that classic Hotline clients and modern filesystems can work together.
+The Hotline protocol was designed for classic Mac OS, which used an encoding called Mac Roman for text. Modern operating systems use UTF-8 instead. Mobius translates filesystem names and newly imported feed news so that classic Hotline clients and modern UTF-8 sources can work together. Most other protocol text remains raw bytes.
By default, Mobius assumes all clients use Mac Roman encoding. If your server exclusively serves modern UTF-8 clients, you can disable the Mac Roman conversion. This document explains how encoding works and how to configure it.
@@ -17,9 +17,20 @@ When a Hotline client uploads, downloads, browses, creates, or renames files and
This means files on disk always use UTF-8 names, regardless of what encoding the client uses. You can place files with Unicode names in the server's file directory and clients will see them — as long as the characters have Mac Roman equivalents.
-### Chat, news, and usernames are NOT translated
+### Server-generated feed news is translated
-Text in chat messages, news articles, usernames, and private messages is passed through as raw bytes with no encoding conversion. This means:
+RSS and Atom sources are UTF-8 server data rather than client-authored Hotline
+text. Mobius encodes each imported article's title, author, and body when it is
+first added to `ThreadedNews.yaml`. With the default `macintosh` setting,
+characters that Mac Roman cannot represent are replaced. With `utf8`, feed text
+is stored unchanged.
+
+Imported entries become ordinary raw-byte news articles. Changing `Encoding`
+therefore affects future imports only; it does not rewrite existing articles.
+
+### Chat, user-authored news, and usernames are NOT translated
+
+Text in chat messages, existing news articles, usernames, and private messages is passed through as raw bytes with no encoding conversion. This means:
- If all your users are on classic Mac clients, they'll see each other's text correctly (all Mac Roman).
- If all your users are on modern UTF-8 clients, they'll also see each other's text correctly.
@@ -29,13 +40,13 @@ There is no way to configure this behavior — the Hotline protocol has no mecha
## Configuration
-The `Encoding` field in `config.yaml` controls how file and folder names are translated:
+The `Encoding` field in `config.yaml` controls how file and folder names and server-generated feed news are translated:
```yaml
# Default — translates between Mac Roman and UTF-8 (compatible with classic Hotline clients)
Encoding: macintosh
-# No-op — passes file names through without conversion (for servers with only modern UTF-8 clients)
+# No-op — passes file names and feed news through unchanged (modern UTF-8 clients only)
Encoding: utf8
```
@@ -59,12 +70,13 @@ Modern Hotline clients that send UTF-8 for file operations may produce unexpecte
## Summary
-| What | Encoding translation? | Notes |
-|---------------------------|----------------------|-----------------------------------------------|
-| File and folder names | Yes | Mac Roman <-> UTF-8 at the filesystem boundary |
-| Chat messages | No | Raw bytes, passed through as-is |
-| News articles and titles | No | Raw bytes, passed through as-is |
-| Usernames | No | Raw bytes, passed through as-is |
-| Private messages | No | Raw bytes, passed through as-is |
-| File comments | No | Stored and retrieved as raw bytes |
-| Login credentials | No | Obfuscated, no charset conversion |
+| What | Encoding translation? | Notes |
+| --- | --- | --- |
+| File and folder names | Yes | Mac Roman <-> UTF-8 at the filesystem boundary |
+| Newly imported feed articles | Yes | UTF-8 source text -> configured encoding at import time |
+| Chat messages | No | Raw bytes, passed through as-is |
+| Existing and user-authored news articles | No | Raw bytes, passed through as-is |
+| Usernames | No | Raw bytes, passed through as-is |
+| Private messages | No | Raw bytes, passed through as-is |
+| File comments | No | Stored and retrieved as raw bytes |
+| Login credentials | No | Obfuscated, no charset conversion |