Files
zonat/cmd/node/main.go
T
4566704 c174a2ed3a fix(node): 默认自动加载本目录 node.ini——裸跑 ./zonat-node 不再缺密钥报错
改了什么: -config 默认值改为 node.ini; 未显式指定且文件不存在时按无配置启动(纯 flag/老部署兼容); 缺密钥报错文案补 node.ini 途径
为什么: 部署目录裸跑二进制(不经 start.sh)时不会主动带 -config, 直接报缺少 jwt-secret; 自动加载同目录配置后包内开箱即跑
2026-09-21 19:14:27 +08:00

136 lines
3.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// zonat 节点入口:TCP 桥接监听 + 隧道注册表 + 纯 TCP 隧道监听。
// 无管理 API、无数据库;隧道由 agent 经桥接控制流注册。
// agent 登录用 JWT 校验(HS256);token 正式部署由 cloud 签发,
// 手工/测试场景可用 -print-token 现场签发。
//
// 配置来源优先级:显式命令行 flag > -config 指定的配置文件 > 内置默认。
package main
import (
"flag"
"fmt"
"log/slog"
"os"
"os/signal"
"syscall"
"time"
"git.zeroonesoft.cn/golib/zonat/internal/node"
)
func main() {
var (
config = flag.String("config", "node.ini", "配置文件路径; 默认自动加载本目录 node.ini, 文件不存在且未显式 -config 时按无配置启动")
addr = flag.String("addr", ":5212", "桥接监听地址")
tunnelBind = flag.String("tunnel-bind", "0.0.0.0", "隧道监听绑定地址")
jwtSecret = flag.String("jwt-secret", "", "agent 登录 JWT 校验密钥(HS256)")
sweep = flag.Duration("sweep", 30*time.Second, "TTL 清扫间隔")
portRange = flag.String("port-range", "", "隧道监听端口范围(如 20000-21000); 未指定端口的隧道在范围内取空闲端口, 空=系统随机")
// 便捷签发:node -jwt-secret s3cret -print-token -agent a1 -ttl 24h
printToken = flag.Bool("print-token", false, "用 -jwt-secret 签发一张 agent 登录 token 后退出")
tokenAgent = flag.String("agent", "", "print-token 时写入 agentId claim")
tokenTTL = flag.Duration("ttl", 24*time.Hour, "print-token 签发的有效期")
)
flag.Parse()
if *printToken {
if *jwtSecret == "" || *tokenTTL <= 0 {
slog.Error("print-token 需要 -jwt-secret 与正的 -ttl")
os.Exit(1)
}
tok, err := node.SignToken(*jwtSecret, *tokenAgent, *tokenTTL)
if err != nil {
slog.Error("签发失败", "err", err.Error())
os.Exit(1)
}
fmt.Println(tok)
return
}
// 终值 = 内置默认 ← 配置文件(非零项) ← 显式 flag
explicit := map[string]bool{}
flag.Visit(func(f *flag.Flag) { explicit[f.Name] = true })
// 自动加载: -config 未显式指定且默认路径不存在 → 按无配置启动(兼容纯 flag/老部署)
if !explicit["config"] {
if _, err := os.Stat(*config); err != nil {
*config = ""
}
}
var (
finalAddr = *addr
finalTunnelBind = *tunnelBind
finalSecret = *jwtSecret
finalSweep = *sweep
finalRange node.PortRange
)
if *config != "" {
cfg, err := loadConfigFile(*config)
if err != nil {
slog.Error("读取配置文件失败", "path", *config, "err", err.Error())
os.Exit(1)
}
if cfg.Addr != "" {
finalAddr = cfg.Addr
}
if cfg.TunnelBind != "" {
finalTunnelBind = cfg.TunnelBind
}
if cfg.JwtSecret != "" {
finalSecret = cfg.JwtSecret
}
if d := cfg.sweepDuration(); d > 0 {
finalSweep = d
}
if cfg.PortRange != "" {
r, err := node.ParsePortRange(cfg.PortRange)
if err != nil {
slog.Error("配置文件端口范围无效", "err", err.Error())
os.Exit(1)
}
finalRange = r
}
}
if explicit["addr"] {
finalAddr = *addr
}
if explicit["tunnel-bind"] {
finalTunnelBind = *tunnelBind
}
if explicit["jwt-secret"] {
finalSecret = *jwtSecret
}
if explicit["sweep"] {
finalSweep = *sweep
}
if explicit["port-range"] {
r, err := node.ParsePortRange(*portRange)
if err != nil {
slog.Error("端口范围无效", "err", err.Error())
os.Exit(1)
}
finalRange = r
}
if finalSecret == "" {
slog.Error("缺少 jwt-secret(agent 登录 JWT 校验密钥; -jwt-secret、-config 指定文件或本目录 node.ini 的 server.jwt-secret)")
os.Exit(1)
}
n := node.New()
n.JwtSecret = finalSecret
n.BindTunnel = finalTunnelBind
n.SweepInterval = finalSweep
n.TunnelPortRange = finalRange
if err := n.Start(finalAddr); err != nil {
slog.Error("节点启动失败", "err", err.Error())
os.Exit(1)
}
quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
<-quit
n.Stop()
}