docs: add design philosophy section explaining protocol rationale
Explains why the protocol is IRC over HTTP (not a new protocol borrowing IRC names), the four specific changes from IRC (HTTP transport, server-held sessions, structured bodies, message metadata), and why the C2S command dispatch resembles but is not JSON-RPC.
This commit is contained in:
82
README.md
82
README.md
@@ -1,5 +1,8 @@
|
||||
# chat
|
||||
|
||||
IRC plus message metadata, a signing system using it, and server-based backlog
|
||||
queues for multiple connected clients on one nick. All via HTTP.
|
||||
|
||||
A modern IRC-inspired chat server written in Go. Decouples session state from
|
||||
transport connections, enabling mobile-friendly persistent sessions over HTTP.
|
||||
|
||||
@@ -22,6 +25,85 @@ This project builds a chat server that:
|
||||
- Provides IRC-like semantics: channels, nicks, topics, modes
|
||||
- Uses structured JSON messages with IRC command names and numeric reply codes
|
||||
|
||||
## Why Not Just Use IRC / XMPP / Matrix?
|
||||
|
||||
This isn't a new protocol that borrows IRC terminology for familiarity. This
|
||||
**is** IRC — the same command model, the same semantics, the same numeric
|
||||
reply codes from RFC 1459/2812 — carried over HTTP+JSON instead of raw TCP.
|
||||
|
||||
The question isn't "why build something new?" It's "what's the minimum set of
|
||||
changes to make IRC work on modern devices?" The answer turned out to be four
|
||||
things:
|
||||
|
||||
### 1. HTTP transport instead of persistent TCP
|
||||
|
||||
IRC requires a persistent TCP connection. That's fine on a desktop. On a phone,
|
||||
the OS kills your background socket, you lose your session, you miss messages.
|
||||
Bouncers exist but add complexity and a second point of failure.
|
||||
|
||||
HTTP solves this cleanly: clients poll when they're awake, messages queue when
|
||||
they're not. Works through firewalls, proxies, CDNs. Every language has an HTTP
|
||||
client. No custom protocol parsers, no connection state machines.
|
||||
|
||||
### 2. Server-held session state
|
||||
|
||||
In IRC, the TCP connection *is* the session. Disconnect and you're gone — your
|
||||
nick is released, you leave all channels, messages sent while you're offline
|
||||
are lost forever. This is IRC's fundamental mobile problem.
|
||||
|
||||
Here, sessions persist independently of connections. Your nick, channel
|
||||
memberships, and message queue survive disconnects. Multiple devices can share
|
||||
a session simultaneously, each with its own delivery queue.
|
||||
|
||||
### 3. Structured message bodies
|
||||
|
||||
IRC messages are single lines of text. That's a protocol constraint from 1988,
|
||||
not a deliberate design choice. It forces multiline content through ugly
|
||||
workarounds (multiple PRIVMSG commands, paste flood).
|
||||
|
||||
Message bodies here are JSON arrays (one string per line) or objects (for
|
||||
structured data like key material). This also enables deterministic
|
||||
canonicalization via RFC 8785 JCS — you can't reliably sign something if the
|
||||
wire representation is ambiguous.
|
||||
|
||||
### 4. Key/value metadata on messages
|
||||
|
||||
The `meta` field on every message envelope carries extensible attributes —
|
||||
cryptographic signatures, content hashes, whatever clients want to attach.
|
||||
IRC has no equivalent; bolting signatures onto IRC requires out-of-band
|
||||
mechanisms or stuffing data into CTCP.
|
||||
|
||||
### What didn't change
|
||||
|
||||
Everything else is IRC. `PRIVMSG`, `JOIN`, `PART`, `NICK`, `TOPIC`, `MODE`,
|
||||
`KICK`, `353`, `433` — same commands, same semantics. Channels start with `#`.
|
||||
Joining a nonexistent channel creates it. Channels disappear when empty. Nicks
|
||||
are unique per server. There are no accounts — identity is a key, a nick is a
|
||||
display name.
|
||||
|
||||
### On the resemblance to JSON-RPC
|
||||
|
||||
All C2S commands go through `POST /messages` with a `command` field that
|
||||
dispatches the action. This looks like JSON-RPC, but the resemblance is
|
||||
incidental. It's IRC's command model — `PRIVMSG #channel :hello` becomes
|
||||
`{"command": "PRIVMSG", "to": "#channel", "body": ["hello"]}` — encoded as
|
||||
JSON rather than space-delimited text. The command vocabulary is IRC's, not
|
||||
an invention.
|
||||
|
||||
The message envelope is deliberately identical for C2S and S2C. A `PRIVMSG` is
|
||||
a `PRIVMSG` regardless of direction. A `JOIN` from a client is the same shape
|
||||
as the `JOIN` relayed to channel members. This keeps the protocol simple and
|
||||
makes signing consistent — you sign the same structure you send.
|
||||
|
||||
### Why not XMPP or Matrix?
|
||||
|
||||
XMPP is XML-based, overengineered for chat, and the ecosystem is fragmented
|
||||
across incompatible extensions (XEPs). Matrix is a federated append-only event
|
||||
graph with a spec that runs to hundreds of pages. Both are fine protocols, but
|
||||
they're solving different problems at different scales.
|
||||
|
||||
This project wants IRC's simplicity with four specific fixes. That's it.
|
||||
|
||||
## Design Decisions
|
||||
|
||||
### Identity & Sessions — No Accounts
|
||||
|
||||
Reference in New Issue
Block a user