feat(komari): add bot_node_config.json to restore single node configurarion

This commit is contained in:
2026-09-06 10:33:58 +08:00
parent 13a670eadd
commit 5bc85effa7
3 changed files with 67 additions and 0 deletions
+39
View File
@@ -1,6 +1,7 @@
package config package config
import ( import (
"bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
@@ -115,6 +116,44 @@ func LoadBotUserConfig(configPath string) (*BotUserConfig, error) {
return &cfg, nil return &cfg, nil
} }
// SaveBotNodeConfig persists the given node UUIDs to the bot node config file.
// Entries already present in the file are always preserved: a UUID Komari no
// longer reports on a given fetch is kept rather than deleted, so per-node
// settings for stale nodes survive a node-list refresh that does not include
// them. UUIDs seen for the first time are added with an empty BotNodeOptions
// entry. The resulting JSON has its object keys emitted in sorted order by
// encoding/json, keeping the file deterministic across writes. The path is
// supplied by the caller (typically global.ConfigPath.BotNodeConfig).
func SaveBotNodeConfig(configPath string, uuids []string) error {
// Start from whatever is already on disk so nothing is dropped. An empty or
// missing file is treated as an empty map.
members := make(BotNodeMembers)
if data, err := os.ReadFile(configPath); err == nil && len(bytes.TrimSpace(data)) > 0 {
if err := json.Unmarshal(data, &members); err != nil {
return fmt.Errorf("failed to parse existing bot node config %s: %w", configPath, err)
}
}
// Add every currently-fetched UUID, but never overwrite an entry that is
// already configured.
for _, uuid := range uuids {
if _, ok := members[uuid]; !ok {
members[uuid] = BotNodeOptions{}
}
}
data, err := json.MarshalIndent(members, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal bot node config: %w", err)
}
data = append(data, '\n')
if err := os.WriteFile(configPath, data, 0o644); err != nil {
return fmt.Errorf("failed to write bot node config %s: %w", configPath, err)
}
return nil
}
// IsDebugMode returns whether debug mode is enabled. // IsDebugMode returns whether debug mode is enabled.
func IsDebugMode() bool { func IsDebugMode() bool {
if C_globalConfig == nil { if C_globalConfig == nil {
+13
View File
@@ -170,3 +170,16 @@ type BotUserConfig struct {
} }
var C_botUserConfig *BotUserConfig var C_botUserConfig *BotUserConfig
// BotNodeOptions holds per-node options stored in bot_node_config.json. The
// struct is currently empty; per-node settings can be added here later without
// invalidating existing files.
type BotNodeOptions struct {
}
// BotNodeMembers maps a node UUID (as reported by Komari) to its per-node
// options. A plain struct value marshals to an empty JSON object, so
// bot_node_config.json reads like:
//
// {"<uuid1>": {}, "<uuid2>": {}}
type BotNodeMembers map[string]BotNodeOptions
+15
View File
@@ -13,6 +13,7 @@ import (
"time" "time"
"nukumizu-backend/config" "nukumizu-backend/config"
"nukumizu-backend/global"
"nukumizu-backend/internal/node" "nukumizu-backend/internal/node"
"nukumizu-backend/postLog" "nukumizu-backend/postLog"
) )
@@ -225,6 +226,20 @@ func (c *Client) FetchNodes() ([]NodeInfo, error) {
nodes = append(nodes, n) nodes = append(nodes, n)
} }
// Persist the fetched node UUIDs to bot_node_config.json on every fetch
// (startup login, WebSocket reconnect and periodic refresh all funnel
// through FetchNodes) so the file always reflects the nodes Komari
// currently manages. A persistence failure is only logged: the node data
// itself was fetched successfully and must not be discarded over a disk
// write problem.
uuids := make([]string, len(nodes))
for i, n := range nodes {
uuids[i] = n.UUID
}
if err := config.SaveBotNodeConfig(global.ConfigPath.BotNodeConfig, uuids); err != nil {
postLog.Warning("Failed to save bot node config: " + err.Error())
}
postLog.Info(fmt.Sprintf("Fetched %d nodes from Komari", len(nodes))) postLog.Info(fmt.Sprintf("Fetched %d nodes from Komari", len(nodes)))
return nodes, nil return nodes, nil
} }