add Sphinx documentation

This commit is contained in:
ars
2026-06-25 02:39:25 +03:00
parent 66b60b9bcb
commit 6261403503
10 changed files with 283 additions and 142 deletions
+89 -89
View File
@@ -2,15 +2,15 @@
## Transport
- Протокол: HTTPS.
- Формат тела запроса и ответа: JSON.
- Префикс API: `/api/v1`.
- Формат времени: RFC 3339 / ISO 8601, например `2026-05-24T13:20:30Z`.
- Авторизация клиента: bearer token в заголовке `Authorization`.
- Protocol: HTTPS.
- Request and response body format: JSON.
- API prefix: `/api/v1`.
- Time format: RFC 3339 / ISO 8601, e.g. `2026-05-24T13:20:30Z`.
- Client authorization: bearer token in the `Authorization` header.
Пример заголовков:
Example headers:
```http
```text
Content-Type: application/json
Authorization: Bearer <client-token>
```
@@ -19,12 +19,12 @@ Authorization: Bearer <client-token>
### `POST /api/v1/client/heartbeat`
Клиент вызывает эту ручку на каждом polling tick. Одна и та же ручка
используется для трёх сценариев:
The client calls this endpoint on every polling tick. The same endpoint serves
three scenarios:
- сообщение "я жив";
- регулярное обновление состояния;
- отправка результата последней завершённой команды.
- an "I'm alive" message;
- a regular state update;
- reporting the result of the last finished command.
### Request
@@ -45,19 +45,19 @@ Authorization: Bearer <client-token>
}
```
Поля:
Fields:
- `client_id` - стабильный идентификатор, заданный при настройке клиента. Он не
должен меняться при каждом рестарте.
- `observed_at` - момент, когда клиент подготовил payload.
- `client.hostname` - текущий hostname машины.
- `client.platform` - платформа клиента. Желательно использовать названия,
близкие к Python/platform: `linux`, `darwin`, `windows`.
- `client.version` - версия nexus-sync client.
- `state` - намеренно маленький объект. Может быть сюда позже можно добавить IP,
disk usage, memory, battery status и другие метрики.
- `last_command_result` - `null`, если клиенту нечего нового сообщать о
выполнении команды.
- `client_id` - a stable identifier set during client setup. It must not change
on every restart.
- `observed_at` - the moment the client prepared the payload.
- `client.hostname` - the machine's current hostname.
- `client.platform` - the client platform. Prefer names close to
Python/platform: `linux`, `darwin`, `windows`.
- `client.version` - the nexus-sync client version.
- `state` - an intentionally small object. IP, disk usage, memory, battery
status and other metrics may be added here later.
- `last_command_result` - `null` if the client has nothing new to report about
command execution.
### Request with command result
@@ -86,17 +86,16 @@ Authorization: Bearer <client-token>
}
```
Поля результата:
Result fields:
- `command_id` должен совпадать с id команды, которую сервер ранее вернул
клиенту.
- `status` принимает одно из значений: `succeeded`, `failed`, `timed_out`,
`rejected`.
- `return_code` - exit code процесса, если процесс был запущен. Для
`timed_out` или `rejected` поле может быть `null`, если финального exit code
нет.
- `stdout` и `stderr` клиент должен ограничивать по размеру перед отправкой.
Конкретный лимит байт в этом контракте пока не фиксируется.
- `command_id` must match the id of the command the server previously returned
to the client.
- `status` takes one of: `succeeded`, `failed`, `timed_out`, `rejected`.
- `return_code` - the process exit code, if the process was started. For
`timed_out` or `rejected` the field may be `null` when there is no final exit
code.
- `stdout` and `stderr` must be size-limited by the client before sending. This
contract does not yet fix a specific byte limit.
### Response without command
@@ -126,36 +125,37 @@ Authorization: Bearer <client-token>
}
```
Поля команды:
Command fields:
- `id` генерируется сервером и должен быть уникальным.
- `kind` описывает тип executor. Пока определён только `exec`.
- `name` - имя command preset.
- `args` содержит аргументы, специфичные для конкретного preset.
- `timeout_seconds` - максимальное время выполнения, которое сервер допускает
для этой команды.
- `id` is generated by the server and must be unique.
- `kind` describes the executor type. Only `exec` is defined so far.
- `name` - the command preset name.
- `args` holds arguments specific to a particular preset.
- `timeout_seconds` - the maximum execution time the server allows for this
command.
Клиент обязан выполнять только те команды, которые он знает и локально
разрешает. Неизвестные или запрещённые команды нужно возвращать как `rejected`.
The client must run only commands it knows and locally allows. Unknown or
forbidden commands must be returned as `rejected`.
## Server-side API
Эти ручки нужны серверной части/админке, чтобы видеть клиентов и ставить им
команды в очередь. Клиенты напрямую используют только heartbeat.
These endpoints are for the server/admin side, to see clients and queue commands
for them. Clients directly use only the heartbeat.
### `GET /api/v1/server/clients`
Возвращает список известных клиентов с последними heartbeat-данными и
Returns the list of known clients with their latest heartbeat data and
`available_commands`.
### `GET /api/v1/server/clients/{client_id}`
Возвращает одного клиента или `404`, если сервер ещё не видел этот `client_id`.
Returns a single client, or `404` if the server has not seen this `client_id`
yet.
### `POST /api/v1/server/clients/{client_id}/commands`
Создаёт pending-команду для клиента. Клиент получит её на следующем heartbeat.
Эта ручка принимает имя команды напрямую.
Creates a pending command for the client. The client receives it on its next
heartbeat. This endpoint accepts the command name directly.
Request:
@@ -188,66 +188,66 @@ Response:
### `GET /api/v1/server/commands/{command_id}`
Возвращает команду и, если клиент уже отчитался, поле `result`.
Returns the command and, if the client has already reported, the `result` field.
## Command lifecycle
Жизненный цикл команды:
Command lifecycle:
1. `pending`: команда создана на сервере и ещё не доставлена клиенту.
2. `delivered`: команда была возвращена клиенту в heartbeat response.
3. `succeeded`: клиент сообщил об успешном выполнении.
4. `failed`: клиент сообщил об ошибке выполнения.
5. `timed_out`: клиент сообщил о timeout.
6. `rejected`: клиент отказался выполнять команду.
1. `pending`: the command was created on the server and not yet delivered to the
client.
2. `delivered`: the command was returned to the client in a heartbeat response.
3. `succeeded`: the client reported successful execution.
4. `failed`: the client reported an execution error.
5. `timed_out`: the client reported a timeout.
6. `rejected`: the client refused to run the command.
Терминальные статусы: `succeeded`, `failed`, `timed_out`, `rejected`.
Terminal statuses: `succeeded`, `failed`, `timed_out`, `rejected`.
## HTTP statuses
Heartbeat endpoint должен использовать такие HTTP-статусы:
The heartbeat endpoint should use these HTTP statuses:
- `200 OK`: heartbeat принят; тело ответа соответствует контракту выше.
- `400 Bad Request`: некорректный JSON или невалидные значения полей.
- `401 Unauthorized`: bearer token отсутствует или невалиден.
- `403 Forbidden`: token валиден, но не имеет права действовать как этот
- `200 OK`: heartbeat accepted; the response body matches the contract above.
- `400 Bad Request`: malformed JSON or invalid field values.
- `401 Unauthorized`: the bearer token is missing or invalid.
- `403 Forbidden`: the token is valid but not allowed to act as this
`client_id`.
- `409 Conflict`: результат ссылается на неизвестную, уже терминальную или
несовместимую команду.
- `429 Too Many Requests`: клиент опрашивает сервер слишком часто.
- `500 Internal Server Error`: неожиданная ошибка сервера.
- `409 Conflict`: the result references an unknown, already terminal, or
incompatible command.
- `429 Too Many Requests`: the client polls the server too often.
- `500 Internal Server Error`: an unexpected server error.
Состояние выполнения команды выражается полями в JSON, а не HTTP-ошибками.
Например, команда с exit code `1` всё равно отправляется через успешный
Command execution state is expressed via JSON fields, not HTTP errors. For
example, a command with exit code `1` is still delivered over a successful
heartbeat request.
## Polling rules
Ответ сервера содержит `next_poll_after_seconds`.
The server response contains `next_poll_after_seconds`.
Поведение:
Behavior:
- обычный polling interval без команды: 60 секунд;
- polling interval после получения команды: 10 секунд;
- клиентский минимальный interval: 5 секунд;
- клиентский максимальный interval: 300 секунд.
- normal polling interval without a command: 60 seconds;
- polling interval after receiving a command: 10 seconds;
- client minimum interval: 5 seconds;
- client maximum interval: 300 seconds.
Клиент должен воспринимать значение сервера как рекомендацию и зажимать его в
локальные min/max границы.
The client should treat the server value as a recommendation and clamp it to its
local min/max bounds.
## Security constraints
Необходимо соблюдать эти ограничения:
The following constraints must be respected:
- не выполнять произвольные shell-строки, полученные от сервера;
- выполнять только локально известные command presets;
- требовать bearer token для клиентских endpoint'ов;
- включать `command_id` в каждый результат, чтобы не было неоднозначного
сопоставления;
- хранить command output как логи, а не как доверенные управляющие данные;
- ограничивать размер command output перед отправкой на сервер;
- выполнять каждую команду с timeout.
- do not run arbitrary shell strings received from the server;
- run only locally known command presets;
- require a bearer token for client endpoints;
- include `command_id` in every result to avoid ambiguous matching;
- store command output as logs, not as trusted control data;
- limit the size of command output before sending it to the server;
- run every command with a timeout.
Эти ограничения намеренно являются частью контракта, потому что проект
занимается удалённым управлением машинами. Дешевле строить первую реализацию
вокруг них, чем добавлять их задним числом.
These constraints are intentionally part of the contract because the project
deals with remote machine management. It is cheaper to build the first
implementation around them than to add them after the fact.