feat: machine mode, PEM-only certs, ECH support, multi-instance config, batch ops, xbctl

This commit is contained in:
xboard
2026-04-16 23:06:58 +08:00
parent 598b6b531b
commit c5bcbc3299
52 changed files with 6676 additions and 1348 deletions
+47 -4
View File
@@ -13,10 +13,11 @@ import (
// Watcher reloads the config file on change (debounced) and calls onChange.
type Watcher struct {
path string
debounce time.Duration
onChange func(*Config)
watcher *fsnotify.Watcher
path string
debounce time.Duration
onChange func(*Config)
onChangeRoot func(*RootConfig)
watcher *fsnotify.Watcher
stopOnce sync.Once
stopCh chan struct{}
@@ -56,6 +57,38 @@ func WatchConfig(ctx context.Context, path string, onChange func(*Config)) (*Wat
return w, nil
}
// WatchConfigRoot watches path and reloads the root config model.
func WatchConfigRoot(ctx context.Context, path string, onChange func(*RootConfig)) (*Watcher, error) {
absPath, err := filepath.Abs(path)
if err != nil {
return nil, err
}
fsw, err := fsnotify.NewWatcher()
if err != nil {
return nil, err
}
dir := filepath.Dir(absPath)
if err := fsw.Add(dir); err != nil {
fsw.Close()
return nil, err
}
w := &Watcher{
path: absPath,
debounce: 1 * time.Second,
onChangeRoot: onChange,
watcher: fsw,
stopCh: make(chan struct{}),
}
go w.loop(ctx)
nlog.Core().Info("config watcher started", "path", absPath)
return w, nil
}
func (w *Watcher) loop(ctx context.Context) {
var timer *time.Timer
defer func() {
@@ -102,6 +135,16 @@ func (w *Watcher) reload() {
if w.stopped.Load() {
return
}
if w.onChangeRoot != nil {
root, err := LoadRoot(w.path)
if err != nil {
nlog.Core().Error("config reload failed, keeping current config", "error", err)
return
}
nlog.Core().Info("config reloaded successfully")
w.onChangeRoot(root)
return
}
cfg, err := Load(w.path)
if err != nil {
nlog.Core().Error("config reload failed, keeping current config", "error", err)