mirror of
https://github.com/dalbodeule/hop-gate.git
synced 2025-12-08 04:45:43 +09:00
build(deps): add ent and x libs dependencies
This commit is contained in:
252
internal/config/config.go
Normal file
252
internal/config/config.go
Normal file
@@ -0,0 +1,252 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// LoggingConfig 는 공통 로그 설정을 담습니다.
|
||||
// Loki push 에 필요한 엔드포인트/인증/정적 라벨 등을 포함합니다.
|
||||
type LoggingConfig struct {
|
||||
Level string // 예: "debug", "info", "warn", "error"
|
||||
Loki LokiConfig // Loki 관련 설정
|
||||
}
|
||||
|
||||
// LokiConfig 는 Loki HTTP push 설정을 담습니다.
|
||||
type LokiConfig struct {
|
||||
Enable bool // true 인 경우 Loki 로도 push
|
||||
Endpoint string // 예: "http://loki:3100/loki/api/v1/push"
|
||||
TenantID string // multi-tenant Loki 사용 시 X-Scope-OrgID 등에 사용
|
||||
Username string // basic auth 사용자명(선택)
|
||||
Password string // basic auth 비밀번호(선택)
|
||||
StaticLabels map[string]string // 모든 로그에 공통으로 붙일 라벨 (app=hop-gate,env=dev 등)
|
||||
}
|
||||
|
||||
// ServerConfig 는 서버 프로세스 설정을 담습니다.
|
||||
type ServerConfig struct {
|
||||
HTTPListen string // 예: ":80"
|
||||
HTTPSListen string // 예: ":443"
|
||||
DTLSListen string // 예: ":443"
|
||||
Domain string // 메인 도메인
|
||||
ProxyDomains []string // 프록시 서브도메인 또는 별도 도메인
|
||||
|
||||
Logging LoggingConfig // 서버용 로그 설정
|
||||
}
|
||||
|
||||
// ClientConfig 는 클라이언트 프로세스 설정을 담습니다.
|
||||
type ClientConfig struct {
|
||||
ServerAddr string // DTLS 서버 주소 (host:port)
|
||||
ClientID string // 클라이언트 식별자
|
||||
AuthToken string // 선택적 인증 토큰
|
||||
ServicePorts map[string]string // service name -> "127.0.0.1:PORT"
|
||||
|
||||
Logging LoggingConfig // 클라이언트용 로그 설정
|
||||
}
|
||||
|
||||
var (
|
||||
dotenvOnce sync.Once
|
||||
dotenvErr error
|
||||
)
|
||||
|
||||
// loadDotEnvOnce 는 현재 작업 디렉터리의 .env 파일을 한 번만 읽어서 os.Environ 에 주입합니다.
|
||||
// - KEY=VALUE, export KEY=VALUE 형식을 지원
|
||||
// - # 으로 시작하는 줄은 주석으로 간주합니다.
|
||||
func loadDotEnvOnce() {
|
||||
dotenvOnce.Do(func() {
|
||||
fi, err := os.Stat(".env")
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
// .env 가 없으면 조용히 무시
|
||||
return
|
||||
}
|
||||
dotenvErr = err
|
||||
return
|
||||
}
|
||||
if fi.IsDir() {
|
||||
// 디렉터리이면 무시
|
||||
return
|
||||
}
|
||||
|
||||
f, err := os.Open(".env")
|
||||
if err != nil {
|
||||
dotenvErr = err
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, "export ") {
|
||||
line = strings.TrimSpace(strings.TrimPrefix(line, "export "))
|
||||
}
|
||||
parts := strings.SplitN(line, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
key := strings.TrimSpace(parts[0])
|
||||
val := strings.TrimSpace(parts[1])
|
||||
// 양 끝의 작은/큰따옴표 제거
|
||||
val = strings.Trim(val, `"'`)
|
||||
|
||||
if key != "" {
|
||||
_ = os.Setenv(key, val)
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
dotenvErr = err
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func getEnvOrDefault(key, def string) string {
|
||||
if v := os.Getenv(key); v != "" {
|
||||
return v
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
func getEnvBool(key string, def bool) bool {
|
||||
v := strings.ToLower(strings.TrimSpace(os.Getenv(key)))
|
||||
if v == "" {
|
||||
return def
|
||||
}
|
||||
switch v {
|
||||
case "1", "true", "yes", "y", "on":
|
||||
return true
|
||||
case "0", "false", "no", "n", "off":
|
||||
return false
|
||||
default:
|
||||
return def
|
||||
}
|
||||
}
|
||||
|
||||
func parseCSVEnv(key string) []string {
|
||||
raw := os.Getenv(key)
|
||||
if raw == "" {
|
||||
return nil
|
||||
}
|
||||
parts := strings.Split(raw, ",")
|
||||
out := make([]string, 0, len(parts))
|
||||
for _, p := range parts {
|
||||
p = strings.TrimSpace(p)
|
||||
if p != "" {
|
||||
out = append(out, p)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// parseKeyValueCSV 는 "k1=v1,k2=v2" 형태의 문자열을 map 으로 변환합니다.
|
||||
func parseKeyValueCSV(raw string) map[string]string {
|
||||
if raw == "" {
|
||||
return nil
|
||||
}
|
||||
m := make(map[string]string)
|
||||
for _, part := range strings.Split(raw, ",") {
|
||||
part = strings.TrimSpace(part)
|
||||
if part == "" {
|
||||
continue
|
||||
}
|
||||
kv := strings.SplitN(part, "=", 2)
|
||||
if len(kv) != 2 {
|
||||
continue
|
||||
}
|
||||
k := strings.TrimSpace(kv[0])
|
||||
v := strings.TrimSpace(kv[1])
|
||||
if k != "" {
|
||||
m[k] = v
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// parseServicePortsEnv 는 "name1=127.0.0.1:8080,name2=127.0.0.1:9000" 형식을 파싱합니다.
|
||||
func parseServicePortsEnv(key string) map[string]string {
|
||||
raw := os.Getenv(key)
|
||||
return parseKeyValueCSV(raw)
|
||||
}
|
||||
|
||||
// loadLoggingFromEnv 는 공통 로그 설정을 .env/환경변수에서 읽어옵니다.
|
||||
func loadLoggingFromEnv() LoggingConfig {
|
||||
level := getEnvOrDefault("HOP_LOG_LEVEL", "info")
|
||||
|
||||
lokiEnable := getEnvBool("HOP_LOKI_ENABLE", false)
|
||||
lokiEndpoint := os.Getenv("HOP_LOKI_ENDPOINT")
|
||||
lokiTenantID := os.Getenv("HOP_LOKI_TENANT_ID")
|
||||
lokiUsername := os.Getenv("HOP_LOKI_USERNAME")
|
||||
lokiPassword := os.Getenv("HOP_LOKI_PASSWORD")
|
||||
lokiStaticLabels := parseKeyValueCSV(os.Getenv("HOP_LOKI_STATIC_LABELS"))
|
||||
|
||||
return LoggingConfig{
|
||||
Level: level,
|
||||
Loki: LokiConfig{
|
||||
Enable: lokiEnable,
|
||||
Endpoint: lokiEndpoint,
|
||||
TenantID: lokiTenantID,
|
||||
Username: lokiUsername,
|
||||
Password: lokiPassword,
|
||||
StaticLabels: lokiStaticLabels,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// LoadServerConfigFromEnv 는 .env 를 우선 읽고, 이후 환경 변수를 기반으로 서버 설정을 구성합니다.
|
||||
func LoadServerConfigFromEnv() (*ServerConfig, error) {
|
||||
loadDotEnvOnce()
|
||||
if dotenvErr != nil {
|
||||
return nil, dotenvErr
|
||||
}
|
||||
|
||||
cfg := &ServerConfig{
|
||||
HTTPListen: getEnvOrDefault("HOP_SERVER_HTTP_LISTEN", ":80"),
|
||||
HTTPSListen: getEnvOrDefault("HOP_SERVER_HTTPS_LISTEN", ":443"),
|
||||
DTLSListen: getEnvOrDefault("HOP_SERVER_DTLS_LISTEN", ":443"),
|
||||
Domain: os.Getenv("HOP_SERVER_DOMAIN"),
|
||||
ProxyDomains: parseCSVEnv("HOP_SERVER_PROXY_DOMAINS"),
|
||||
Logging: loadLoggingFromEnv(),
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// LoadClientConfigFromEnv 는 .env 를 우선 읽고, 이후 환경 변수를 기반으로 클라이언트 설정을 구성합니다.
|
||||
func LoadClientConfigFromEnv() (*ClientConfig, error) {
|
||||
loadDotEnvOnce()
|
||||
if dotenvErr != nil {
|
||||
return nil, dotenvErr
|
||||
}
|
||||
|
||||
cfg := &ClientConfig{
|
||||
ServerAddr: os.Getenv("HOP_CLIENT_SERVER_ADDR"),
|
||||
ClientID: os.Getenv("HOP_CLIENT_ID"),
|
||||
AuthToken: os.Getenv("HOP_CLIENT_AUTH_TOKEN"),
|
||||
ServicePorts: parseServicePortsEnv("HOP_CLIENT_SERVICE_PORTS"),
|
||||
Logging: loadLoggingFromEnv(),
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// Optional: 숫자 포트만 지정하고 싶을 경우를 위한 헬퍼 (예: "80" -> ":80").
|
||||
// 현재는 사용하지 않지만, 향후 유효성 검사/정규화에 사용할 수 있습니다.
|
||||
func normalizePort(p string, def string) string {
|
||||
p = strings.TrimSpace(p)
|
||||
if p == "" {
|
||||
return def
|
||||
}
|
||||
if strings.HasPrefix(p, ":") {
|
||||
return p
|
||||
}
|
||||
// 숫자로만 구성된 경우 ":" prefix 를 붙입니다.
|
||||
if _, err := strconv.Atoi(p); err == nil {
|
||||
return ":" + p
|
||||
}
|
||||
return p
|
||||
}
|
||||
Reference in New Issue
Block a user