go-infra

module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 14, 2026 License: MIT

README

go-infra

Go 基础设施工具集,用于构建生产级应用。

说明
lifecycle 应用生命周期管理:顺序启动、LIFO 关闭、信号处理、优雅停机
license 离线软件授权:Ed25519 签名、机器绑定、Feature/Capacity 两层授权、密钥轮换

使用

import "github.com/qoderwork/go-infra/lifecycle"

func main() {
    mgr := lifecycle.New(lifecycle.WithTimeout(10 * time.Second))
    mgr.Add(myDB)
    mgr.Add(myHTTPServer)
    mgr.Run() // 阻塞直到收到信号,然后优雅关闭
}

完整示例见 examples

设计原则

  • KISS — 最小 API 表面,没有不必要的抽象
  • 注册顺序即优先级 — 先加的先启动、后关闭,和 defer 一样直觉
  • 零隐藏 goroutine — Manager 不会在调用者 goroutine 之外偷偷起后台线程(唯一例外是 WaitSignal,由 Go runtime 的信号处理 goroutine 负责捕获 SIGINT/SIGTERM,与你的代码无关)。Task.Start / Task.Stop 由 Manager 在调用者 goroutine 同步驱动,但 Task 自己可以用 go 起后台服务——Start 不必阻塞,返回即代表"已启动"。
  • 幂等关闭sync.Once 保证 Stop 安全调用多次

停机触发源

Manager 提供两种"等停机信号"的入口,按需选择:

  • mgr.Run() —— 推荐入口Start 之后自动监听系统信号(SIGINT / SIGTERM,Windows 上为 Ctrl+C),收到后优雅关闭。适合独立二进制。
  • mgr.WaitSignal(timeout) —— 与 Run 内部逻辑相同,但你可以先 Start 再做别的事,再手动等待信号。
  • mgr.Wait(ctx) —— 停机由你自己的 context 驱动(如测试、K8s 探针、父进程编排),不依赖 OS 信号。把 ctx 取消即可触发优雅关闭。

授权(license 包)

极简、零依赖的离线软件授权方案。用 Ed25519 数字签名而非加密来保证防篡改与身份认证:授权文件是明文 JSON,可被审计;防伪造靠的是签名,不是隐藏内容。

核心概念
  • 签发 / 验签分离license-tool 持有私钥签发授权;你的程序只内置公钥验签,无法伪造。
  • 数据模型LicenseID / Product / Subject / Features[] / Capacity / NotBefore / Expiry / Machine / VersionFeatures 是功能开关列表,Capacity 是数量上限(map[string]int64),二者构成 Feature + Capacity 两层授权。
  • 确定性签名:签名字节 = License 结构体的 JSON 编码。Go 的 json 按字段声明顺序输出、并对 map 的 key 排序,因此签发端与验签端产生完全一致字节。
  • 机器绑定Machine 声明允许的机器指纹列表;strict 要求精确匹配(取不到指纹则失败),loose 在取不到指纹时放行。指纹由 license/machine 计算(主板序列号 → /etc/machine-id → hostname 回退链,sha256 归一化并拒占位符)。
  • 密钥轮换Version 字段选择验签用的公钥;Verifier.WithKey(pub, v) 注册多版本公钥,换密钥时旧授权仍有效。
快速开始

签发(在你这边,持有私钥):

go run ./cmd/license-tool genkey -priv private.pem -pub public.pem
# 写一个 template.json(字段见 License 结构体),然后:
go run ./cmd/license-tool sign -key private.pem -in template.json -out license.lic

验签(在程序里,只内置公钥):

pub, _ := license.DecodePublicKeyPEM(pubPEM) // pubPEM 用 go:embed 内置
data, _ := os.ReadFile("license.lic")
lic, err := license.NewVerifier(pub, license.CurrentVersion).
    WithFingerprint(machine.Fingerprint).
    Verify(data)
if err != nil { /* 授权无效:err 说明原因 */ }
_ = lic.HasFeature("advanced")
n := lic.CapacityOf("nodes")

CLI 还有 verify(手动校验)和 fingerprint(打印当前机器指纹)两个子命令。完整演示见 examples/license

安全预期(重要)

离线授权是君子级防护,不是保险箱

  • ✅ 有效签名 = 授权确由私钥签发、且未被篡改;机器绑定防止 .lic 文件被拷贝到别机。
  • ⚠️ 不防二进制补丁:攻击者可 patch 程序跳过 Verify(),或改内存里的 Expiry。如需更强保护,请额外加二进制完整性校验 / 混淆。
  • ⚠️ 时间旅行:离线环境下改系统时间可绕过过期。可用 Verifier.WithMinClock() 接到一个持久化的"已知最晚时间"来防御时钟回拨。
  • 私钥泄露需走轮换流程(升 Version 并签发新密钥,旧版授权靠 WithKey 兼容)。

License

MIT

Directories

Path Synopsis
cmd
license-tool command
Command license-tool issues and verifies offline software licenses.
Command license-tool issues and verifies offline software licenses.
Package licensing — crypto.go
Package licensing — crypto.go
machine
Package machine computes a stable, normalized machine fingerprint used to bind a license to a physical (or virtual) machine.
Package machine computes a stable, normalized machine fingerprint used to bind a license to a physical (or virtual) machine.
Package lifecycle provides a minimal application lifecycle manager.
Package lifecycle provides a minimal application lifecycle manager.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL