Add dual-tier storage (embedded SQLite + optional PostgreSQL)
Details (original message): Add dual-tier storage (embedded SQLite + optional PostgreSQL), tenant owner scoping, API key auth, versioned dual-dialect migrations, integrity hardening, and batched event persistence
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
// agent-system:单二进制服务(HTTP/SSE + 内嵌前端 + 嵌入式 SQLite)。
|
||||
// agent-system:单二进制服务(HTTP/SSE + 内嵌前端 + 双档存储)。
|
||||
// 部署约束(设计 4.1 原则 8):非容器化;拷贝即运行。
|
||||
// 嵌入式档默认(SQLite + 本地对象目录,零外部服务);--dsn 切换 PostgreSQL 档
|
||||
//(多用户/多实例,认证默认开启,apikey 子命令管理密钥)。
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -20,6 +23,8 @@ func main() {
|
||||
return
|
||||
case "serve":
|
||||
os.Args = append([]string{os.Args[0]}, os.Args[2:]...)
|
||||
case "apikey":
|
||||
os.Exit(runAPIKey(os.Args[2:]))
|
||||
}
|
||||
}
|
||||
fs := flag.NewFlagSet("serve", flag.ExitOnError)
|
||||
@@ -27,10 +32,69 @@ func main() {
|
||||
data := fs.String("data", "./data", "数据目录(SQLite 与工件对象目录)")
|
||||
pluginsDir := fs.String("plugins", "./plugins", "插件目录(声明资产热加载)")
|
||||
mock := fs.Bool("mock", false, "演示模式(等同 runtime.mock=true,不调用模型)")
|
||||
dsn := fs.String("dsn", "", "PostgreSQL 档 DSN(空 = 嵌入式 SQLite 档)")
|
||||
artifacts := fs.String("artifacts", "", "工件对象目录(默认 <data>/artifacts;PG 档多实例时指向共享卷)")
|
||||
auth := fs.String("auth", "auto", "API key 认证:auto(PG 档开、嵌入式关)| on | off")
|
||||
fs.Parse(os.Args[1:])
|
||||
|
||||
if err := app.Run(app.Options{Addr: *addr, DataDir: *data, PluginsDir: *pluginsDir, ForceMock: *mock}); err != nil {
|
||||
if err := app.Run(app.Options{
|
||||
Addr: *addr, DataDir: *data, PluginsDir: *pluginsDir, ForceMock: *mock,
|
||||
StorageDSN: *dsn, ArtifactsDir: *artifacts, AuthMode: *auth,
|
||||
}); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "agent-system:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// runAPIKey:密钥管理子命令(create/list/revoke)。
|
||||
func runAPIKey(args []string) int {
|
||||
fs := flag.NewFlagSet("apikey", flag.ExitOnError)
|
||||
data := fs.String("data", "./data", "数据目录")
|
||||
dsn := fs.String("dsn", "", "PostgreSQL 档 DSN(空 = 嵌入式档)")
|
||||
owner := fs.String("owner", "", "租户名(owner)")
|
||||
name := fs.String("name", "default", "密钥名称")
|
||||
fs.Parse(args)
|
||||
if len(fs.Args()) == 0 {
|
||||
fmt.Fprintln(os.Stderr, "用法:agent-system apikey <create|list|revoke> [--owner x --name y]")
|
||||
return 2
|
||||
}
|
||||
if *owner == "" {
|
||||
fmt.Fprintln(os.Stderr, "apikey: --owner 必填")
|
||||
return 2
|
||||
}
|
||||
switch fs.Args()[0] {
|
||||
case "create":
|
||||
key, err := app.CreateAPIKey(*dsn, *data, *owner, *name)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "apikey create:", err)
|
||||
return 1
|
||||
}
|
||||
// 明文仅此一次输出;库中只存 SHA-256 摘要。
|
||||
fmt.Println(key)
|
||||
return 0
|
||||
case "list":
|
||||
keys, err := app.ListAPIKeys(*dsn, *data, *owner)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "apikey list:", err)
|
||||
return 1
|
||||
}
|
||||
out, _ := json.MarshalIndent(keys, "", " ")
|
||||
fmt.Println(string(out))
|
||||
return 0
|
||||
case "revoke":
|
||||
ok, err := app.RevokeAPIKey(*dsn, *data, *owner, *name)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "apikey revoke:", err)
|
||||
return 1
|
||||
}
|
||||
if !ok {
|
||||
fmt.Fprintf(os.Stderr, "apikey revoke: 未找到 owner=%s name=%s 的有效密钥\n", *owner, *name)
|
||||
return 1
|
||||
}
|
||||
fmt.Println("revoked")
|
||||
return 0
|
||||
default:
|
||||
fmt.Fprintln(os.Stderr, "apikey: 未知子命令", fs.Args()[0])
|
||||
return 2
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user