重构:拆出 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>
This commit is contained in:
@@ -2,543 +2,42 @@ package main
|
||||
|
||||
import (
|
||||
cryptotls "crypto/tls"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
cfgpkg "meshtastic_mqtt_server/internal/config"
|
||||
)
|
||||
|
||||
const configFileName = "config.yaml"
|
||||
// 桥接到 internal/config — 让根目录其余文件无须修改即可继续使用旧的非导出名字。
|
||||
|
||||
type config struct {
|
||||
MQTT mqttConfig `yaml:"mqtt"`
|
||||
Meshtastic meshtasticConfig `yaml:"meshtastic"`
|
||||
Database databaseConfig `yaml:"database"`
|
||||
Web webConfig `yaml:"web"`
|
||||
AI aiConfig `yaml:"ai"`
|
||||
DataDir string `yaml:"data_dir"`
|
||||
key []byte
|
||||
}
|
||||
const (
|
||||
configFileName = cfgpkg.FileName
|
||||
databaseDriverSQLite = cfgpkg.DriverSQLite
|
||||
databaseDriverMySQL = cfgpkg.DriverMySQL
|
||||
)
|
||||
|
||||
type mqttConfig struct {
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
TLS tlsConfig `yaml:"tls"`
|
||||
}
|
||||
|
||||
type tlsConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
CertFile string `yaml:"cert_file"`
|
||||
KeyFile string `yaml:"key_file"`
|
||||
}
|
||||
|
||||
type meshtasticConfig struct {
|
||||
PSK string `yaml:"psk"`
|
||||
}
|
||||
|
||||
type databaseConfig struct {
|
||||
Driver string `yaml:"driver"`
|
||||
SQLite sqliteConfig `yaml:"sqlite"`
|
||||
MySQL mysqlConfig `yaml:"mysql"`
|
||||
}
|
||||
|
||||
type sqliteConfig struct {
|
||||
Path string `yaml:"path"`
|
||||
}
|
||||
|
||||
type mysqlConfig struct {
|
||||
DSN string `yaml:"dsn"`
|
||||
}
|
||||
|
||||
type webConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
PortEnabled bool `yaml:"port_enabled"`
|
||||
SocketEnabled bool `yaml:"socket_enabled"`
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
SocketPath string `yaml:"socket_path"`
|
||||
StaticDir string `yaml:"static_dir"`
|
||||
MapTileCacheDir string `yaml:"map_tile_cache_dir"`
|
||||
Admin webAdminConfig `yaml:"admin"`
|
||||
}
|
||||
|
||||
type webAdminConfig struct {
|
||||
Username string `yaml:"username"`
|
||||
Password string `yaml:"password"`
|
||||
SessionSecret string `yaml:"session_secret"`
|
||||
SessionSecure bool `yaml:"session_secure"`
|
||||
}
|
||||
|
||||
type aiConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
}
|
||||
|
||||
type rawConfig struct {
|
||||
MQTT *rawMQTTConfig `yaml:"mqtt"`
|
||||
Meshtastic *rawMeshtasticConfig `yaml:"meshtastic"`
|
||||
Database *rawDatabaseConfig `yaml:"database"`
|
||||
Web *rawWebConfig `yaml:"web"`
|
||||
AI *rawAIConfig `yaml:"ai"`
|
||||
DataDir *string `yaml:"data_dir"`
|
||||
}
|
||||
|
||||
type rawAIConfig struct {
|
||||
Enabled *bool `yaml:"enabled"`
|
||||
}
|
||||
|
||||
type rawMQTTConfig struct {
|
||||
Host *string `yaml:"host"`
|
||||
Port *int `yaml:"port"`
|
||||
TLS *rawTLSConfig `yaml:"tls"`
|
||||
}
|
||||
|
||||
type rawTLSConfig struct {
|
||||
Enabled *bool `yaml:"enabled"`
|
||||
CertFile *string `yaml:"cert_file"`
|
||||
KeyFile *string `yaml:"key_file"`
|
||||
}
|
||||
|
||||
type rawMeshtasticConfig struct {
|
||||
PSK *string `yaml:"psk"`
|
||||
}
|
||||
|
||||
type rawDatabaseConfig struct {
|
||||
Driver *string `yaml:"driver"`
|
||||
SQLite *rawSQLiteConfig `yaml:"sqlite"`
|
||||
MySQL *rawMySQLConfig `yaml:"mysql"`
|
||||
}
|
||||
|
||||
type rawSQLiteConfig struct {
|
||||
Path *string `yaml:"path"`
|
||||
}
|
||||
|
||||
type rawMySQLConfig struct {
|
||||
DSN *string `yaml:"dsn"`
|
||||
}
|
||||
|
||||
type rawWebConfig struct {
|
||||
Enabled *bool `yaml:"enabled"`
|
||||
PortEnabled *bool `yaml:"port_enabled"`
|
||||
SocketEnabled *bool `yaml:"socket_enabled"`
|
||||
Host *string `yaml:"host"`
|
||||
Port *int `yaml:"port"`
|
||||
SocketPath *string `yaml:"socket_path"`
|
||||
StaticDir *string `yaml:"static_dir"`
|
||||
MapTileCacheDir *string `yaml:"map_tile_cache_dir"`
|
||||
Admin *rawWebAdminConfig `yaml:"admin"`
|
||||
}
|
||||
|
||||
type rawWebAdminConfig struct {
|
||||
Username *string `yaml:"username"`
|
||||
Password *string `yaml:"password"`
|
||||
SessionSecret *string `yaml:"session_secret"`
|
||||
SessionSecure *bool `yaml:"session_secure"`
|
||||
}
|
||||
|
||||
// defaultConfig 返回内置默认配置。
|
||||
func defaultConfig() *config {
|
||||
return &config{
|
||||
MQTT: mqttConfig{
|
||||
Host: "0.0.0.0",
|
||||
Port: 1883,
|
||||
TLS: tlsConfig{
|
||||
Enabled: false,
|
||||
CertFile: "",
|
||||
KeyFile: "",
|
||||
},
|
||||
},
|
||||
Meshtastic: meshtasticConfig{
|
||||
PSK: "AQ==",
|
||||
},
|
||||
Database: databaseConfig{
|
||||
Driver: "sqlite",
|
||||
SQLite: sqliteConfig{Path: defaultSQLitePath()},
|
||||
MySQL: mysqlConfig{DSN: ""},
|
||||
},
|
||||
Web: webConfig{
|
||||
Enabled: true,
|
||||
PortEnabled: true,
|
||||
SocketEnabled: defaultWebSocketPath() != "",
|
||||
Host: "0.0.0.0",
|
||||
Port: 8080,
|
||||
SocketPath: defaultWebSocketPath(),
|
||||
StaticDir: "./dist",
|
||||
MapTileCacheDir: defaultMapTileCacheDir(),
|
||||
Admin: webAdminConfig{
|
||||
Username: "admin",
|
||||
Password: "admin",
|
||||
SessionSecret: "",
|
||||
SessionSecure: false,
|
||||
},
|
||||
},
|
||||
AI: aiConfig{
|
||||
Enabled: false,
|
||||
},
|
||||
DataDir: defaultDataDir(),
|
||||
}
|
||||
}
|
||||
|
||||
// defaultConfigDir 根据操作系统返回配置目录。
|
||||
func defaultConfigDir() string {
|
||||
return defaultConfigDirForGOOS(runtime.GOOS)
|
||||
}
|
||||
|
||||
func defaultConfigDirForGOOS(goos string) string {
|
||||
if useRelativeDefaultPath(goos) {
|
||||
return filepath.Join(".", "win", "etc", "mesh_mqtt_go")
|
||||
}
|
||||
return filepath.Join(string(filepath.Separator), "etc", "mesh_mqtt_go")
|
||||
}
|
||||
|
||||
func useRelativeDefaultPath(goos string) bool {
|
||||
return goos == "windows" || goos == "darwin"
|
||||
}
|
||||
|
||||
// defaultConfigPath 返回默认配置文件路径。
|
||||
func defaultConfigPath() string {
|
||||
return filepath.Join(defaultConfigDir(), configFileName)
|
||||
}
|
||||
|
||||
func defaultSQLitePath() string {
|
||||
return defaultSQLitePathForGOOS(runtime.GOOS)
|
||||
}
|
||||
|
||||
func defaultWebSocketPath() string {
|
||||
return defaultWebSocketPathForGOOS(runtime.GOOS)
|
||||
}
|
||||
|
||||
func defaultMapTileCacheDir() string {
|
||||
return defaultMapTileCacheDirForGOOS(runtime.GOOS)
|
||||
}
|
||||
|
||||
func defaultMapTileCacheDirForGOOS(goos string) string {
|
||||
if useRelativeDefaultPath(goos) {
|
||||
return filepath.Join(".", "win", "srv", "mesh_mqtt_go")
|
||||
}
|
||||
return filepath.Join(string(filepath.Separator), "srv", "mesh_mqtt_go")
|
||||
}
|
||||
|
||||
func defaultWebSocketPathForGOOS(goos string) string {
|
||||
if goos == "windows" {
|
||||
return ""
|
||||
}
|
||||
if useRelativeDefaultPath(goos) {
|
||||
return filepath.Join(".", "win", "opt", "mesh_mqtt_go", "web.sock")
|
||||
}
|
||||
return filepath.Join(string(filepath.Separator), "opt", "mesh_mqtt_go", "web.sock")
|
||||
}
|
||||
// 旧的小写类型名通过别名继续可用。
|
||||
type (
|
||||
config = cfgpkg.Config
|
||||
mqttConfig = cfgpkg.MQTTConfig
|
||||
tlsConfig = cfgpkg.TLSConfig
|
||||
meshtasticConfig = cfgpkg.MeshtasticConfig
|
||||
databaseConfig = cfgpkg.DatabaseConfig
|
||||
sqliteConfig = cfgpkg.SQLiteConfig
|
||||
mysqlConfig = cfgpkg.MySQLConfig
|
||||
webConfig = cfgpkg.WebConfig
|
||||
webAdminConfig = cfgpkg.WebAdminConfig
|
||||
aiConfig = cfgpkg.AIConfig
|
||||
)
|
||||
|
||||
func defaultConfig() *config { return cfgpkg.Default() }
|
||||
func defaultConfigDir() string { return cfgpkg.DefaultDir() }
|
||||
func defaultConfigPath() string { return cfgpkg.DefaultPath() }
|
||||
func loadConfig(path string) (*config, error) { return cfgpkg.Load(path) }
|
||||
func writeConfig(path string, cfg *config) error { return cfgpkg.Write(path, cfg) }
|
||||
func validateConfig(cfg *config) error { return cfgpkg.Validate(cfg) }
|
||||
func clearWebSocketPathOnUnsupportedGOOS(cfg *config, goos string) bool {
|
||||
if goos != "windows" {
|
||||
return false
|
||||
}
|
||||
changed := false
|
||||
if cfg.Web.SocketPath != "" {
|
||||
cfg.Web.SocketPath = ""
|
||||
changed = true
|
||||
}
|
||||
if cfg.Web.SocketEnabled {
|
||||
cfg.Web.SocketEnabled = false
|
||||
changed = true
|
||||
}
|
||||
return changed
|
||||
return cfgpkg.ClearWebSocketPathOnUnsupportedGOOS(cfg, goos)
|
||||
}
|
||||
|
||||
func defaultSQLitePathForGOOS(goos string) string {
|
||||
if useRelativeDefaultPath(goos) {
|
||||
return filepath.Join(".", "win", "etc", "mesh_mqtt_go", "mesh_mqtt_go.db")
|
||||
}
|
||||
return filepath.Join(string(filepath.Separator), "srv", "mesh_mqtt_go", "mesh_mqtt_go.db")
|
||||
}
|
||||
|
||||
func defaultDataDir() string {
|
||||
return defaultDataDirForGOOS(runtime.GOOS)
|
||||
}
|
||||
|
||||
func defaultDataDirForGOOS(goos string) string {
|
||||
if useRelativeDefaultPath(goos) {
|
||||
return filepath.Join(".", "win", "var", "lib", "mesh_mqtt_go")
|
||||
}
|
||||
return filepath.Join(string(filepath.Separator), "var", "lib", "mesh_mqtt_go")
|
||||
}
|
||||
|
||||
// loadConfig 加载配置文件;文件不存在时生成,字段缺失时自动补全并写回。
|
||||
func loadConfig(path string) (*config, error) {
|
||||
if path == "" {
|
||||
path = defaultConfigPath()
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
|
||||
return nil, fmt.Errorf("create config directory %s: %w", filepath.Dir(path), err)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("stat config file %s: %w", path, err)
|
||||
}
|
||||
cfg := defaultConfig()
|
||||
if err := writeConfig(path, cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read config file %s: %w", path, err)
|
||||
}
|
||||
|
||||
var raw rawConfig
|
||||
if err := yaml.Unmarshal(data, &raw); err != nil {
|
||||
return nil, fmt.Errorf("parse config file %s: %w", path, err)
|
||||
}
|
||||
|
||||
cfg, changed := normalizeConfig(raw)
|
||||
if clearWebSocketPathOnUnsupportedGOOS(cfg, runtime.GOOS) {
|
||||
changed = true
|
||||
}
|
||||
if err := validateConfig(cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if changed {
|
||||
if err := writeConfig(path, cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// normalizeConfig 将原始配置合并到默认配置,并标记是否补齐了缺失项。
|
||||
func normalizeConfig(raw rawConfig) (*config, bool) {
|
||||
cfg := defaultConfig()
|
||||
changed := false
|
||||
|
||||
if raw.MQTT == nil {
|
||||
changed = true
|
||||
} else {
|
||||
if raw.MQTT.Host == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.MQTT.Host = *raw.MQTT.Host
|
||||
}
|
||||
if raw.MQTT.Port == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.MQTT.Port = *raw.MQTT.Port
|
||||
}
|
||||
if raw.MQTT.TLS == nil {
|
||||
changed = true
|
||||
} else {
|
||||
if raw.MQTT.TLS.Enabled == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.MQTT.TLS.Enabled = *raw.MQTT.TLS.Enabled
|
||||
}
|
||||
if raw.MQTT.TLS.CertFile == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.MQTT.TLS.CertFile = *raw.MQTT.TLS.CertFile
|
||||
}
|
||||
if raw.MQTT.TLS.KeyFile == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.MQTT.TLS.KeyFile = *raw.MQTT.TLS.KeyFile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if raw.Meshtastic == nil {
|
||||
changed = true
|
||||
} else if raw.Meshtastic.PSK == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.Meshtastic.PSK = *raw.Meshtastic.PSK
|
||||
}
|
||||
|
||||
if raw.Database == nil {
|
||||
changed = true
|
||||
} else {
|
||||
if raw.Database.Driver == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.Database.Driver = *raw.Database.Driver
|
||||
}
|
||||
if raw.Database.SQLite == nil {
|
||||
changed = true
|
||||
} else if raw.Database.SQLite.Path == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.Database.SQLite.Path = *raw.Database.SQLite.Path
|
||||
}
|
||||
if raw.Database.MySQL == nil {
|
||||
changed = true
|
||||
} else if raw.Database.MySQL.DSN == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.Database.MySQL.DSN = *raw.Database.MySQL.DSN
|
||||
}
|
||||
}
|
||||
|
||||
if raw.Web == nil {
|
||||
changed = true
|
||||
} else {
|
||||
if raw.Web.Enabled == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.Web.Enabled = *raw.Web.Enabled
|
||||
}
|
||||
if raw.Web.PortEnabled == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.Web.PortEnabled = *raw.Web.PortEnabled
|
||||
}
|
||||
if raw.Web.SocketEnabled == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.Web.SocketEnabled = *raw.Web.SocketEnabled
|
||||
}
|
||||
if raw.Web.Host == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.Web.Host = *raw.Web.Host
|
||||
}
|
||||
if raw.Web.Port == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.Web.Port = *raw.Web.Port
|
||||
}
|
||||
if raw.Web.SocketPath == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.Web.SocketPath = *raw.Web.SocketPath
|
||||
}
|
||||
if raw.Web.StaticDir == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.Web.StaticDir = *raw.Web.StaticDir
|
||||
}
|
||||
if raw.Web.MapTileCacheDir == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.Web.MapTileCacheDir = *raw.Web.MapTileCacheDir
|
||||
}
|
||||
if raw.Web.Admin == nil {
|
||||
changed = true
|
||||
} else {
|
||||
if raw.Web.Admin.Username == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.Web.Admin.Username = *raw.Web.Admin.Username
|
||||
}
|
||||
if raw.Web.Admin.Password == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.Web.Admin.Password = *raw.Web.Admin.Password
|
||||
}
|
||||
if raw.Web.Admin.SessionSecret == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.Web.Admin.SessionSecret = *raw.Web.Admin.SessionSecret
|
||||
}
|
||||
if raw.Web.Admin.SessionSecure == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.Web.Admin.SessionSecure = *raw.Web.Admin.SessionSecure
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if raw.AI == nil {
|
||||
changed = true
|
||||
} else {
|
||||
if raw.AI.Enabled == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.AI.Enabled = *raw.AI.Enabled
|
||||
}
|
||||
}
|
||||
|
||||
if raw.DataDir == nil {
|
||||
changed = true
|
||||
} else {
|
||||
cfg.DataDir = *raw.DataDir
|
||||
}
|
||||
|
||||
return cfg, changed
|
||||
}
|
||||
|
||||
func validateConfig(cfg *config) error {
|
||||
if cfg.MQTT.Port <= 0 || cfg.MQTT.Port > 65535 {
|
||||
return fmt.Errorf("invalid mqtt port %d: must be 1-65535", cfg.MQTT.Port)
|
||||
}
|
||||
switch cfg.Database.Driver {
|
||||
case "sqlite":
|
||||
if cfg.Database.SQLite.Path == "" {
|
||||
return fmt.Errorf("database.sqlite.path is required when database.driver is sqlite")
|
||||
}
|
||||
case "mysql":
|
||||
if cfg.Database.MySQL.DSN == "" {
|
||||
return fmt.Errorf("database.mysql.dsn is required when database.driver is mysql")
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("invalid database.driver %q: must be sqlite or mysql", cfg.Database.Driver)
|
||||
}
|
||||
if cfg.Web.Enabled {
|
||||
if !cfg.Web.PortEnabled && !cfg.Web.SocketEnabled {
|
||||
return fmt.Errorf("web.port_enabled and web.socket_enabled cannot both be false when web is enabled")
|
||||
}
|
||||
if cfg.Web.PortEnabled && (cfg.Web.Port <= 0 || cfg.Web.Port > 65535) {
|
||||
return fmt.Errorf("invalid web port %d: must be 1-65535", cfg.Web.Port)
|
||||
}
|
||||
if cfg.Web.SocketEnabled && cfg.Web.SocketPath == "" {
|
||||
return fmt.Errorf("web.socket_path is required when web.socket_enabled is true")
|
||||
}
|
||||
if cfg.Web.StaticDir == "" {
|
||||
return fmt.Errorf("web.static_dir is required when web is enabled")
|
||||
}
|
||||
if cfg.Web.MapTileCacheDir == "" {
|
||||
return fmt.Errorf("web.map_tile_cache_dir is required when web is enabled")
|
||||
}
|
||||
if cfg.Web.Admin.Username == "" {
|
||||
return fmt.Errorf("web.admin.username is required when web is enabled")
|
||||
}
|
||||
if cfg.Web.Admin.Password == "" {
|
||||
return fmt.Errorf("web.admin.password is required when web is enabled")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeConfig(path string, cfg *config) error {
|
||||
data, err := yaml.Marshal(cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode config file %s: %w", path, err)
|
||||
}
|
||||
if err := os.WriteFile(path, data, 0644); err != nil {
|
||||
return fmt.Errorf("write config file %s: %w", path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// buildTLSConfig 根据配置构造 mochi listener 使用的 TLS 设置。
|
||||
func buildTLSConfig(cfg tlsConfig) (*cryptotls.Config, error) {
|
||||
if !cfg.Enabled {
|
||||
return nil, nil
|
||||
}
|
||||
if cfg.CertFile == "" {
|
||||
return nil, fmt.Errorf("mqtt tls cert_file is required when tls is enabled")
|
||||
}
|
||||
if cfg.KeyFile == "" {
|
||||
return nil, fmt.Errorf("mqtt tls key_file is required when tls is enabled")
|
||||
}
|
||||
|
||||
cert, err := cryptotls.LoadX509KeyPair(cfg.CertFile, cfg.KeyFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load mqtt tls certificate: %w", err)
|
||||
}
|
||||
return &cryptotls.Config{
|
||||
MinVersion: cryptotls.VersionTLS12,
|
||||
Certificates: []cryptotls.Certificate{cert},
|
||||
}, nil
|
||||
return cfgpkg.BuildTLS(cfg)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user