all repos

onasty @ d74a3878064113aa2c096f346d96468bd51c4338

a one-time notes service

onasty/internal/config/config.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
feat(web): add oauth login (#213)..., 8 months ago
1
package config
2
3
import (
4
	"errors"
5
	"os"
6
	"strconv"
7
	"strings"
8
	"sync"
9
	"time"
10
)
11
12
var (
13
	instance *Config
14
	once     sync.Once
15
)
16
17
// Environment represents current app environment.
18
type Environment string
19
20
func (e Environment) IsDevMode() bool {
21
	return e == "debug" || e == "test"
22
}
23
24
type Config struct {
25
	AppEnv      Environment
26
	AppURL      string
27
	FrontendURL string
28
	NatsURL     string
29
30
	CORSAllowedOrigins []string
31
	CORSMaxAge         time.Duration
32
33
	HTTPPort            int
34
	HTTPWriteTimeout    time.Duration
35
	HTTPReadTimeout     time.Duration
36
	HTTPHeaderMaxSizeMb int
37
38
	PostgresDSN      string
39
	PasswordSalt     string
40
	NotePasswordSalt string
41
42
	RedisAddr     string
43
	RedisPassword string
44
	RedisDB       int
45
46
	CacheUsersTTL time.Duration
47
	CacheNoteTTL  time.Duration
48
49
	JwtSigningKey      string
50
	JwtAccessTokenTTL  time.Duration
51
	JwtRefreshTokenTTL time.Duration
52
53
	GoogleClientID    string
54
	GoogleSecret      string
55
	GoogleRedirectURL string
56
57
	GitHubClientID    string
58
	GitHubSecret      string
59
	GitHubRedirectURL string
60
61
	VerificationTokenTTL  time.Duration
62
	ResetPasswordTokenTTL time.Duration
63
	ChangeEmailTokenTTL   time.Duration
64
65
	MetricsEnabled bool
66
	MetricsPort    int
67
68
	LogLevel    string
69
	LogFormat   string
70
	LogShowLine bool
71
72
	RateLimiterRPS       int
73
	RateLimiterBurst     int
74
	RateLimiterTTL       time.Duration
75
	SlowRateLimiterRPS   int
76
	SlowRateLimiterBurst int
77
	SlowRateLimiterTTL   time.Duration
78
}
79
80
func NewConfig() *Config {
81
	once.Do(func() {
82
		instance = &Config{
83
			AppEnv:      Environment(getenvOrDefault("APP_ENV", "debug")),
84
			AppURL:      getenvOrDefault("APP_URL", ""),
85
			FrontendURL: getenvOrDefault("FRONTEND_URL", ""),
86
			NatsURL:     getenvOrDefault("NATS_URL", ""),
87
88
			CORSAllowedOrigins: strings.Split(getenvOrDefault("CORS_ALLOWED_ORIGINS", "*"), ","),
89
			CORSMaxAge:         mustParseDuration(getenvOrDefault("CORS_MAX_AGE", "12h")),
90
91
			HTTPPort:            mustGetenvOrDefaultInt("HTTP_PORT", 3000),
92
			HTTPWriteTimeout:    mustParseDuration(getenvOrDefault("HTTP_WRITE_TIMEOUT", "10s")),
93
			HTTPReadTimeout:     mustParseDuration(getenvOrDefault("HTTP_READ_TIMEOUT", "10s")),
94
			HTTPHeaderMaxSizeMb: mustGetenvOrDefaultInt("HTTP_HEADER_MAX_SIZE_MB", 1),
95
96
			PostgresDSN:      getenvOrDefault("POSTGRESQL_DSN", ""),
97
			PasswordSalt:     getenvOrDefault("PASSWORD_SALT", ""),
98
			NotePasswordSalt: getenvOrDefault("NOTE_PASSWORD_SALT", ""),
99
100
			RedisAddr:     getenvOrDefault("REDIS_ADDR", ""),
101
			RedisPassword: getenvOrDefault("REDIS_PASSWORD", ""),
102
			RedisDB:       mustGetenvOrDefaultInt(getenvOrDefault("REDIS_DB", "0"), 0),
103
104
			CacheUsersTTL: mustParseDuration(getenvOrDefault("CACHE_USERS_TTL", "1h")),
105
			CacheNoteTTL:  mustParseDuration(getenvOrDefault("CACHE_NOTE_TTL", "1h")),
106
107
			JwtSigningKey: getenvOrDefault("JWT_SIGNING_KEY", ""),
108
			JwtAccessTokenTTL: mustParseDuration(
109
				getenvOrDefault("JWT_ACCESS_TOKEN_TTL", "15m"),
110
			),
111
			JwtRefreshTokenTTL: mustParseDuration(
112
				getenvOrDefault("JWT_REFRESH_TOKEN_TTL", "24h"),
113
			),
114
115
			GoogleClientID:    getenvOrDefault("GOOGLE_CLIENTID", ""),
116
			GoogleSecret:      getenvOrDefault("GOOGLE_SECRET", ""),
117
			GoogleRedirectURL: getenvOrDefault("GOOGLE_REDIRECTURL", ""),
118
119
			GitHubClientID:    getenvOrDefault("GITHUB_CLIENTID", ""),
120
			GitHubSecret:      getenvOrDefault("GITHUB_SECRET", ""),
121
			GitHubRedirectURL: getenvOrDefault("GITHUB_REDIRECTURL", ""),
122
123
			VerificationTokenTTL: mustParseDuration(
124
				getenvOrDefault("VERIFICATION_TOKEN_TTL", "24h"),
125
			),
126
			ResetPasswordTokenTTL: mustParseDuration(
127
				getenvOrDefault("RESET_PASSWORD_TOKEN_TTL", "1h"),
128
			),
129
			ChangeEmailTokenTTL: mustParseDuration(
130
				getenvOrDefault("CHANGE_EMAIL_TOKEN_TTL", "24h"),
131
			),
132
133
			MetricsPort:    mustGetenvOrDefaultInt("METRICS_PORT", 3001),
134
			MetricsEnabled: getenvOrDefault("METRICS_ENABLED", "true") == "true",
135
136
			LogLevel:    getenvOrDefault("LOG_LEVEL", "debug"),
137
			LogFormat:   getenvOrDefault("LOG_FORMAT", "json"),
138
			LogShowLine: getenvOrDefault("LOG_SHOW_LINE", "true") == "true",
139
140
			RateLimiterRPS:       mustGetenvOrDefaultInt("RATELIMITER_RPS", 100),
141
			RateLimiterBurst:     mustGetenvOrDefaultInt("RATELIMITER_BURST", 10),
142
			RateLimiterTTL:       mustParseDuration(getenvOrDefault("RATELIMITER_TTL", "1m")),
143
			SlowRateLimiterRPS:   mustGetenvOrDefaultInt("SLOW_RATELIMITER_RPS", 2),
144
			SlowRateLimiterBurst: mustGetenvOrDefaultInt("SLOW_RATELIMITER_BURST", 2),
145
			SlowRateLimiterTTL:   mustParseDuration(getenvOrDefault("SLOW_RATELIMITER_TTL", "1m")),
146
		}
147
	})
148
	return instance
149
}
150
151
func getenvOrDefault(key, def string) string {
152
	if v, ok := os.LookupEnv(key); ok {
153
		return v
154
	}
155
	return def
156
}
157
158
func mustGetenvOrDefaultInt(key string, def int) int {
159
	if v, ok := os.LookupEnv(key); ok {
160
		r, err := strconv.Atoi(v)
161
		if err != nil {
162
			panic(err)
163
		}
164
		return r
165
	}
166
	return def
167
}
168
169
func mustParseDuration(dur string) time.Duration {
170
	d, err := time.ParseDuration(dur)
171
	if err != nil {
172
		panic(errors.Join(errors.New("cannot time.ParseDuration"), err)) //nolint:err113
173
	}
174
175
	return d
176
}