Files
geoip-rest/internal/userprogram/config.go
2025-12-10 11:53:48 +09:00

140 lines
3.2 KiB
Go

package userprogram
import (
"fmt"
"os"
"path/filepath"
"regexp"
"strconv"
"time"
)
const (
DefaultUpdateDir = "/update_data"
DefaultLogDir = "/log"
DefaultSchema = "public"
DefaultInitialCSV = "/initial_data/user_program_info_init_20251208.csv"
DefaultTable = "user_program_info"
DefaultDatabase = "user_program_info"
defaultTargetRange = "20060102"
)
type MySQLConfig struct {
Host string
Port int
User string
Password string
Database string
Table string
}
type Paths struct {
UpdateDir string
LogDir string
InitialCSV string
Schema string
}
func NewMySQLConfigFromEnv() (MySQLConfig, error) {
port, err := strconv.Atoi(env("USER_PROGRAM_INFO_PORT", "3306"))
if err != nil {
return MySQLConfig{}, fmt.Errorf("invalid USER_PROGRAM_INFO_PORT: %w", err)
}
host, err := envRequiredValue("USER_PROGRAM_INFO_HOST")
if err != nil {
return MySQLConfig{}, err
}
user, err := envRequiredValue("USER_PROGRAM_INFO_USERNAME")
if err != nil {
return MySQLConfig{}, err
}
password, err := envRequiredValue("USER_PROGRAM_INFO_PASSWORD")
if err != nil {
return MySQLConfig{}, err
}
cfg := MySQLConfig{
Host: host,
Port: port,
User: user,
Password: password,
Database: env("USER_PROGRAM_INFO_DB", DefaultDatabase),
Table: env("USER_PROGRAM_INFO_TABLE", DefaultTable),
}
if cfg.Host == "" || cfg.User == "" || cfg.Password == "" {
return MySQLConfig{}, fmt.Errorf("mysql connection envs are required")
}
return cfg, nil
}
func NewPathsFromEnv() (Paths, error) {
schema := env("USER_PROGRAM_INFO_SCHEMA", env("POSTGRES_SCHEMA", DefaultSchema))
paths := Paths{
UpdateDir: env("USER_PROGRAM_UPDATE_DIR", DefaultUpdateDir),
LogDir: env("USER_PROGRAM_IMPORT_LOG_DIR", DefaultLogDir),
InitialCSV: env("USER_PROGRAM_INFO_CSV", DefaultInitialCSV),
Schema: schema,
}
for _, dir := range []string{paths.UpdateDir, paths.LogDir} {
if dir == "" {
continue
}
if err := os.MkdirAll(dir, 0o755); err != nil {
return Paths{}, fmt.Errorf("create dir %s: %w", dir, err)
}
}
return paths, nil
}
func ParseTargetDate(raw string) (time.Time, error) {
if raw == "" {
return yesterdayKST(), nil
}
t, err := time.ParseInLocation("2006-01-02", raw, kst())
if err != nil {
return time.Time{}, fmt.Errorf("invalid date %q (expected YYYY-MM-DD)", raw)
}
return t, nil
}
func DateFromFilename(path string) (time.Time, error) {
base := filepath.Base(path)
re := regexp.MustCompile(`(\d{8})`)
match := re.FindStringSubmatch(base)
if len(match) < 2 {
return time.Time{}, fmt.Errorf("no date in filename: %s", base)
}
return time.ParseInLocation(defaultTargetRange, match[1], kst())
}
func yesterdayKST() time.Time {
now := time.Now().In(kst())
yesterday := now.AddDate(0, 0, -1)
return time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 0, 0, 0, 0, kst())
}
func kst() *time.Location {
loc, err := time.LoadLocation("Asia/Seoul")
if err != nil {
return time.FixedZone("KST", 9*60*60)
}
return loc
}
func env(key, fallback string) string {
if v := os.Getenv(key); v != "" {
return v
}
return fallback
}
func envRequiredValue(key string) (string, error) {
v := os.Getenv(key)
if v == "" {
return "", fmt.Errorf("%s is required", key)
}
return v, nil
}