Files
meshtastic_mqtt_server/internal/store/runtime_settings_store.go
T
kevinandClaude eff4972668 重构:拆出 internal/config 与 internal/store 子包
把工程根目录中和"配置加载"、"数据存储"两个领域相关的全部 Go 文件迁到
internal/ 下的子包,按功能分组的第一阶段成果。

internal/config/
- 从 config.go 抽出 Config / MQTTConfig / WebConfig / DatabaseConfig 等
  类型并大写导出,函数改名 Default/Load/Write/Validate/BuildTLS 等。
- 测试随被测代码迁移成 package config 的内部测试。
- 根目录留 config.go 作桥接:用 type alias 让旧的小写名(config /
  mqttConfig / databaseConfig 等)继续可用,避免修改 30+ 处调用方。

internal/store/
- 把 db.go、store_query.go、db_write_queue.go 与 13 个 *_store.go 一并
  迁入;26 个 *Record 类型与 store 同包以避免循环依赖。
- store -> Store;50+ 标识符从小写未导出改为大写导出(包括 record、
  ListOptions、错误变量、bot/llm/runtime 常量、helpers 等)。
- 新增 DB() / Driver() 访问器供 ai 子系统使用,避免直接访问私有字段。
- bot_pki_store.go 独立出来,把 PKI 解密所需的 store 方法集中归类。
- helpers.go 提供 hashPassword / uint32FromRecord / printJSON 等以前在
  其他根目录文件中的辅助;test_helpers_test.go 提供 verifyPassword
  与 publicMapTileSourceDTO 让测试可以本地运行而不依赖 main 包。

根目录新增:
- store_bridge.go:完整 type-alias / 函数包装层,把 internal/store 的
  导出名映射回旧的小写名,让 admin_*_routes.go、web.go、bot_service.go
  等仍未迁出的文件继续编译。后续步骤把它们迁到各自领域包后可逐步删除。
- test_helpers_test.go:根目录测试沿用 openTestStore 的入口。

go build ./... 与 go test ./... 全部通过;测试数量与重构前一致。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-18 13:56:36 +08:00

99 lines
2.7 KiB
Go

package store
import (
"errors"
"fmt"
"strconv"
"strings"
"time"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
const (
RuntimeSettingAllowEncryptedForwarding = "mqtt.allow_encrypted_forwarding"
RuntimeSettingLLMQueueEnabled = "llm.queue_enabled"
RuntimeSettingLLMQueueIncludeChannel = "llm.include_channel_messages"
runtimeSettingTypeBool = "bool"
)
type RuntimeSettingsSnapshot struct {
AllowEncryptedForwarding bool
LLMQueueEnabled bool
LLMIncludeChannel bool
}
func (s *Store) GetRuntimeSettings() (RuntimeSettingsSnapshot, error) {
allowEncrypted, err := s.GetBoolRuntimeSetting(RuntimeSettingAllowEncryptedForwarding, false)
if err != nil {
return RuntimeSettingsSnapshot{}, err
}
llmQueueEnabled, err := s.GetBoolRuntimeSetting(RuntimeSettingLLMQueueEnabled, true)
if err != nil {
return RuntimeSettingsSnapshot{}, err
}
llmIncludeChannel, err := s.GetBoolRuntimeSetting(RuntimeSettingLLMQueueIncludeChannel, false)
if err != nil {
return RuntimeSettingsSnapshot{}, err
}
return RuntimeSettingsSnapshot{
AllowEncryptedForwarding: allowEncrypted,
LLMQueueEnabled: llmQueueEnabled,
LLMIncludeChannel: llmIncludeChannel,
}, nil
}
func (s *Store) GetBoolRuntimeSetting(key string, defaultValue bool) (bool, error) {
key = strings.TrimSpace(key)
if key == "" {
return false, fmt.Errorf("runtime setting key is required")
}
var row RuntimeSettingRecord
err := s.db.Where("`key` = ?", key).Take(&row).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return defaultValue, nil
}
if err != nil {
return false, err
}
if row.ValueType != "" && row.ValueType != runtimeSettingTypeBool {
return false, fmt.Errorf("runtime setting %s has type %s, want %s", key, row.ValueType, runtimeSettingTypeBool)
}
value, err := strconv.ParseBool(strings.TrimSpace(row.Value))
if err != nil {
return false, fmt.Errorf("parse runtime setting %s: %w", key, err)
}
return value, nil
}
func (s *Store) SetBoolRuntimeSetting(key string, value bool, label string) (*RuntimeSettingRecord, error) {
key = strings.TrimSpace(key)
if key == "" {
return nil, fmt.Errorf("runtime setting key is required")
}
row := RuntimeSettingRecord{
Key: key,
Value: strconv.FormatBool(value),
ValueType: runtimeSettingTypeBool,
Label: strings.TrimSpace(label),
}
if err := s.db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "key"}},
DoUpdates: clause.Assignments(map[string]any{
"value": row.Value,
"value_type": row.ValueType,
"label": row.Label,
"updated_at": time.Now(),
}),
}).Create(&row).Error; err != nil {
return nil, err
}
if err := s.db.Where("`key` = ?", key).Take(&row).Error; err != nil {
return nil, err
}
return &row, nil
}