summaryrefslogtreecommitdiff
path: root/docs
Commit message (Collapse)AuthorAge
...
* Wrote down the DB recovery processOwen Jacobson2024-10-05
|
* List messages per channel.Owen Jacobson2024-10-03
|
* Add endpoints for deleting channels and messages.Owen Jacobson2024-10-03
| | | | It is deliberate that the expire() functions do not use them. To avoid races, the transactions must be committed before events get sent, in both cases, which makes them structurally pretty different.
* Provide a resume point to bridge clients from state snapshots to the event ↵Owen Jacobson2024-10-01
| | | | sequence.
* Expire channels, too.Owen Jacobson2024-09-28
|
* Push message body into its own object in eventsOwen Jacobson2024-09-28
|
* Send created events when channels are added.Owen Jacobson2024-09-28
|
* Make `/api/events` a firehose endpoint.Owen Jacobson2024-09-27
| | | | | | | | It now includes events for all channels. Clients are responsible for filtering. The schema for channel events has changed; it now includes a channel name and ID, in the same format as the sender's name and ID. They also now include a `"type"` field, whose only valid value (as of this writing) is `"message"`. This is groundwork for delivering message deletion (expiry) events to clients, and notifying clients of channel lifecycle events.
* Use a vector of sequence numbers, not timestamps, to restart /api/events ↵Owen Jacobson2024-09-25
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | streams. The timestamp-based approach had some formal problems. In particular, it assumed that time always went forwards, which isn't necessarily the case: * Alice calls `/api/channels/Cfoo` to send a message. * The server assigns time T to the request. * The server stalls somewhere in send() for a while, before storing and broadcasting the message. If it helps, imagine blocking on `tx.begin().await?` for a while. * In this interval, Bob calls `/api/events?channel=Cfoo`, receives historical messages up to time U (after T), and disconnects. * The server resumes Alice's request and finishes it. * Bob reconnects, setting his Last-Event-Id header to timestamp U. In this scenario, Bob never sees Alice's message unless he starts over. It wasn't in the original stream, since it wasn't broadcast while Bob was subscribed, and it's not in the new stream, since Bob's resume point is after the timestamp on Alice's message. The new approach avoids this. Each message is assigned a _sequence number_ when it's stored. Bob can be sure that his stream included every event, since the resume point is identified by sequence number even if the server processes them out of chronological order: * Alice calls `/api/channels/Cfoo` to send a message. * The server assigns time T to the request. * The server stalls somewhere in send() for a while, before storing and broadcasting. * In this interval, Bob calls `/api/events?channel=Cfoo`, receives historical messages up to sequence Cfoo=N, and disconnects. * The server resumes Alice's request, assigns her message sequence M (after N), and finishes it. * Bob resumes his subscription at Cfoo=N. * Bob receives Alice's message at Cfoo=M. There's a natural mutual exclusion on sequence numbers, enforced by sqlite, which ensures that no two messages have the same sequence number. Since sqlite promises that transactions are serializable by default (and enforces this with a whole-DB write lock), we can be confident that sequence numbers are monotonic, as well. This scenario is, to put it mildly, contrived and unlikely - which is what motivated me to fix it. These kinds of bugs are fiendishly hard to identify, let alone reproduce or understand. I wonder how costly cloning a map is going to turn out to be… A note on database migrations: sqlite3 really, truly has no `alter table … alter column` statement. The only way to modify an existing column is to add the column to a new table. If `alter column` existed, I would create the new `sequence` column in `message` in a much less roundabout way. Fortunately, these migrations assume that they are being run _offline_, so operations like "replace the whole table" are reasonable.
* Small design docOwen Jacobson2024-09-23
|
* Docs updatesOwen Jacobson2024-09-21
|
* Write tests.Owen Jacobson2024-09-20
|
* Docs updates:Owen Jacobson2024-09-20
| | | | | * Document message expiry. * More warnings about Last-Event-Id.
* Remove the HTML client, and expose a JSON API.Owen Jacobson2024-09-20
This API structure fell out of a conversation with Kit. Described loosely: kit: ok kit: Here's what I'm picturing in a client kit: list channels, make-new-channel, zero to one active channels, post-to-active. kit: login/sign-up, logout owen: you will likely also want "am I logged in" here kit: sure, whoami