HTTP 接口
danio 的 HTTP 接口:地址、令牌与权限、错误格式、事件流、OpenAPI 描述,以及常用接口。
danio 自己的界面、命令行、Blender 扩展、插件,以及加入工作区的设备,调用的是同一套 HTTP 接口。你写的脚本也可以用它。
接口都在 /api/v1/ 下,数据用 JSON。每个接口的参数、返回值和所需权限,都在 OpenAPI 描述里,本页只讲约定和最常用的接口。
地址
| 地址 | 谁用 | 令牌 |
|---|---|---|
http://127.0.0.1:7421 | 这台电脑上的程序。端口被占用时往上找,:ui设置 → 接口 里显示实际地址 | 本机令牌 |
| 主机的工作区地址,默认端口 7420 | 其他电脑上的设备和脚本。主机要先对其他设备开放这个端口 | 工作区令牌 |
端口的设置见本机配置。
令牌和权限
请求带上令牌:
Authorization: Bearer <令牌>
| 令牌 | 能做什么 | 从哪来 |
|---|---|---|
| 本机令牌 | 这台电脑的引擎能做的一切,包括只在本机的接口 | 设置 → 本机令牌 里看;也可以用 DANIO_TOKEN 固定 |
| 集成令牌 | 只有你选的权限级别 | 工作区详情的 插件与集成 页,或 danio workspace token add <名称> --access <级别> --integration |
| 设备令牌 | 设备加入工作区、渲染用,也带一个权限级别 | 添加设备时生成,见令牌 |
集成令牌只在生成时显示一次,用 轮换 换新,旧的立即失效。
工作区权限有 9 项,权限级别是它们的组合:
| 权限 | 能做什么 |
|---|---|
workspace.view | 查看项目、任务、进度、预览、设备、用量 |
output.download | 下载成片和各镜头的片段 |
job.submit | 提交任务;更新、暂停、继续、取消、重渲、删除自己提交的任务 |
job.manage | 控制所有人的任务,改队列顺序和镜头分配 |
project.edit | 新建、修改、删除项目 |
device.manage | 添加设备、批准加入申请、改设备的权限和设置、拉黑 |
storage.manage | 存储、资源包、回收 |
plugin.manage | 插件和集成令牌 |
workspace.manage | 工作区设置、备份、接管 |
级别 无 没有权限,:ui查看 有前两项,:ui工作站 再加 job.submit 和 project.edit,:ui管理 是全部。
OpenAPI 里每个接口的 x-required-permission 写着它要哪一项。除了上面 9 项,还有四种写法:
| 写法 | 含义 |
|---|---|
public | 不要令牌,设备加入时用 |
token | 任何带有效令牌的请求 |
device | 只有设备令牌 |
local | 只有本机令牌 |
权限不够时返回 403,错误码是 forbidden,说明缺哪一项。GET /api/v1/me 返回当前令牌的身份和权限。
错误
出错时返回 application/problem+json:
{
"type": "urn:danio:error:version-conflict",
"title": "Conflict",
"status": 409,
"detail": "…"
}
type 是稳定的错误码,程序按它判断;detail 给人看,语言跟请求的 Accept-Language,没写这个头或以 zh 开头是中文,其余是英文。校验不过的字段列在 errors 里;提交检查没通过时,原因列在 checks 里。
| 错误码 | 状态 | 什么时候 |
|---|---|---|
invalid-request | 400 | 请求本身不对 |
unauthorized | 401 | 没带令牌,或令牌无效 |
forbidden | 403 | 权限不够,或这个来源不被允许 |
not-found | 404 | 找不到 |
conflict | 409 | 和现状冲突 |
version-conflict | 409 | 有人先更新了任务 |
precondition-failed | 412 | If-Match 对不上 |
validation-failed | 422 | 字段没通过校验 |
check-failed | 422 | 提交的检查没通过 |
too-many-requests | 429 | 请求太多 |
render-limit | 403 | 同时渲染的设备数已达工作区的上限 |
lease-ended | 409 | 设备领的段已结束 |
lease-taken | 409 | 设备领的段已交给别的设备 |
internal | 500 | danio 内部出错 |
重试和并发
- 提交任务(
POST /api/v1/jobs)、更新任务(POST /api/v1/jobs/{id}/versions)和比对草稿(POST /api/v1/jobs/{id}/versions/draft)可以带Idempotency-Key,自己取一个值。24 小时内用同一个键重试,返回第一次的结果,不会重复登记。只有成功的结果会被记住,失败后重试会重新执行。 - 同样这三个接口可以带
X-Danio-Request,自己取一个 ID。提交进度事件submit.progress带着它,你可以认出哪条是自己的。 - 更新任务时带
baseVersion。已有更新的版本时返回 409,错误码version-conflict,请基于最新版本重新比对。 - 项目的读取返回
ETag,修改(PATCH /api/v1/projects/{id})时用If-Match带回去。别人先改过就返回 412。
列表
GET /api/v1/jobs 和 GET /api/v1/projects 分页:用 limit 指定每页多少条,返回里的 next 填进下一次请求的 cursor。next 为空就是最后一页。任务列表还能用 project(项目 ID)、name(任务名,只在项目内唯一)和 blend(Blend 文件 ID)过滤。
路径里的 {id} 只接受 ID。按名称找,用查询参数。
事件流
GET /api/v1/events 是 Server-Sent Events 长连接,需要 workspace.view:
curl -N -H "Authorization: Bearer $TOKEN" http://127.0.0.1:7421/api/v1/events
每个事件有 id、event(类型)和 data(JSON)。id 是字符串,不要当数字比较。连接每 15 秒发一行 : ping 注释,用来保活。
断线重连时,带上最后收到的 Last-Event-ID,danio 补发错过的事件。它保留最近 1024 个事件;补不上时(danio 重启过,或断开太久)先发一个 reset 事件,这时请重新读取状态。
OpenAPI 里列出的事件:
| 事件 | 什么时候 |
|---|---|
submit.progress | 提交的进度。request 字段是你在 X-Danio-Request 里给的 ID |
render.progress | 这台电脑渲染的进度和状态变化 |
queue.changed | 排队变了:有任务加入,或顺序变了 |
device.room | 设备磁盘空间不足、已满或已恢复 |
workspace.devices | 设备列表变了:有设备加入、离开,或改了设置、名称、权限、拉黑 |
workspace.join-request | 局域网里有设备申请加入 |
workspace.license | 授权导入或移除了 |
notice | 这台设备的窗口程序要弹的提示 |
window.show | danio 窗口要打开某一页 |
reset | 错过的事件补不上,请重新读取状态 |
流里还会有别的事件。不认识的事件类型,忽略就行。
OpenAPI 描述
完整的接口描述是 OpenAPI 3.1 的 JSON,有两种拿法:
# 命令行输出,默认中文
danio openapi > openapi.json
# 英文
danio openapi --lang en > openapi.json
# 从运行中的 danio 取,带任意有效令牌
curl -H "Authorization: Bearer $TOKEN" \
"http://127.0.0.1:7421/api/openapi.json?lang=en" -o openapi.json
lang 可以是 zh-CN 或 en。不写时按 Accept-Language 选,规则和错误信息一样。
命令行输出里的 info.version 是 dev,运行中的 danio 给的是它自己的版本。
设置 → 接口 里的 接口文档 在界面里打开同一份描述,能直接浏览。
用 OpenAPI 的通用工具就能生成客户端,如 openapi-typescript、openapi-python-client。
常用接口
下表的权限是用工作区令牌调用时需要的。本机令牌不受限制。完整的列表和参数看 OpenAPI。
状态和身份
| 接口 | 权限 | 作用 |
|---|---|---|
GET /api/v1/health | token | 引擎是否在运行,返回版本和启动时间 |
GET /api/v1/me | token | 当前令牌的身份和权限 |
GET /api/v1/workspace | workspace.view | 这台电脑当主机的工作区:名称、设置、监听的地址 |
项目和任务
| 接口 | 权限 | 作用 |
|---|---|---|
GET /api/v1/projects | workspace.view | 项目列表 |
POST /api/v1/projects | project.edit | 新建项目 |
GET /api/v1/projects/{id} | workspace.view | 项目,返回 ETag |
PATCH /api/v1/projects/{id} | project.edit | 修改项目的设置,带 If-Match |
GET /api/v1/jobs | workspace.view | 任务列表,新的在前 |
POST /api/v1/jobs | job.submit | 提交任务,一个场景一个任务 |
GET /api/v1/jobs/{id} | workspace.view | 任务详情 |
DELETE /api/v1/jobs/{id} | job.submit | 删除任务 |
POST /api/v1/jobs/{id}/pause | job.submit | 暂停,已渲染的帧保留 |
POST /api/v1/jobs/{id}/resume | job.submit | 继续 |
POST /api/v1/jobs/{id}/cancel | job.submit | 取消 |
POST /api/v1/jobs/{id}/versions/draft | job.submit | 和最新版本比对,出更新的草稿 |
POST /api/v1/jobs/{id}/versions | job.submit | 更新任务,生成新版本 |
GET /api/v1/jobs/{id}/preview | workspace.view | 一帧的预览,JPEG,frame 不写为最新一帧 |
GET /api/v1/jobs/{id}/films | workspace.view | 各版本的成片 |
GET /api/v1/jobs/{id}/film | output.download | 下载成片,version 不写为当前版本;还没生成时返回 404 |
设备和令牌
| 接口 | 权限 | 作用 |
|---|---|---|
GET /api/v1/devices | workspace.view | 设备列表 |
PATCH /api/v1/devices/{id} | device.manage | 改名称、权限,拉黑或解除拉黑 |
DELETE /api/v1/devices/{id} | device.manage | 移除设备 |
GET /api/v1/tokens | device.manage | 令牌列表 |
POST /api/v1/tokens | device.manage | 生成令牌,完整的令牌只在这次返回 |
POST /api/v1/tokens/{id}/rotate | device.manage | 轮换集成令牌 |
DELETE /api/v1/tokens/{id} | device.manage | 作废令牌 |
插件
| 接口 | 权限 | 作用 |
|---|---|---|
GET /api/v1/plugins | plugin.manage | 插件列表 |
POST /api/v1/plugins | plugin.manage | 安装插件,装好后是停用的 |
POST /api/v1/plugins/{id}/enable | plugin.manage | 启用,要带上它声明的权限 |
POST /api/v1/plugins/{id}/disable | plugin.manage | 停用 |
PUT /api/v1/plugins/{id}/settings | plugin.manage | 改设置 |
GET /api/v1/jobs/{id}/handovers | workspace.view | 成片交给插件的情况 |
POST /api/v1/jobs/{id}/handovers/{plugin}/retry | job.submit | 重新交给插件 |
例子
列出任务,再暂停其中一个:
curl -H "Authorization: Bearer $TOKEN" "http://192.168.1.20:7420/api/v1/jobs?limit=20"
curl -X POST -H "Authorization: Bearer $TOKEN" \
http://192.168.1.20:7420/api/v1/jobs/<任务 ID>/pause
这里的 192.168.1.20:7420 换成你主机的工作区地址。