all repos

onasty @ c3cd6686a990dcd8870c4f1db6073bb495b66842

a one-time notes service

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

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