hn-readcard-go/config.go

169 lines
4.6 KiB
Go
Raw Permalink Normal View History

2026-08-06 11:23:33 +08:00
package main
import (
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
)
type Config struct {
Host string `json:"host"`
Port int `json:"port"`
DLLDir string `json:"dll_dir"`
CORSOrigin string `json:"cors_origin"`
LogDir string `json:"log_dir"`
LogRetentionDays int `json:"log_retention_days"`
LogMaxFileMB int `json:"log_max_file_mb"`
LogMaxTotalMB int `json:"log_max_total_mb"`
RestartDelayMS int `json:"restart_delay_ms"`
MaxRapidRestarts int `json:"max_rapid_restarts"`
2026-08-12 13:40:06 +08:00
GUIReaderType string `json:"gui_reader_type"`
2026-08-06 11:23:33 +08:00
AppRoot string `json:"-"`
}
func defaultConfig(appRoot string) Config {
return Config{
Host: "127.0.0.1",
Port: 17880,
DLLDir: "package/DWCardReaderDLL",
CORSOrigin: "*",
LogDir: "logs",
LogRetentionDays: 30,
LogMaxFileMB: 20,
LogMaxTotalMB: 200,
RestartDelayMS: 1500,
MaxRapidRestarts: 5,
2026-08-12 13:40:06 +08:00
GUIReaderType: "ZJ_HZ_310000",
2026-08-06 11:23:33 +08:00
AppRoot: appRoot,
}
}
func resolveAppRoot() (string, error) {
if root := strings.TrimSpace(os.Getenv("CARD_APP_ROOT")); root != "" {
return filepath.Abs(root)
}
cwd, cwdErr := os.Getwd()
if cwdErr == nil && fileExists(filepath.Join(cwd, "config.json")) {
return filepath.Abs(cwd)
}
exe, exeErr := os.Executable()
if exeErr == nil {
return filepath.Abs(filepath.Dir(exe))
}
if cwdErr != nil {
return "", fmt.Errorf("无法确定程序目录: cwd=%v, executable=%v", cwdErr, exeErr)
}
return filepath.Abs(cwd)
}
func loadConfig() (Config, error) {
root, err := resolveAppRoot()
if err != nil {
return Config{}, err
}
return loadConfigAt(root)
}
func loadConfigAt(root string) (Config, error) {
root, err := filepath.Abs(root)
if err != nil {
return Config{}, fmt.Errorf("解析程序目录失败: %w", err)
}
cfg := defaultConfig(root)
path := filepath.Join(root, "config.json")
if data, readErr := os.ReadFile(path); readErr == nil {
if err = json.Unmarshal(data, &cfg); err != nil {
return Config{}, fmt.Errorf("配置文件格式错误 %s: %w", path, err)
}
} else if !errors.Is(readErr, os.ErrNotExist) {
return Config{}, fmt.Errorf("读取配置文件失败 %s: %w", path, readErr)
}
cfg.AppRoot = root
if value := strings.TrimSpace(os.Getenv("CARD_HOST")); value != "" {
cfg.Host = value
}
if value := strings.TrimSpace(os.Getenv("CARD_PORT")); value != "" {
cfg.Port, err = strconv.Atoi(value)
if err != nil {
return Config{}, fmt.Errorf("CARD_PORT 不是有效端口: %q", value)
}
}
if value := strings.TrimSpace(os.Getenv("CARD_DLL_DIR")); value != "" {
cfg.DLLDir = value
}
2026-08-12 13:40:06 +08:00
if value := strings.TrimSpace(os.Getenv("CARD_GUI_READER_TYPE")); value != "" {
cfg.GUIReaderType = value
}
2026-08-06 11:23:33 +08:00
if value := os.Getenv("CARD_CORS_ORIGIN"); value != "" {
cfg.CORSOrigin = value
}
if value := strings.TrimSpace(os.Getenv("CARD_LOG_DIR")); value != "" {
cfg.LogDir = value
}
if value := strings.TrimSpace(os.Getenv("CARD_LOG_MAX_FILE_MB")); value != "" {
cfg.LogMaxFileMB, err = strconv.Atoi(value)
if err != nil {
return Config{}, fmt.Errorf("CARD_LOG_MAX_FILE_MB 不是有效整数: %q", value)
}
}
if value := strings.TrimSpace(os.Getenv("CARD_LOG_MAX_TOTAL_MB")); value != "" {
cfg.LogMaxTotalMB, err = strconv.Atoi(value)
if err != nil {
return Config{}, fmt.Errorf("CARD_LOG_MAX_TOTAL_MB 不是有效整数: %q", value)
}
}
if strings.TrimSpace(cfg.Host) == "" {
return Config{}, errors.New("host 不能为空")
}
if cfg.Port < 1 || cfg.Port > 65535 {
return Config{}, fmt.Errorf("port 超出范围: %d", cfg.Port)
}
if strings.TrimSpace(cfg.DLLDir) == "" {
return Config{}, errors.New("dll_dir 不能为空")
}
2026-08-12 13:40:06 +08:00
if strings.TrimSpace(cfg.GUIReaderType) == "" {
return Config{}, errors.New("gui_reader_type 不能为空")
}
2026-08-06 11:23:33 +08:00
if strings.TrimSpace(cfg.CORSOrigin) == "" {
cfg.CORSOrigin = "*"
}
if strings.TrimSpace(cfg.LogDir) == "" {
cfg.LogDir = "logs"
}
if cfg.LogRetentionDays <= 0 {
cfg.LogRetentionDays = 30
}
if cfg.LogMaxFileMB <= 0 {
cfg.LogMaxFileMB = 20
}
if cfg.LogMaxTotalMB <= 0 {
cfg.LogMaxTotalMB = 200
}
if cfg.LogMaxTotalMB < cfg.LogMaxFileMB*3 {
return Config{}, fmt.Errorf("log_max_total_mb 至少应为 log_max_file_mb 的 3 倍(当前 %d < %d", cfg.LogMaxTotalMB, cfg.LogMaxFileMB*3)
}
if cfg.RestartDelayMS < 100 {
cfg.RestartDelayMS = 1500
}
if cfg.MaxRapidRestarts <= 0 {
cfg.MaxRapidRestarts = 5
}
if !filepath.IsAbs(cfg.LogDir) {
cfg.LogDir = filepath.Join(cfg.AppRoot, cfg.LogDir)
}
return cfg, nil
}
func fileExists(path string) bool {
info, err := os.Stat(path)
return err == nil && !info.IsDir()
}