From aa7e7f87e17f17ff2f64aa1823a00a291628d4eb Mon Sep 17 00:00:00 2001 From: NanamiAdmin Date: Tue, 29 Sep 2026 21:43:46 +0800 Subject: [PATCH] feat(node): add `GetNodeCount` to get node count and remove no need node update log, only log when node count changed --- config/settings.go | 10 +++++----- config/settings_test.go | 4 ++-- handler/settings.go | 2 +- internal/komari/client.go | 2 +- internal/node/tracker.go | 10 ++++++++++ main.go | 4 ++++ 6 files changed, 23 insertions(+), 9 deletions(-) diff --git a/config/settings.go b/config/settings.go index 31ce22c..a1d859e 100644 --- a/config/settings.go +++ b/config/settings.go @@ -46,7 +46,7 @@ var startupOnlySettings = []string{ "dbPath", } -// RestartRequiredKeys lists the settings in patch that only take effect at +// IsRestartRequiredKeys lists the settings in patch that only take effect at // startup, as dot-separated paths, in the order startupOnlySettings declares // them. Only config.json carries such settings; an update to one of the other // files always reports nothing. @@ -54,7 +54,7 @@ var startupOnlySettings = []string{ // The write itself succeeds either way — this is advice for the user, not a // rejection. The result is never nil, so a caller can put it straight into a // JSON response and get [] rather than null. -func RestartRequiredKeys(settingsType string, patch map[string]interface{}) []string { +func IsRestartRequiredKeys(settingsType string, patch map[string]interface{}) []string { keys := []string{} if settingsType != SettingGlobal { return keys @@ -63,7 +63,7 @@ func RestartRequiredKeys(settingsType string, patch map[string]interface{}) []st patched := patchPaths(patch) for _, watched := range startupOnlySettings { for _, path := range patched { - if pathsOverlap(path, watched) { + if isPathsOverlap(path, watched) { keys = append(keys, watched) break } @@ -96,12 +96,12 @@ func patchPaths(patch map[string]interface{}) []string { return paths } -// pathsOverlap reports whether a patched path and a watched setting can affect +// isPathsOverlap reports whether a patched path and a watched setting can affect // each other: they are the same key, the patch names something inside the // watched setting, or the patch names a section the watched setting lives in. // The last case matters because a patch may replace a whole section, which // changes every key under it. -func pathsOverlap(patched, watched string) bool { +func isPathsOverlap(patched, watched string) bool { return patched == watched || strings.HasPrefix(patched, watched+".") || strings.HasPrefix(watched, patched+".") diff --git a/config/settings_test.go b/config/settings_test.go index 6a864e1..c02005e 100644 --- a/config/settings_test.go +++ b/config/settings_test.go @@ -271,7 +271,7 @@ func TestRestartRequiredKeys(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - got := RestartRequiredKeys(tc.settingsType, tc.patch) + got := IsRestartRequiredKeys(tc.settingsType, tc.patch) if !reflect.DeepEqual(got, tc.want) { t.Errorf("RestartRequiredKeys() = %v, want %v", got, tc.want) } @@ -287,7 +287,7 @@ func TestRestartRequiredKeys(t *testing.T) { func TestRestartRequiredKeysIsAdvisory(t *testing.T) { writeTempConfig(t, &global.ConfigPath.Global, `{"system":{"listenPort":"8080"}}`) - keys := RestartRequiredKeys(SettingGlobal, map[string]interface{}{ + keys := IsRestartRequiredKeys(SettingGlobal, map[string]interface{}{ "system": map[string]interface{}{"listenPort": "9090"}, }) if len(keys) != 1 { diff --git a/handler/settings.go b/handler/settings.go index 9f8bc16..838c279 100644 --- a/handler/settings.go +++ b/handler/settings.go @@ -88,6 +88,6 @@ func SettingsSetHandler(w http.ResponseWriter, r *http.Request) { // it changed will not be live until the program is restarted. utils.SendSuccessResponse(w, "settings updated successfully", map[string]interface{}{ "type": settingsType, - "restartRequired": config.RestartRequiredKeys(settingsType, patch), + "restartRequired": config.IsRestartRequiredKeys(settingsType, patch), }) } diff --git a/internal/komari/client.go b/internal/komari/client.go index f727296..0be97bc 100644 --- a/internal/komari/client.go +++ b/internal/komari/client.go @@ -248,7 +248,7 @@ func (c *Client) FetchNodes() ([]NodeInfo, error) { postLog.Warning("Failed to save bot node config: " + err.Error()) } - postLog.Info(fmt.Sprintf("Fetched %d nodes from Komari", len(nodes))) + // postLog.Debug(fmt.Sprintf("Fetched %d nodes from Komari", len(nodes))) return nodes, nil } diff --git a/internal/node/tracker.go b/internal/node/tracker.go index 7b6c077..5e00456 100644 --- a/internal/node/tracker.go +++ b/internal/node/tracker.go @@ -107,6 +107,7 @@ type StatusChangeCallback func(change StatusChange) // All methods are thread-safe. type Tracker struct { mu sync.RWMutex + count int nodes map[string]*Node // uuid → Node uuidToName map[string]string // uuid → name (from node list) onlineSet map[string]bool // which uuids are currently online @@ -161,6 +162,13 @@ func (t *Tracker) fireCallbacks(change StatusChange) { } } +// GetNodeCount returns the total number of nodes in the tracker. +func (t *Tracker) GetNodeCount() int { + t.mu.RLock() + defer t.mu.RUnlock() + return t.count +} + // UpdateNodeList replaces the full node list and updates each node's name and // static Info metadata. entries maps UUID → node metadata from the Komari node // list. @@ -175,6 +183,8 @@ func (t *Tracker) UpdateNodeList(entries map[string]NodeListEntry) { t.knownUUIDs[uuid] = true } + t.count = len(entries) + t.uuidToName = make(map[string]string, len(entries)) for uuid, entry := range entries { t.uuidToName[uuid] = entry.Name diff --git a/main.go b/main.go index 16afeb7..f9295fd 100644 --- a/main.go +++ b/main.go @@ -260,11 +260,15 @@ func startBackgroundTasks(_ *config.Config) { if client == nil { continue } + orgNodeCount := node.GetTracker().GetNodeCount() nodes, err := client.FetchNodes() if err != nil { postLog.Warning("Failed to refresh node list: " + err.Error()) continue } + if node.GetTracker().GetNodeCount() != orgNodeCount { + postLog.Info(fmt.Sprintf("Refreshed node list: %d nodes", len(nodes))) + } tracker := node.GetTracker() if tracker != nil { tracker.UpdateNodeList(komari.BuildNodeListData(nodes))