Both sides added a line at the top of the Completed Steps in docs/TODO.md; both are kept, this branch's first. Model: opus-5-5
This commit is contained in:
@@ -73,8 +73,10 @@ development.
|
||||
is never quietly replaced by the default. Defaults apply only to
|
||||
variables that are absent.
|
||||
|
||||
- `DATA_DIR` — where the SimpleX database lives: the bot's profile, its
|
||||
keys, its address and its contacts. Default `./data`; the image sets
|
||||
- `DATA_DIR` — where the bot keeps what it must not lose: the SimpleX
|
||||
database, which holds the bot's profile, its keys, its address and its
|
||||
contacts, and `webhooks.json`, which holds the webhooks registered
|
||||
through the [API](#api). Default `./data`; the image sets
|
||||
`/var/lib/simplexcalc`.
|
||||
- `DEBUG` — `true` or `false`, default `false`. `true` logs every event
|
||||
the chat client sends.
|
||||
@@ -89,7 +91,8 @@ variables that are absent.
|
||||
## API
|
||||
|
||||
An HTTP API beside the chat client lets another program read the bot's
|
||||
chats and send messages in them. It speaks JSON on `PORT`.
|
||||
chats, send messages in them and register webhooks on them. It speaks
|
||||
JSON on `PORT`.
|
||||
|
||||
**Authentication.** Every request carries the credential from
|
||||
`API_TOKEN_FILE`:
|
||||
@@ -218,6 +221,88 @@ Nothing is sent, and the answer is:
|
||||
- `413` if the body is over 64 KiB, or the text is too long for one
|
||||
SimpleX message, which holds about 15,000 bytes.
|
||||
|
||||
### `POST /api/v1/chats/{id}/webhooks`
|
||||
|
||||
Registers the `url` in the body as a webhook on the chat `id`, and
|
||||
answers `201` with the webhook. If the chat already has a webhook with
|
||||
the same `url`, character for character, the answer is `200` with that
|
||||
webhook instead.
|
||||
|
||||
```sh
|
||||
curl -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
|
||||
-d '{"url":"https://example.com/hook"}' \
|
||||
http://127.0.0.1:8080/api/v1/chats/3/webhooks
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "5f0c7a1e9b2d4c8e3a6f1b7d2e9c4a80",
|
||||
"chat_id": 3,
|
||||
"url": "https://example.com/hook"
|
||||
}
|
||||
```
|
||||
|
||||
A webhook has:
|
||||
|
||||
- `id` — 16 random bytes, written as 32 hexadecimal digits.
|
||||
- `chat_id` — the chat it is registered on.
|
||||
- `url` — the URL, as it was registered.
|
||||
|
||||
The bot keeps the webhooks in `webhooks.json` in `DATA_DIR`, with mode
|
||||
0600, and reads that file at startup, so they survive a restart. Without
|
||||
the file there are none; a file that cannot be read, or that holds
|
||||
anything but webhooks as the bot writes them, aborts startup, as
|
||||
configuration that cannot be parsed does. The bot does not post anything
|
||||
to a webhook yet.
|
||||
|
||||
Nothing is registered, and the answer is:
|
||||
|
||||
- `400` if the body is not JSON of that shape, or `url` is not an
|
||||
absolute `http` or `https` URL with a host, at most 2048 bytes long;
|
||||
- `404` if `GET /api/v1/chats` does not list `id`;
|
||||
- `413` if the body is over 64 KiB;
|
||||
- `500` if `webhooks.json` cannot be written.
|
||||
|
||||
### `GET /api/v1/chats/{id}/webhooks`
|
||||
|
||||
The webhooks registered on the chat `id`, in the order they were
|
||||
registered; `404` if `GET /api/v1/chats` does not list `id`. A chat's
|
||||
webhooks stay after its contact deletes the chat (`contact_deleted` is
|
||||
`true`), until they are removed.
|
||||
|
||||
```sh
|
||||
curl -H "Authorization: Bearer $TOKEN" \
|
||||
http://127.0.0.1:8080/api/v1/chats/3/webhooks
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"webhooks": [
|
||||
{
|
||||
"id": "5f0c7a1e9b2d4c8e3a6f1b7d2e9c4a80",
|
||||
"chat_id": 3,
|
||||
"url": "https://example.com/hook"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `DELETE /api/v1/chats/{id}/webhooks/{webhook_id}`
|
||||
|
||||
Removes the webhook `webhook_id` from the chat `id`, and answers `204`
|
||||
with no body.
|
||||
|
||||
```sh
|
||||
curl -X DELETE -H "Authorization: Bearer $TOKEN" \
|
||||
http://127.0.0.1:8080/api/v1/chats/3/webhooks/5f0c7a1e9b2d4c8e3a6f1b7d2e9c4a80
|
||||
```
|
||||
|
||||
Nothing is removed, and the answer is:
|
||||
|
||||
- `404` if `GET /api/v1/chats` does not list `id`, or the chat has no
|
||||
webhook `webhook_id`;
|
||||
- `500` if `webhooks.json` cannot be written.
|
||||
|
||||
## Entrypoints
|
||||
|
||||
This repo adheres to the
|
||||
@@ -315,6 +400,12 @@ container.
|
||||
the one that delivers events, which also delivers the chat client's
|
||||
answers. When the bot stops, requests in progress get 5 seconds to
|
||||
finish before the chat client is stopped.
|
||||
- **Webhooks** (`internal/api`) are read from `$DATA_DIR/webhooks.json`
|
||||
before the chat client starts. Changes are made one at a time, and
|
||||
each rewrites the file whole: the bot writes a temporary file beside
|
||||
it, named `webhooks.json.` and digits, and renames it over the old
|
||||
one. A crash leaves the old file or the new one, never part of one,
|
||||
and at worst a stray temporary file, which the bot ignores.
|
||||
- **Replies**: for each text message a contact sends in a direct chat,
|
||||
the bot sends back the result, as a reply quoting the message. Group
|
||||
messages, files and the bot's own messages are ignored.
|
||||
@@ -363,12 +454,13 @@ container.
|
||||
## Operating it
|
||||
|
||||
**Backup.** Everything durable is on the volume: the SimpleX database,
|
||||
`simplex_chat.db` and `simplex_agent.db`, and the API credential,
|
||||
`api-token`. Stop the container before copying the database, since a
|
||||
copy taken from under the running client can be inconsistent. The
|
||||
database holds the bot's keys, so a copy lets its holder answer as the
|
||||
bot, and the credential lets its holder use the API; keep both as
|
||||
private as the running instance.
|
||||
`simplex_chat.db` and `simplex_agent.db`; the API credential,
|
||||
`api-token`; and the webhooks, `webhooks.json`. Stop the container
|
||||
before copying the database, since a copy taken from under the running
|
||||
client can be inconsistent. The database holds the bot's keys, so a copy
|
||||
lets its holder answer as the bot; the credential lets its holder use
|
||||
the API; and a webhook's URL can hold a secret of the program it points
|
||||
at. Keep all three as private as the running instance.
|
||||
|
||||
**Upgrade.** Rebuild the image and recreate the container with the same
|
||||
volume. The chat client migrates its database on start. A newer
|
||||
|
||||
Reference in New Issue
Block a user