Add embedded web chat client (closes #7) #8
73
README.md
73
README.md
@@ -3,6 +3,11 @@
|
|||||||
A modern IRC-inspired chat server written in Go. Decouples session state from
|
A modern IRC-inspired chat server written in Go. Decouples session state from
|
||||||
transport connections, enabling mobile-friendly persistent sessions over HTTP.
|
transport connections, enabling mobile-friendly persistent sessions over HTTP.
|
||||||
|
|
||||||
|
The **HTTP API is the primary interface**. It's designed to be simple enough
|
||||||
|
that writing a terminal IRC-style client against it is straightforward — just
|
||||||
|
`curl` and `jq` get you surprisingly far. The server also ships an embedded
|
||||||
|
web client as a convenience/reference implementation, but the API comes first.
|
||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
IRC is in decline because session state is tied to the TCP connection. In a
|
IRC is in decline because session state is tied to the TCP connection. In a
|
||||||
@@ -12,7 +17,7 @@ or pay for IRCCloud.
|
|||||||
This project builds a chat server that:
|
This project builds a chat server that:
|
||||||
|
|
||||||
- Holds session state server-side (message queues, presence, channel membership)
|
- Holds session state server-side (message queues, presence, channel membership)
|
||||||
- Delivers messages over HTTP (JSON-RPC style)
|
- Exposes a minimal, clean HTTP+JSON API — easy to build clients against
|
||||||
- Supports multiple concurrent connections per user session
|
- Supports multiple concurrent connections per user session
|
||||||
- Provides IRC-like semantics: channels, nicks, topics, modes
|
- Provides IRC-like semantics: channels, nicks, topics, modes
|
||||||
- Uses structured JSON messages with arbitrary extensibility
|
- Uses structured JSON messages with arbitrary extensibility
|
||||||
@@ -24,12 +29,15 @@ This project builds a chat server that:
|
|||||||
All client↔server and server↔server communication uses HTTP/1.1+ with JSON
|
All client↔server and server↔server communication uses HTTP/1.1+ with JSON
|
||||||
request/response bodies. No WebSockets, no raw TCP, no gRPC — just plain HTTP.
|
request/response bodies. No WebSockets, no raw TCP, no gRPC — just plain HTTP.
|
||||||
|
|
||||||
- **Client polling**: Clients poll for new messages via `GET` with long-polling
|
- **Client polling**: Clients long-poll `GET /api/v1/messages` — server holds
|
||||||
support (server holds the connection open until messages arrive or timeout)
|
the connection until messages arrive or timeout. One endpoint for everything.
|
||||||
- **Client sending**: Clients send messages/commands via `POST`
|
- **Client sending**: `POST /api/v1/messages` with a `to` field. That's it.
|
||||||
- **Server federation**: Servers exchange messages via HTTP to enable multi-server
|
- **Server federation**: Servers exchange messages via HTTP to enable multi-server
|
||||||
networks (like IRC server linking)
|
networks (like IRC server linking)
|
||||||
|
|
||||||
|
The entire read/write loop for a client is two endpoints. Everything else is
|
||||||
|
channel management and history.
|
||||||
|
|
||||||
### Core Concepts
|
### Core Concepts
|
||||||
|
|
||||||
#### Users
|
#### Users
|
||||||
@@ -90,9 +98,37 @@ Fields:
|
|||||||
All endpoints accept and return `application/json`. Authenticated endpoints
|
All endpoints accept and return `application/json`. Authenticated endpoints
|
||||||
require `Authorization: Bearer <token>` header.
|
require `Authorization: Bearer <token>` header.
|
||||||
|
|
||||||
The API follows an IRC-inspired design: one unified message stream for all
|
The API is the primary interface — designed for IRC-style clients. The entire
|
||||||
message types (channel messages, DMs, server notices), with a simple `to` field
|
client loop is:
|
||||||
for addressing.
|
|
||||||
|
1. `POST /api/v1/register` — get a token
|
||||||
|
2. `GET /api/v1/state` — see who you are and what channels you're in
|
||||||
|
3. `GET /api/v1/messages?after=0` — long-poll for all messages (channel, DM, system)
|
||||||
|
4. `POST /api/v1/messages` — send to `"#channel"` or `"nick"`
|
||||||
|
|
||||||
|
That's the core. Everything else (join, part, history, members) is ancillary.
|
||||||
|
|
||||||
|
#### Quick example (curl)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Register
|
||||||
|
TOKEN=$(curl -s -X POST http://localhost:8080/api/v1/register \
|
||||||
|
-d '{"nick":"alice"}' | jq -r .token)
|
||||||
|
|
||||||
|
# Join a channel
|
||||||
|
curl -s -X POST http://localhost:8080/api/v1/channels/join \
|
||||||
|
-H "Authorization: Bearer $TOKEN" \
|
||||||
|
-d '{"channel":"#general"}'
|
||||||
|
|
||||||
|
# Send a message
|
||||||
|
curl -s -X POST http://localhost:8080/api/v1/messages \
|
||||||
|
-H "Authorization: Bearer $TOKEN" \
|
||||||
|
-d '{"to":"#general","content":"hello world"}'
|
||||||
|
|
||||||
|
# Poll for messages (long-poll)
|
||||||
|
curl -s http://localhost:8080/api/v1/messages?after=0 \
|
||||||
|
-H "Authorization: Bearer $TOKEN"
|
||||||
|
```
|
||||||
|
|
||||||
#### Registration
|
#### Registration
|
||||||
|
|
||||||
@@ -259,18 +295,29 @@ Per gohttpserver conventions:
|
|||||||
| Metrics | `github.com/prometheus/client_golang` |
|
| Metrics | `github.com/prometheus/client_golang` |
|
||||||
| DB | `modernc.org/sqlite` + `database/sql` |
|
| DB | `modernc.org/sqlite` + `database/sql` |
|
||||||
|
|
||||||
|
### Web Client
|
||||||
|
|
||||||
|
The server embeds a single-page web client (Preact) served at `/`. This is a
|
||||||
|
**convenience/reference implementation** — not the primary interface. It
|
||||||
|
demonstrates the API and provides a quick way to test the server in a browser.
|
||||||
|
|
||||||
|
The primary intended clients are IRC-style terminal applications and bots
|
||||||
|
talking directly to the HTTP API.
|
||||||
|
|
||||||
### Design Principles
|
### Design Principles
|
||||||
|
|
||||||
1. **HTTP is the only transport** — no WebSockets, no raw TCP, no protocol
|
1. **API-first** — the HTTP API is the product. Clients are thin. If you can't
|
||||||
|
build a working IRC-style TUI client in an afternoon, the API is too complex.
|
||||||
|
2. **HTTP is the only transport** — no WebSockets, no raw TCP, no protocol
|
||||||
negotiation. HTTP is universal, proxy-friendly, and works everywhere.
|
negotiation. HTTP is universal, proxy-friendly, and works everywhere.
|
||||||
2. **Server holds state** — clients are stateless. Reconnect, switch devices,
|
3. **Server holds state** — clients are stateless. Reconnect, switch devices,
|
||||||
lose connectivity — your messages are waiting.
|
lose connectivity — your messages are waiting.
|
||||||
3. **Structured messages** — JSON with extensible metadata. Enables signatures,
|
4. **Structured messages** — JSON with extensible metadata. Enables signatures,
|
||||||
rich content, client extensions without protocol changes.
|
rich content, client extensions without protocol changes.
|
||||||
4. **Simple deployment** — single binary, SQLite default, zero mandatory
|
5. **Simple deployment** — single binary, SQLite default, zero mandatory
|
||||||
external dependencies.
|
external dependencies.
|
||||||
5. **No eternal logs** — history rotates. Chat should be ephemeral by default.
|
6. **No eternal logs** — history rotates. Chat should be ephemeral by default.
|
||||||
6. **Federation optional** — single server works standalone. Linking is opt-in.
|
7. **Federation optional** — single server works standalone. Linking is opt-in.
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user