158 lines
4.8 KiB
Go
158 lines
4.8 KiB
Go
// Package config — конфигурация монолита iot-service из env-переменных.
|
|
//
|
|
// Принцип: несекретные значения имеют дефолты (продублированы ENV в Dockerfile),
|
|
// секреты — обязательны и задаются в deck-UI при создании контейнера.
|
|
// Env-переменные после деплоя не меняются — поэтому дефолты вшиты в образ.
|
|
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"log/slog"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// Config — вся конфигурация iot-service.
|
|
type Config struct {
|
|
// HTTP API
|
|
APIPort string
|
|
|
|
// PostgreSQL (managed, общий для устройств и телеметрии)
|
|
IOTPGDSN string
|
|
|
|
// shared-SQS
|
|
SQSEndpoint string
|
|
SQSAccessKey string
|
|
SQSSecretKey string
|
|
SQSQueueName string
|
|
SQSRegion string
|
|
|
|
// SQS-потребитель
|
|
SQSLongPollSeconds int
|
|
SQSVisibilityTimeout int
|
|
|
|
// MQTT (EMQX)
|
|
MQTTBrokerURL string
|
|
MQTTUsername string
|
|
MQTTPassword string
|
|
MQTTClientID string
|
|
|
|
// Админ-статистика
|
|
AdminStatsToken string
|
|
|
|
// Безопасность
|
|
AuthTestMode bool
|
|
// JwtHMACSecret — если задан, JWT проверяется по HS256 (HMAC-SHA256).
|
|
// Пусто — структурная проверка (как раньше, периметр = платформа).
|
|
JwtHMACSecret string
|
|
|
|
// Логирование
|
|
LogLevel slog.Level
|
|
}
|
|
|
|
// getEnv возвращает значение env или дефолт.
|
|
func getEnv(key, def string) string {
|
|
if v := os.Getenv(key); v != "" {
|
|
return v
|
|
}
|
|
return def
|
|
}
|
|
|
|
// getEnvInt возвращает целое значение env или дефолт (неположительное — дефолт).
|
|
func getEnvInt(key string, def int) int {
|
|
if v := os.Getenv(key); v != "" {
|
|
if n, err := strconv.Atoi(v); err == nil && n > 0 {
|
|
return n
|
|
}
|
|
}
|
|
return def
|
|
}
|
|
|
|
// getEnvBool разбирает булево значение env.
|
|
func getEnvBool(key string, def bool) bool {
|
|
v := os.Getenv(key)
|
|
if v == "" {
|
|
return def
|
|
}
|
|
switch strings.ToLower(v) {
|
|
case "1", "true", "yes", "on":
|
|
return true
|
|
case "0", "false", "no", "off":
|
|
return false
|
|
default:
|
|
return def
|
|
}
|
|
}
|
|
|
|
// parseLogLevel разбирает уровень логирования.
|
|
func parseLogLevel(v string, def slog.Level) slog.Level {
|
|
switch strings.ToLower(v) {
|
|
case "debug":
|
|
return slog.LevelDebug
|
|
case "warn", "warning":
|
|
return slog.LevelWarn
|
|
case "error":
|
|
return slog.LevelError
|
|
default:
|
|
return def
|
|
}
|
|
}
|
|
|
|
// Load читает конфигурацию из env, подставляет дефолты
|
|
// и проверяет обязательные (секретные) переменные.
|
|
func Load() (*Config, error) {
|
|
cfg := &Config{
|
|
APIPort: getEnv("API_PORT", DefaultAPIPort),
|
|
IOTPGDSN: os.Getenv("IOT_PG_DSN"),
|
|
SQSEndpoint: getEnv("SQS_ENDPOINT", DefaultSQSEndpoint),
|
|
SQSAccessKey: os.Getenv("SQS_ACCESS_KEY"),
|
|
SQSSecretKey: os.Getenv("SQS_SECRET_KEY"),
|
|
SQSQueueName: getEnv("SQS_QUEUE_NAME", DefaultSQSQueueName),
|
|
SQSRegion: getEnv("SQS_REGION", DefaultSQSRegion),
|
|
SQSLongPollSeconds: getEnvInt("SQS_LONG_POLL_SECONDS", 20),
|
|
SQSVisibilityTimeout: getEnvInt("SQS_VISIBILITY_TIMEOUT", 120),
|
|
MQTTUsername: os.Getenv("MQTT_USERNAME"),
|
|
MQTTPassword: os.Getenv("MQTT_PASSWORD"),
|
|
MQTTClientID: getEnv("MQTT_CLIENT_ID", DefaultMQTTClientID),
|
|
AdminStatsToken: os.Getenv("ADMIN_STATS_TOKEN"),
|
|
AuthTestMode: getEnvBool("AUTH_TEST_MODE", false),
|
|
JwtHMACSecret: os.Getenv("JWT_HMAC_SECRET"),
|
|
LogLevel: parseLogLevel(os.Getenv("LOG_LEVEL"), slog.LevelInfo),
|
|
}
|
|
|
|
// MQTT broker URL: либо полный MQTT_BROKER_URL, либо из HOST/PORT/WS_PATH
|
|
cfg.MQTTBrokerURL = os.Getenv("MQTT_BROKER_URL")
|
|
if cfg.MQTTBrokerURL == "" {
|
|
host := getEnv("MQTT_HOST", DefaultMQTTHost)
|
|
port := getEnv("MQTT_PORT", DefaultMQTTPort)
|
|
path := getEnv("MQTT_WS_PATH", DefaultMQTTWSPath)
|
|
cfg.MQTTBrokerURL = "ws://" + host + ":" + port + path
|
|
} else if !strings.HasPrefix(cfg.MQTTBrokerURL, "ws://") &&
|
|
!strings.HasPrefix(cfg.MQTTBrokerURL, "wss://") {
|
|
return nil, fmt.Errorf("MQTT_BROKER_URL must start with ws:// or wss://, got %q", cfg.MQTTBrokerURL)
|
|
}
|
|
|
|
var missing []string
|
|
if cfg.IOTPGDSN == "" {
|
|
missing = append(missing, "IOT_PG_DSN")
|
|
}
|
|
if cfg.SQSAccessKey == "" {
|
|
missing = append(missing, "SQS_ACCESS_KEY")
|
|
}
|
|
if cfg.SQSSecretKey == "" {
|
|
missing = append(missing, "SQS_SECRET_KEY")
|
|
}
|
|
if cfg.MQTTUsername == "" {
|
|
missing = append(missing, "MQTT_USERNAME")
|
|
}
|
|
if cfg.MQTTPassword == "" {
|
|
missing = append(missing, "MQTT_PASSWORD")
|
|
}
|
|
if len(missing) > 0 {
|
|
return nil, fmt.Errorf("required env vars not set: %s", strings.Join(missing, ", "))
|
|
}
|
|
|
|
return cfg, nil
|
|
}
|