140 lines
3.2 KiB
Go
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
|
|
}
|