Files
sgmail-skill/internal/config/config.go
2026-06-06 22:28:36 +08:00

178 lines
4.3 KiB
Go

package config
import (
"bufio"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"time"
)
type Config struct {
AccountID string
POP3 POP3Config
SMTP SMTPConfig
Data DataConfig
HTTP HTTPConfig
}
type POP3Config struct {
Host string
Port int
Username string
Password string
UseTLS bool
TimeoutSeconds int
}
type SMTPConfig struct {
Host string
Port int
Username string
Password string
UseTLS bool
UseSTARTTLS bool
AuthRequired bool
AllowInsecureAuth bool
FromAddress string
FromName string
TimeoutSeconds int
}
type DataConfig struct {
DataDir string
DatabasePath string
RawMailDir string
AttachmentDir string
}
type HTTPConfig struct {
Host string
Port int
}
func (c POP3Config) Timeout() time.Duration {
return time.Duration(c.TimeoutSeconds) * time.Second
}
func (c SMTPConfig) Timeout() time.Duration {
return time.Duration(c.TimeoutSeconds) * time.Second
}
func Load(envPath string) (*Config, error) {
values := map[string]string{}
if envPath == "" {
envPath = ".env"
}
if err := readEnvFile(envPath, values); err != nil {
return nil, err
}
for _, item := range os.Environ() {
key, val, ok := strings.Cut(item, "=")
if ok {
values[key] = val
}
}
dataDir := getString(values, "DATA_DIR", "./data")
cfg := &Config{
AccountID: getString(values, "MAIL_ACCOUNT_ID", "default"),
POP3: POP3Config{
Host: getString(values, "POP3_HOST", ""),
Port: getInt(values, "POP3_PORT", 110),
Username: getString(values, "POP3_USERNAME", ""),
Password: getString(values, "POP3_PASSWORD", ""),
UseTLS: getBool(values, "POP3_USE_TLS", false),
TimeoutSeconds: getInt(values, "POP3_TIMEOUT_SECONDS", 30),
},
SMTP: SMTPConfig{
Host: getString(values, "SMTP_HOST", ""),
Port: getInt(values, "SMTP_PORT", 25),
Username: getString(values, "SMTP_USERNAME", ""),
Password: getString(values, "SMTP_PASSWORD", ""),
UseTLS: getBool(values, "SMTP_USE_TLS", false),
UseSTARTTLS: getBool(values, "SMTP_USE_STARTTLS", false),
AuthRequired: getBool(values, "SMTP_AUTH_REQUIRED", false),
AllowInsecureAuth: getBool(values, "SMTP_ALLOW_INSECURE_AUTH", false),
FromAddress: getString(values, "SMTP_FROM_ADDRESS", ""),
FromName: getString(values, "SMTP_FROM_NAME", ""),
TimeoutSeconds: getInt(values, "SMTP_TIMEOUT_SECONDS", 30),
},
Data: DataConfig{
DataDir: dataDir,
DatabasePath: getString(values, "DATABASE_PATH", filepath.Join(dataDir, "internal_mail.db")),
RawMailDir: getString(values, "RAW_MAIL_DIR", filepath.Join(dataDir, "raw")),
AttachmentDir: getString(values, "ATTACHMENT_DIR", filepath.Join(dataDir, "attachments")),
},
HTTP: HTTPConfig{
Host: getString(values, "HTTP_HOST", "127.0.0.1"),
Port: getInt(values, "HTTP_PORT", 8765),
},
}
return cfg, nil
}
func readEnvFile(path string, values map[string]string) error {
file, err := os.Open(path)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return fmt.Errorf("read env file: %w", err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" || strings.HasPrefix(line, "#") {
continue
}
key, value, ok := strings.Cut(line, "=")
if !ok {
continue
}
key = strings.TrimSpace(key)
value = strings.TrimSpace(value)
value = strings.Trim(value, `"'`)
values[key] = value
}
return scanner.Err()
}
func getString(values map[string]string, key, def string) string {
if v, ok := values[key]; ok {
return v
}
return def
}
func getInt(values map[string]string, key string, def int) int {
v, ok := values[key]
if !ok || strings.TrimSpace(v) == "" {
return def
}
n, err := strconv.Atoi(v)
if err != nil {
return def
}
return n
}
func getBool(values map[string]string, key string, def bool) bool {
v, ok := values[key]
if !ok || strings.TrimSpace(v) == "" {
return def
}
switch strings.ToLower(strings.TrimSpace(v)) {
case "1", "true", "yes", "y", "on":
return true
case "0", "false", "no", "n", "off":
return false
default:
return def
}
}