docs: rewrite README and add Chinese docs (README.zh-CN.md)
This commit is contained in:
297
README.md
297
README.md
@@ -1,167 +1,43 @@
|
|||||||
# Kotlin Script Host (Gradle Project)
|
# slhaf-hub
|
||||||
|
|
||||||
This project provides two runtime entrypoints while keeping dynamic script loading from `scripts/`.
|
Kotlin-based dynamic script host with HTTP APIs, root/sub token auth, script metadata, timeout control, and companion CLI/TUI tools.
|
||||||
|
|
||||||
## Run CLI host
|
Language:
|
||||||
|
- English: `README.md`
|
||||||
|
- 中文: `README.zh-CN.md`
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Dynamic script loading from `scripts/*.hub.kts` without restarting host
|
||||||
|
- Root/Sub token authorization model
|
||||||
|
- Metadata in script comments (`@desc`, `@timeout`, `@param`)
|
||||||
|
- Script CRUD + run + metadata APIs
|
||||||
|
- Subtoken management APIs
|
||||||
|
- Run concurrency limit (`--max-run-concurrency`)
|
||||||
|
- Script timeout (default 10s, script-level override)
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
- JDK 17+
|
||||||
|
- Gradle (or Gradle wrapper)
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
### Server
|
||||||
|
#### 1) Run from terminal (Gradle)
|
||||||
```bash
|
```bash
|
||||||
cd /tmp/kotlin-scripts
|
cd /tmp/kotlin-scripts
|
||||||
./gradlew runCli --args='scripts/hello.hub.kts'
|
|
||||||
./gradlew runCli --args='scripts/hello.hub.kts --arg=name=Codex --arg=upper=true'
|
|
||||||
```
|
|
||||||
|
|
||||||
Watch mode:
|
|
||||||
```bash
|
|
||||||
./gradlew runCli --args='scripts/hello.hub.kts --watch --debounce-ms=200'
|
|
||||||
```
|
|
||||||
|
|
||||||
## Run Web host (Ktor)
|
|
||||||
```bash
|
|
||||||
./gradlew runWeb --args='--host=0.0.0.0 --port=8080 --scripts-dir=./scripts'
|
./gradlew runWeb --args='--host=0.0.0.0 --port=8080 --scripts-dir=./scripts'
|
||||||
```
|
```
|
||||||
|
|
||||||
Auth:
|
#### 2) Run with Docker
|
||||||
- Use `Authorization: Bearer <token>` for all APIs except `/health`.
|
|
||||||
- Token source:
|
|
||||||
- Preferred: set env `HOST_API_TOKEN`.
|
|
||||||
- Otherwise host auto-generates a token and stores it at `scripts/.host-api-token`.
|
|
||||||
- Token types:
|
|
||||||
- `root`: full access to all endpoints.
|
|
||||||
- `sub`: only `health`, filtered `scripts`, and allowed-script `meta`/`run`.
|
|
||||||
|
|
||||||
Routes:
|
|
||||||
- `GET /health`
|
|
||||||
- `GET /type`
|
|
||||||
- `GET /scripts`
|
|
||||||
- `GET /scripts/{script}` (raw script content)
|
|
||||||
- `POST /scripts/{script}`
|
|
||||||
- `PUT /scripts/{script}`
|
|
||||||
- `DELETE /scripts/{script}`
|
|
||||||
- `GET /meta/{script}`
|
|
||||||
- `GET /run/{script}?k=v`
|
|
||||||
- `POST /run/{script}?k=v`
|
|
||||||
- `GET /subtokens` (root only)
|
|
||||||
- `GET /subtokens/{name}` (root only)
|
|
||||||
- `POST /subtokens/{name}` (root only, body = script names list)
|
|
||||||
- `PUT /subtokens/{name}` (root only, body = script names list)
|
|
||||||
- `DELETE /subtokens/{name}` (root only)
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
```bash
|
|
||||||
curl 'http://127.0.0.1:8080/health'
|
|
||||||
TOKEN="$(cat scripts/.host-api-token)"
|
|
||||||
curl -H "Authorization: Bearer $TOKEN" 'http://127.0.0.1:8080/type'
|
|
||||||
curl -H "Authorization: Bearer $TOKEN" 'http://127.0.0.1:8080/scripts'
|
|
||||||
curl -H "Authorization: Bearer $TOKEN" 'http://127.0.0.1:8080/scripts/hello'
|
|
||||||
curl -H "Authorization: Bearer $TOKEN" -X POST 'http://127.0.0.1:8080/scripts/new-api' --data-binary $'// @desc: new api\nval args: Array<String> = emptyArray()\nprintln("ok")'
|
|
||||||
curl -H "Authorization: Bearer $TOKEN" -X PUT 'http://127.0.0.1:8080/scripts/new-api' --data-binary $'// @desc: new api v2\nval args: Array<String> = emptyArray()\nprintln("ok-v2")'
|
|
||||||
curl -H "Authorization: Bearer $TOKEN" -X DELETE 'http://127.0.0.1:8080/scripts/new-api'
|
|
||||||
curl -H "Authorization: Bearer $TOKEN" 'http://127.0.0.1:8080/meta/hello'
|
|
||||||
curl -H "Authorization: Bearer $TOKEN" 'http://127.0.0.1:8080/run/hello?name=Alice&upper=true'
|
|
||||||
curl -H "Authorization: Bearer $TOKEN" -X POST 'http://127.0.0.1:8080/run/hello?name=Alice' -d 'from-body'
|
|
||||||
curl -H "Authorization: Bearer $TOKEN" -X POST 'http://127.0.0.1:8080/subtokens/demo-sub' --data-binary $'hello\ntime'
|
|
||||||
curl -H "Authorization: Bearer $TOKEN" 'http://127.0.0.1:8080/subtokens'
|
|
||||||
```
|
|
||||||
|
|
||||||
## Script Metadata & Args (`*.hub.kts`)
|
|
||||||
Scripts declare metadata in comments and receive request arguments through explicit `args` declaration:
|
|
||||||
|
|
||||||
```kotlin
|
|
||||||
// @desc: Demo greeting API
|
|
||||||
// @param: name | default=world | desc=Name to greet
|
|
||||||
// @param: token | required=true | desc=Required token
|
|
||||||
|
|
||||||
val args: Array<String> = emptyArray()
|
|
||||||
val kv = args.mapNotNull {
|
|
||||||
val i = it.indexOf('=')
|
|
||||||
if (i <= 0) null else it.substring(0, i) to it.substring(i + 1)
|
|
||||||
}.toMap()
|
|
||||||
|
|
||||||
val name = kv["name"] ?: "world"
|
|
||||||
val token = kv["token"] ?: error("token required")
|
|
||||||
println("hello $name, token=$token")
|
|
||||||
```
|
|
||||||
|
|
||||||
## Dynamic scripts
|
|
||||||
You can add/remove `*.hub.kts` files in `scripts/` at any time. The web host resolves scripts by route name (`/run/{script}` -> `scripts/{script}.hub.kts`) on each request, so newly added scripts are available immediately.
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
- This keeps runtime behavior dynamic; Gradle is used for dependency resolution and launching, not for precompiling scripts.
|
|
||||||
- IDE completion for regular Kotlin sources (`src/main/kotlin`) is fully modelled by Gradle.
|
|
||||||
- You do not need a package/build artifact step before each run. `runCli` and `runWeb` launch directly from source; scripts are compiled on-demand per execution/request.
|
|
||||||
- For script files with custom extension (`*.hub.kts`), IDEA code insight is usually weaker than standard `*.main.kts` or module Kotlin sources. This is an IDE limitation for custom script definitions.
|
|
||||||
|
|
||||||
## Command CLI
|
|
||||||
A standalone CLI script is available at `tools/slhaf-hub-cli.kts` (independent from host internals, only HTTP calls).
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
```bash
|
|
||||||
kotlin tools/slhaf-hub-cli.kts --base-url=http://127.0.0.1:8080 --token-file=./scripts/.host-api-token list
|
|
||||||
kotlin tools/slhaf-hub-cli.kts --token-file=./scripts/.host-api-token type
|
|
||||||
kotlin tools/slhaf-hub-cli.kts --token-file=./scripts/.host-api-token show hello
|
|
||||||
kotlin tools/slhaf-hub-cli.kts --token-file=./scripts/.host-api-token run hello --arg=name=Alice --arg=upper=true
|
|
||||||
kotlin tools/slhaf-hub-cli.kts --token-file=./scripts/.host-api-token create demo --text='// @desc: demo\nval args: Array<String> = emptyArray()\nprintln("ok")'
|
|
||||||
kotlin tools/slhaf-hub-cli.kts --token-file=./scripts/.host-api-token sub-create demo-sub --scripts=hello,time
|
|
||||||
kotlin tools/slhaf-hub-cli.kts --token-file=./scripts/.host-api-token sub-list
|
|
||||||
```
|
|
||||||
|
|
||||||
Note:
|
|
||||||
- In this environment, `elide run <kts> -- <args...>` currently does not expose Kotlin script args reliably; use `kotlin` to run the CLI script.
|
|
||||||
|
|
||||||
## Simple TUI
|
|
||||||
A minimal keyboard-driven TUI is available at `tools/slhaf-hub-tui.kts`.
|
|
||||||
|
|
||||||
Run:
|
|
||||||
```bash
|
|
||||||
kotlin tools/slhaf-hub-tui.kts --base-url=http://127.0.0.1:8080 --token-file=./scripts/.host-api-token
|
|
||||||
```
|
|
||||||
|
|
||||||
Keys:
|
|
||||||
- `Up/Down` or `j/k`: switch script
|
|
||||||
- `Left/Right` or `h/l`: switch action (grouped by `Script` / `SubToken` / `System`)
|
|
||||||
- `Enter`: execute selected action
|
|
||||||
- `q`: quit
|
|
||||||
|
|
||||||
Action model:
|
|
||||||
- `root` token: full grouped actions including `Subtokens`
|
|
||||||
- `sub` token: reduced action set (`Refresh/Run/Meta/Type/Quit`)
|
|
||||||
- `Subtokens` opens a keyboard sub-menu (`List/Show/Create/Update/Delete/Back`)
|
|
||||||
|
|
||||||
Create/Edit/Delete behavior:
|
|
||||||
- `Create`: prompt script name, then choose source mode:
|
|
||||||
- `e` (default): create temp file, open terminal editor, then upload via API
|
|
||||||
- `f`: read a specified local file and upload via API
|
|
||||||
- In editor mode, if content is unchanged from initial template, creation is cancelled
|
|
||||||
- `Edit`: fetch current script content (`GET /scripts/{script}`), write to temp file, open editor, save+exit, then upload via `PUT`
|
|
||||||
- `Delete`: asks confirmation before calling `DELETE`
|
|
||||||
- `Run`: prompts for optional query args (`k=v`, separated by `&` or space), and optional POST mode/body
|
|
||||||
- Now uses a keyboard-driven sub-menu (`Method/Query/Body/Execute/Cancel`) and remembers last run config per script during the session
|
|
||||||
|
|
||||||
Editor selection:
|
|
||||||
- First uses `$EDITOR`
|
|
||||||
- Fallback to first available of `nvim`, `vim`, `nano`
|
|
||||||
|
|
||||||
## Docker
|
|
||||||
Build image:
|
|
||||||
```bash
|
```bash
|
||||||
docker build -t slhaf-hub:latest .
|
docker build -t slhaf-hub:latest .
|
||||||
```
|
|
||||||
|
|
||||||
Run container (mount local scripts directory):
|
|
||||||
```bash
|
|
||||||
docker run --rm -p 8080:8080 \
|
docker run --rm -p 8080:8080 \
|
||||||
-v /tmp/kotlin-scripts/scripts:/app/scripts \
|
-v /tmp/kotlin-scripts/scripts:/app/scripts \
|
||||||
-e HOST_API_TOKEN=your-token \
|
-e HOST_API_TOKEN=your-token \
|
||||||
|
-e MAX_RUN_CONCURRENCY=8 \
|
||||||
slhaf-hub:latest
|
slhaf-hub:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
Then call APIs:
|
#### 3) Run with Docker Compose
|
||||||
```bash
|
|
||||||
curl http://127.0.0.1:8080/health
|
|
||||||
curl -H "Authorization: Bearer your-token" http://127.0.0.1:8080/scripts
|
|
||||||
```
|
|
||||||
|
|
||||||
## Docker Compose
|
|
||||||
Run with compose:
|
|
||||||
```bash
|
```bash
|
||||||
# optional: export HOST_API_TOKEN=your-token
|
# optional: export HOST_API_TOKEN=your-token
|
||||||
# optional: export HOST_PORT=8080
|
# optional: export HOST_PORT=8080
|
||||||
@@ -169,13 +45,126 @@ Run with compose:
|
|||||||
docker compose up -d --build
|
docker compose up -d --build
|
||||||
```
|
```
|
||||||
|
|
||||||
Check status/logs:
|
Health check:
|
||||||
```bash
|
```bash
|
||||||
docker compose ps
|
curl http://127.0.0.1:8080/health
|
||||||
docker compose logs -f slhaf-hub
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Stop:
|
### Clients
|
||||||
|
#### CLI
|
||||||
```bash
|
```bash
|
||||||
docker compose down
|
kotlin tools/slhaf-hub-cli.kts --base-url=http://127.0.0.1:8080 --token-file=./scripts/.host-api-token list
|
||||||
|
kotlin tools/slhaf-hub-cli.kts --token-file=./scripts/.host-api-token type
|
||||||
|
kotlin tools/slhaf-hub-cli.kts --token-file=./scripts/.host-api-token run hello --arg=name=Alice --arg=upper=true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### TUI
|
||||||
|
```bash
|
||||||
|
kotlin tools/slhaf-hub-tui.kts --base-url=http://127.0.0.1:8080 --token-file=./scripts/.host-api-token
|
||||||
|
```
|
||||||
|
|
||||||
|
CLI/TUI env vars:
|
||||||
|
- `SLHAF_HUB_BASE_URL`
|
||||||
|
- `SLHAF_HUB_TOKEN`
|
||||||
|
- `SLHAF_HUB_TOKEN_FILE`
|
||||||
|
|
||||||
|
## Auth Model
|
||||||
|
Auth headers:
|
||||||
|
- `Authorization: Bearer <token>` (recommended)
|
||||||
|
- `X-Host-Token: <token>`
|
||||||
|
|
||||||
|
Token source priority:
|
||||||
|
1. `HOST_API_TOKEN` env var
|
||||||
|
2. `scripts/.host-api-token`
|
||||||
|
3. Auto-generated token saved to `scripts/.host-api-token`
|
||||||
|
|
||||||
|
Token types:
|
||||||
|
- `root`: full access
|
||||||
|
- `sub`: access to `/health`, `/type`, filtered `/scripts`, and allowed-script `/meta/{script}` + `/run/{script}`
|
||||||
|
|
||||||
|
## Script Metadata (`*.hub.kts`)
|
||||||
|
Example:
|
||||||
|
```kotlin
|
||||||
|
// @desc: Demo greeting API
|
||||||
|
// @timeout: 10s
|
||||||
|
// @param: name | required=false | default=world | desc=Name to greet
|
||||||
|
|
||||||
|
val args: Array<String> = emptyArray()
|
||||||
|
val kv = args.mapNotNull {
|
||||||
|
val i = it.indexOf('=')
|
||||||
|
if (i <= 0) null else it.substring(0, i) to it.substring(i + 1)
|
||||||
|
}.toMap()
|
||||||
|
|
||||||
|
println("hello " + (kv["name"] ?: "world"))
|
||||||
|
```
|
||||||
|
|
||||||
|
Fields:
|
||||||
|
- `@desc: <text>`
|
||||||
|
- `@timeout: <value>`
|
||||||
|
- `@param: <name> | required=true|false | default=<value> | desc=<text>`
|
||||||
|
|
||||||
|
Timeout formats:
|
||||||
|
- `500ms`, `10s`, `1m`, or plain integer seconds (`10`)
|
||||||
|
|
||||||
|
Default timeout:
|
||||||
|
- `10s`
|
||||||
|
|
||||||
|
### Metadata Validation
|
||||||
|
`POST /scripts/{script}` and `PUT /scripts/{script}` validate metadata before saving.
|
||||||
|
|
||||||
|
On validation failure, server returns `400 Bad Request` with:
|
||||||
|
- line-based reason details
|
||||||
|
- valid metadata examples
|
||||||
|
|
||||||
|
## API Summary
|
||||||
|
Public:
|
||||||
|
- `GET /health`
|
||||||
|
|
||||||
|
Authenticated:
|
||||||
|
- `GET /type`
|
||||||
|
- `GET /scripts`
|
||||||
|
- `GET /meta/{script}`
|
||||||
|
- `GET /run/{script}?k=v`
|
||||||
|
- `POST /run/{script}?k=v`
|
||||||
|
|
||||||
|
Root only:
|
||||||
|
- `GET /scripts/{script}`
|
||||||
|
- `POST /scripts/{script}`
|
||||||
|
- `PUT /scripts/{script}`
|
||||||
|
- `DELETE /scripts/{script}`
|
||||||
|
- `GET /subtokens`
|
||||||
|
- `GET /subtokens/{name}`
|
||||||
|
- `POST /subtokens/{name}`
|
||||||
|
- `PUT /subtokens/{name}`
|
||||||
|
- `DELETE /subtokens/{name}`
|
||||||
|
|
||||||
|
Common statuses:
|
||||||
|
- `200`, `201`, `400`, `401`, `403`, `404`, `408` (timeout)
|
||||||
|
|
||||||
|
## Runtime Controls
|
||||||
|
Run concurrency:
|
||||||
|
- arg: `--max-run-concurrency=<N>`
|
||||||
|
- env (compose): `MAX_RUN_CONCURRENCY`
|
||||||
|
- default: number of available processors
|
||||||
|
|
||||||
|
The limit only applies to `/run/*` endpoints.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
Run:
|
||||||
|
```bash
|
||||||
|
./gradlew test
|
||||||
|
```
|
||||||
|
|
||||||
|
Current automated coverage focuses on WebHost APIs:
|
||||||
|
- auth behavior
|
||||||
|
- script CRUD/meta/run
|
||||||
|
- metadata validation responses
|
||||||
|
- subtoken permission filtering
|
||||||
|
- run timeout behavior
|
||||||
|
|
||||||
|
## Project Layout
|
||||||
|
- `src/main/kotlin/work/slhaf/hub`: host implementation
|
||||||
|
- `src/test/kotlin/work/slhaf/hub`: automated tests
|
||||||
|
- `scripts`: runtime scripts and token/subtoken storage
|
||||||
|
- `tools`: standalone CLI/TUI scripts
|
||||||
|
- `Dockerfile`, `docker-compose.yml`: container deployment
|
||||||
|
|||||||
170
README.zh-CN.md
Normal file
170
README.zh-CN.md
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
# slhaf-hub
|
||||||
|
|
||||||
|
基于 Kotlin 的动态脚本宿主,提供 HTTP API、root/sub token 鉴权、脚本 metadata、超时控制,以及配套 CLI/TUI 工具。
|
||||||
|
|
||||||
|
语言版本:
|
||||||
|
- English: `README.md`
|
||||||
|
- 中文: `README.zh-CN.md`
|
||||||
|
|
||||||
|
## 功能概览
|
||||||
|
- 从 `scripts/*.hub.kts` 动态加载脚本,无需重启 host
|
||||||
|
- Root/Sub token 鉴权模型
|
||||||
|
- 脚本注释 metadata(`@desc`、`@timeout`、`@param`)
|
||||||
|
- 脚本 CRUD + run + meta API
|
||||||
|
- subtoken 管理 API
|
||||||
|
- 运行并发限制(`--max-run-concurrency`)
|
||||||
|
- 脚本执行超时(默认 10 秒,可脚本级覆盖)
|
||||||
|
|
||||||
|
## 环境要求
|
||||||
|
- JDK 17+
|
||||||
|
- Gradle(或 Gradle Wrapper)
|
||||||
|
|
||||||
|
## 快速启动
|
||||||
|
### 服务端
|
||||||
|
#### 1) 终端启动(Gradle)
|
||||||
|
```bash
|
||||||
|
cd /tmp/kotlin-scripts
|
||||||
|
./gradlew runWeb --args='--host=0.0.0.0 --port=8080 --scripts-dir=./scripts'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2) Docker 启动
|
||||||
|
```bash
|
||||||
|
docker build -t slhaf-hub:latest .
|
||||||
|
docker run --rm -p 8080:8080 \
|
||||||
|
-v /tmp/kotlin-scripts/scripts:/app/scripts \
|
||||||
|
-e HOST_API_TOKEN=your-token \
|
||||||
|
-e MAX_RUN_CONCURRENCY=8 \
|
||||||
|
slhaf-hub:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3) Docker Compose 启动
|
||||||
|
```bash
|
||||||
|
# 可选:export HOST_API_TOKEN=your-token
|
||||||
|
# 可选:export HOST_PORT=8080
|
||||||
|
# 可选:export MAX_RUN_CONCURRENCY=8
|
||||||
|
docker compose up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
健康检查:
|
||||||
|
```bash
|
||||||
|
curl http://127.0.0.1:8080/health
|
||||||
|
```
|
||||||
|
|
||||||
|
### 客户端
|
||||||
|
#### CLI
|
||||||
|
```bash
|
||||||
|
kotlin tools/slhaf-hub-cli.kts --base-url=http://127.0.0.1:8080 --token-file=./scripts/.host-api-token list
|
||||||
|
kotlin tools/slhaf-hub-cli.kts --token-file=./scripts/.host-api-token type
|
||||||
|
kotlin tools/slhaf-hub-cli.kts --token-file=./scripts/.host-api-token run hello --arg=name=Alice --arg=upper=true
|
||||||
|
```
|
||||||
|
|
||||||
|
#### TUI
|
||||||
|
```bash
|
||||||
|
kotlin tools/slhaf-hub-tui.kts --base-url=http://127.0.0.1:8080 --token-file=./scripts/.host-api-token
|
||||||
|
```
|
||||||
|
|
||||||
|
CLI/TUI 环境变量:
|
||||||
|
- `SLHAF_HUB_BASE_URL`
|
||||||
|
- `SLHAF_HUB_TOKEN`
|
||||||
|
- `SLHAF_HUB_TOKEN_FILE`
|
||||||
|
|
||||||
|
## 鉴权模型
|
||||||
|
鉴权请求头:
|
||||||
|
- `Authorization: Bearer <token>`(推荐)
|
||||||
|
- `X-Host-Token: <token>`
|
||||||
|
|
||||||
|
Token 来源优先级:
|
||||||
|
1. 环境变量 `HOST_API_TOKEN`
|
||||||
|
2. `scripts/.host-api-token`
|
||||||
|
3. 自动生成并写入 `scripts/.host-api-token`
|
||||||
|
|
||||||
|
Token 类型:
|
||||||
|
- `root`:完整权限
|
||||||
|
- `sub`:可访问 `/health`、`/type`、过滤后的 `/scripts`,以及被授权脚本的 `/meta/{script}` 与 `/run/{script}`
|
||||||
|
|
||||||
|
## 脚本 Metadata(`*.hub.kts`)
|
||||||
|
示例:
|
||||||
|
```kotlin
|
||||||
|
// @desc: Demo greeting API
|
||||||
|
// @timeout: 10s
|
||||||
|
// @param: name | required=false | default=world | desc=Name to greet
|
||||||
|
|
||||||
|
val args: Array<String> = emptyArray()
|
||||||
|
val kv = args.mapNotNull {
|
||||||
|
val i = it.indexOf('=')
|
||||||
|
if (i <= 0) null else it.substring(0, i) to it.substring(i + 1)
|
||||||
|
}.toMap()
|
||||||
|
|
||||||
|
println("hello " + (kv["name"] ?: "world"))
|
||||||
|
```
|
||||||
|
|
||||||
|
字段:
|
||||||
|
- `@desc: <text>`
|
||||||
|
- `@timeout: <value>`
|
||||||
|
- `@param: <name> | required=true|false | default=<value> | desc=<text>`
|
||||||
|
|
||||||
|
超时格式:
|
||||||
|
- `500ms`、`10s`、`1m`,或纯数字秒(`10`)
|
||||||
|
|
||||||
|
默认超时:
|
||||||
|
- `10s`
|
||||||
|
|
||||||
|
### Metadata 校验
|
||||||
|
`POST /scripts/{script}` 与 `PUT /scripts/{script}` 在保存前会校验 metadata。
|
||||||
|
|
||||||
|
校验失败时返回 `400 Bad Request`,并包含:
|
||||||
|
- 行级错误原因
|
||||||
|
- 正确格式示例
|
||||||
|
|
||||||
|
## API 概览
|
||||||
|
公开接口:
|
||||||
|
- `GET /health`
|
||||||
|
|
||||||
|
鉴权后接口:
|
||||||
|
- `GET /type`
|
||||||
|
- `GET /scripts`
|
||||||
|
- `GET /meta/{script}`
|
||||||
|
- `GET /run/{script}?k=v`
|
||||||
|
- `POST /run/{script}?k=v`
|
||||||
|
|
||||||
|
仅 root:
|
||||||
|
- `GET /scripts/{script}`
|
||||||
|
- `POST /scripts/{script}`
|
||||||
|
- `PUT /scripts/{script}`
|
||||||
|
- `DELETE /scripts/{script}`
|
||||||
|
- `GET /subtokens`
|
||||||
|
- `GET /subtokens/{name}`
|
||||||
|
- `POST /subtokens/{name}`
|
||||||
|
- `PUT /subtokens/{name}`
|
||||||
|
- `DELETE /subtokens/{name}`
|
||||||
|
|
||||||
|
常见状态码:
|
||||||
|
- `200`、`201`、`400`、`401`、`403`、`404`、`408`(超时)
|
||||||
|
|
||||||
|
## 运行控制
|
||||||
|
并发限制:
|
||||||
|
- 启动参数:`--max-run-concurrency=<N>`
|
||||||
|
- Compose 环境变量:`MAX_RUN_CONCURRENCY`
|
||||||
|
- 默认值:可用处理器数量
|
||||||
|
|
||||||
|
并发限制仅作用于 `/run/*` 接口。
|
||||||
|
|
||||||
|
## 自动化测试
|
||||||
|
执行:
|
||||||
|
```bash
|
||||||
|
./gradlew test
|
||||||
|
```
|
||||||
|
|
||||||
|
当前自动化覆盖 WebHost 接口:
|
||||||
|
- 鉴权行为
|
||||||
|
- 脚本 CRUD/meta/run
|
||||||
|
- metadata 校验返回
|
||||||
|
- subtoken 权限过滤
|
||||||
|
- run 超时行为
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
- `src/main/kotlin/work/slhaf/hub`:host 实现
|
||||||
|
- `src/test/kotlin/work/slhaf/hub`:自动化测试
|
||||||
|
- `scripts`:运行时脚本和 token/subtoken 存储
|
||||||
|
- `tools`:独立 CLI/TUI 脚本
|
||||||
|
- `Dockerfile`、`docker-compose.yml`:容器部署
|
||||||
Reference in New Issue
Block a user