diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..58456ff --- /dev/null +++ b/docs/api.md @@ -0,0 +1,386 @@ +# HTTP API 接口文档 + +本文档根据 `src/http_handler` 下各 handler 的 `handle_request/4` 实现整理。 + +## 通用说明 + +- HTTP 服务端口由应用配置 `sdlan.http_server.port` 决定。 +- 响应 `Content-Type` 为 `application/json;charset=utf-8`。 +- 当响应体大小大于等于 1024 字节且请求头 `Accept-Encoding` 包含 `gzip` 时,响应会启用 gzip 压缩。 +- GET 参数来自 URL query string。 +- POST 请求体支持两种格式: + - `Content-Type: application/json`:请求体会按 JSON object 解析,数字保持为 JSON number。 + - `Content-Type: application/x-www-form-urlencoded`:请求体会按表单解析,参数值为 binary/string;涉及整型参数的接口建议使用 JSON 请求体。 +- 统一成功返回格式: + +```json +{ + "result": "" +} +``` + +- 统一失败返回格式: + +```json +{ + "error": { + "code": -1, + "message": "错误描述" + } +} +``` + +- handler 未匹配到 URL、Method 或参数结构时,通常返回 HTTP 200,并返回如下错误格式: + +```json +{ + "error": { + "code": -1, + "message": "url: /path not found" + } +} +``` + +## binlog_handler + +路由配置:`/binlog` + +### POST /binlog + +接收 binlog 通知,目前只记录请求参数并返回固定结果。 + +**Method**:`POST` + +**参数**:无必填参数。请求体可为 JSON object 或 form。 + +| 参数 | 位置 | 类型 | 必填 | 说明 | +| --- | --- | --- | --- | --- | +| 任意字段 | body | object/string/number/boolean/array | 否 | 当前实现不读取具体字段,仅打印完整请求体参数。 | + +**成功返回**: + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| result | string | 固定为 `"ok"`。 | + +示例: + +```json +{ + "result": "ok" +} +``` + +## test_handler + +路由配置:`/test/[...]` + +### POST /test/auth_access_token + +测试用 access token 校验接口,目前返回固定结果。 + +**Method**:`POST` + +**参数**:无必填参数。请求体可为 JSON object 或 form。 + +| 参数 | 位置 | 类型 | 必填 | 说明 | +| --- | --- | --- | --- | --- | +| 任意字段 | body | object/string/number/boolean/array | 否 | 当前实现不读取具体字段。 | + +**成功返回**: + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| result | string | 固定为 `"ok"`。 | + +示例: + +```json +{ + "result": "ok" +} +``` + +### GET /test/get_all_networks + +测试用获取全部网络 ID。 + +**Method**:`GET` + +**参数**:无。 + +**成功返回**: + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| result | array<integer> | 网络 ID 列表。当前实现固定返回 `[8]`。 | + +示例: + +```json +{ + "result": [8] +} +``` + +### GET /test/get_network + +测试用获取单个网络详情。 + +**Method**:`GET` + +**参数**: + +| 参数 | 位置 | 类型 | 必填 | 说明 | +| --- | --- | --- | --- | --- | +| id | query | string(integer) | 是 | 网络 ID。实现中会通过 `binary_to_integer/1` 转为 integer;当前仅内置 ID `8`。 | + +**成功返回**: + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| result | object | 网络详情对象。 | +| result.id | integer | 网络 ID。 | +| result.name | string | 网络名称。 | +| result.domain | string | 网络域名。 | +| result.ipaddr | string | 网络地址段,CIDR 格式。 | +| result.owner_id | integer | 所属用户 ID。 | +| result.algorithm | string | 加密算法。 | +| result.disabled_clients | array<string> | 禁用的客户端 ID 列表。 | + +示例: + +```json +{ + "result": { + "id": 8, + "name": "test1", + "domain": "punchnet.cn", + "ipaddr": "10.211.179.0/24", + "owner_id": 1234, + "algorithm": "chacha20", + "disabled_clients": [] + } +} +``` + +## api_handler + +路由配置:`/api/[...]` + +注意:当前 `api_handler` 的实现匹配路径为 `/test/auth_token`,但 Cowboy 路由只会把 `/api/[...]` 请求分发给 `api_handler`。因此按当前路由配置,该接口不可达;直接请求 `/test/auth_token` 会被分发到 `test_handler`,也不会命中此实现。 + +### POST /test/auth_token + +获取测试 auth token 信息,返回第一个网络 ID。 + +**Method**:`POST` + +**当前可达性**:不可达,原因见本节说明。 + +**参数**:无必填参数。请求体可为 JSON object 或 form。 + +| 参数 | 位置 | 类型 | 必填 | 说明 | +| --- | --- | --- | --- | --- | +| 任意字段 | body | object/string/number/boolean/array | 否 | 当前实现不读取具体字段,仅打印完整请求体参数。 | + +**成功返回**: + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| result | object | 返回数据对象。 | +| result.network_id | integer | `network_bo:get_all_networks/0` 返回列表中的第一个网络 ID。 | + +示例: + +```json +{ + "result": { + "network_id": 8 + } +} +``` + +## network_handler + +路由配置:`/network/[...]` + +### POST /network/create + +启动或确保指定网络已启动。 + +**Method**:`POST` + +**参数**: + +| 参数 | 位置 | 类型 | 必填 | 说明 | +| --- | --- | --- | --- | --- | +| id | body | integer | 是 | 网络 ID,需大于 0。建议使用 JSON number。 | + +请求示例: + +```json +{ + "id": 8 +} +``` + +**成功返回**: + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| result | string | 固定为 `"success"`。 | + +示例: + +```json +{ + "result": "success" +} +``` + +**失败返回**: + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| error.code | integer | 固定为 `-1`。 | +| error.message | string | 固定为 `"error"`。 | + +### POST /network/delete + +删除指定网络;如果网络未启动,也视为删除成功。 + +**Method**:`POST` + +**参数**: + +| 参数 | 位置 | 类型 | 必填 | 说明 | +| --- | --- | --- | --- | --- | +| id | body | integer | 是 | 网络 ID,需大于 0。建议使用 JSON number。 | + +请求示例: + +```json +{ + "id": 8 +} +``` + +**成功返回**: + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| result | string | 固定为 `"success"`。 | + +示例: + +```json +{ + "result": "success" +} +``` + +**失败返回**: + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| error.code | integer | 固定为 `-1`。 | +| error.message | string | 固定为 `"error"`。 | + +### POST /network/exit_node_control + +向指定客户端下发出口节点控制命令,并等待客户端 ACK。 + +**Method**:`POST` + +**参数**: + +| 参数 | 位置 | 类型 | 必填 | 说明 | +| --- | --- | --- | --- | --- | +| id | body | integer | 是 | 网络 ID,需大于 0。建议使用 JSON number。 | +| action | body | integer | 是 | 出口节点动作,传入 `SDLCommand.ExitNodeControl.action`。历史文档约定:`0` 表示关闭,`1` 表示开启。 | +| client_id | body | string | 是 | 目标客户端 ID。 | +| remark | body | string | 是 | 下发备注,用于跟踪命令;可传空字符串。 | +| timeout | body | integer | 是 | 等待 ACK 的超时时间,单位秒。实现中会转换为毫秒。 | + +请求示例: + +```json +{ + "id": 8, + "action": 1, + "client_id": "client-id", + "remark": "trace remark", + "timeout": 10 +} +``` + +**成功返回**: + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| result | string | 正常 ACK 时固定为 `"success"`。 | + +示例: + +```json +{ + "result": "success" +} +``` + +**其他返回**: + +| 场景 | 返回格式 | 字段类型 | 说明 | +| --- | --- | --- | --- | +| 网络不存在 | `{"result":"network not found"}` | result: string | 当前实现将网络不存在作为 result 返回,而不是 error。 | +| 命令发送失败 | `{"error":{"code":-1,"message":"..."}}` | code: integer, message: string | message 为底层返回的 Reason,需为可 JSON 编码值。 | +| 客户端 ACK 失败 | `{"error":{"code":,"message":""}}` | code: integer, message: string | Code 和 Message 来自 `SDLCommandAck`。 | +| 等待 ACK 超时 | `{"error":{"code":-1,"message":"任务执行超时"}}` | code: integer, message: string | 超过 `timeout` 秒未收到 ACK。 | + +## node_handler + +路由配置:`/node/[...]` + +### POST /node/disable + +禁用指定网络中的客户端节点。 + +**Method**:`POST` + +**参数**: + +| 参数 | 位置 | 类型 | 必填 | 说明 | +| --- | --- | --- | --- | --- | +| network_id | body | integer | 是 | 网络 ID,需大于 0。建议使用 JSON number。 | +| client_id | body | string | 是 | 客户端 ID。 | + +请求示例: + +```json +{ + "network_id": 8, + "client_id": "client-id" +} +``` + +**成功返回**: + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| result | string | 固定为 `"success"`。 | + +示例: + +```json +{ + "result": "success" +} +``` + +**失败返回**: + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| error.code | integer | 固定为 `-1`。 | +| error.message | string | 当前实现中网络不存在时为 `"network not found"`。 |