initial commit
This commit is contained in:
6
config/azure_blob_storage.go
Normal file
6
config/azure_blob_storage.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package config
|
||||
|
||||
// AzureBlobStorageConfig holds configuration for Azure Blob Storage
|
||||
type AzureBlobStorageConfig struct {
|
||||
BlobEndpoint string `mapstructure:"blob_endpoint"` // e.g. https://account.blob.core.windows.net - base URL for asset/avatar URLs
|
||||
}
|
||||
8
config/azure_communication.go
Normal file
8
config/azure_communication.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package config
|
||||
|
||||
type AzureCommunicationConfig struct {
|
||||
Endpoint string
|
||||
AccessKey string
|
||||
ApiVersion string
|
||||
SenderAddress string
|
||||
}
|
||||
16
config/azure_service_bus.go
Normal file
16
config/azure_service_bus.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package config
|
||||
|
||||
// AzureServiceBusConfig holds configuration for Azure Service Bus
|
||||
type AzureServiceBusConfig struct {
|
||||
// ConnectionString is the Azure Service Bus connection string
|
||||
// If provided, this will be used for authentication
|
||||
ConnectionString string
|
||||
|
||||
// Namespace is the Azure Service Bus namespace
|
||||
// Required when using managed identity authentication
|
||||
Namespace string
|
||||
|
||||
// UseManagedIdentity determines whether to use managed identity for authentication
|
||||
// If true, managed identity will be used instead of connection string
|
||||
UseManagedIdentity bool
|
||||
}
|
||||
508
config/config.go
Normal file
508
config/config.go
Normal file
@@ -0,0 +1,508 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// AppConfig contains the application configuration
|
||||
type AppConfig struct {
|
||||
Env string
|
||||
|
||||
// Server configuration
|
||||
Port int
|
||||
|
||||
// Application configuration
|
||||
Name string
|
||||
Environment string
|
||||
VendorLockTimeOut int
|
||||
Database DatabaseConfig
|
||||
Redis RedisConfig
|
||||
Server ServerConfig
|
||||
RabbitMQ RabbitMQConfig
|
||||
Syslog SyslogConfig
|
||||
Metrics MetricsConfig
|
||||
AzureCommunicationConfig AzureCommunicationConfig
|
||||
AzureBlobStorage AzureBlobStorageConfig
|
||||
AzureServiceBus AzureServiceBusConfig
|
||||
PgDatabaseConfig PgDatabaseConfig
|
||||
JWT JWTConfig
|
||||
OAuth OAuthConfig
|
||||
}
|
||||
|
||||
// PrintConfig logs the current configuration
|
||||
func PrintConfig(logger zerolog.Logger, config *AppConfig) {
|
||||
logger.
|
||||
Info().
|
||||
Str("port", config.Server.WebPort).
|
||||
Str("name", config.Name).
|
||||
Str("environment", config.Environment).
|
||||
Msg("Application configuration")
|
||||
|
||||
}
|
||||
|
||||
// NewConfig creates a new configuration from environment variables or config file
|
||||
func NewConfig() (*AppConfig, error) {
|
||||
viper.SetConfigName("config")
|
||||
viper.SetConfigType("yaml")
|
||||
viper.AddConfigPath(".")
|
||||
viper.AddConfigPath("./config")
|
||||
|
||||
// Enable automatic environment variable binding
|
||||
viper.AutomaticEnv()
|
||||
|
||||
// Set environment variable prefix and replace dots with underscores
|
||||
viper.SetEnvPrefix("base")
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
|
||||
// Set defaults
|
||||
viper.SetDefault("environment", "local")
|
||||
viper.SetDefault("name", "base")
|
||||
viper.SetDefault("debug", true)
|
||||
viper.SetDefault("port", 8080)
|
||||
viper.SetDefault("vendor_lock_time_out", 5)
|
||||
|
||||
// Database defaults
|
||||
viper.SetDefault("database.host", "localhost")
|
||||
viper.SetDefault("database.port", "3306")
|
||||
viper.SetDefault("database.user", "base")
|
||||
viper.SetDefault("database.password", "base123")
|
||||
viper.SetDefault("database.name", "base")
|
||||
viper.SetDefault("database.max_idle_conns", 10)
|
||||
viper.SetDefault("database.max_open_conns", 20)
|
||||
viper.SetDefault("database.conn_max_idle_time", "2m")
|
||||
viper.SetDefault("database.conn_max_lifetime", "9m")
|
||||
viper.SetDefault("database.ro_user", "base")
|
||||
viper.SetDefault("database.ro_password", "base123")
|
||||
viper.SetDefault("database.ro_max_idle_conns", 10)
|
||||
viper.SetDefault("database.ro_max_open_conns", 20)
|
||||
|
||||
// PgDatabase defaults
|
||||
viper.SetDefault("pg_database.host", "localhost")
|
||||
viper.SetDefault("pg_database.port", 5430)
|
||||
viper.SetDefault("pg_database.user", "alinmeuser")
|
||||
viper.SetDefault("pg_database.password", "password")
|
||||
viper.SetDefault("pg_database.name", "alinmedb")
|
||||
viper.SetDefault("pg_database.ssl_mode", "disable")
|
||||
viper.SetDefault("pg_database.connection_timeout", 1*time.Minute)
|
||||
viper.SetDefault("pg_database.query_timeout", 60*time.Second)
|
||||
viper.SetDefault("pg_database.pool_config.max_conn", 20)
|
||||
viper.SetDefault("pg_database.pool_config.min_conn", 5)
|
||||
viper.SetDefault("pg_database.pool_config.max_conn_lifetime", 5*time.Minute)
|
||||
viper.SetDefault("pg_database.pool_config.max_conn_idle_time", 30*time.Minute)
|
||||
viper.SetDefault("pg_database.migrations.enabled", true)
|
||||
viper.SetDefault("pg_database.migrations.dir", "./database/migrations")
|
||||
|
||||
// Redis defaults
|
||||
viper.SetDefault("redis.host", "localhost")
|
||||
viper.SetDefault("redis.port", "6379")
|
||||
viper.SetDefault("redis.password", "")
|
||||
viper.SetDefault("redis.database", 0)
|
||||
viper.SetDefault("redis.url", "")
|
||||
|
||||
// Server defaults
|
||||
viper.SetDefault("server.host", "localhost")
|
||||
viper.SetDefault("server.port", "8080")
|
||||
viper.SetDefault("rpc.host", "0.0.0.0")
|
||||
viper.SetDefault("rpc.port", "8102")
|
||||
viper.SetDefault("web.host", "localhost")
|
||||
viper.SetDefault("web.port", "8101")
|
||||
viper.SetDefault("server.max_file_size_mb", 10) // Default 10MB file size limit
|
||||
viper.SetDefault("server.cleanup_queues", false) // Default to false for production safety
|
||||
|
||||
// JWT defaults
|
||||
viper.SetDefault("jwt.secret", "default-secret-key-change-in-production")
|
||||
viper.SetDefault("jwt.access_token_expiration", "24h")
|
||||
viper.SetDefault("jwt.refresh_token_expiration", "168h") // 7 days
|
||||
|
||||
// OAuth defaults
|
||||
viper.SetDefault("oauth.google.client_id", "")
|
||||
viper.SetDefault("oauth.google.client_secret", "")
|
||||
viper.SetDefault("oauth.google.redirect_url", "")
|
||||
viper.SetDefault("oauth.google.scopes", []string{"openid", "profile", "email"})
|
||||
viper.SetDefault("oauth.github.client_id", "")
|
||||
viper.SetDefault("oauth.github.client_secret", "")
|
||||
viper.SetDefault("oauth.github.redirect_url", "")
|
||||
viper.SetDefault("oauth.github.scopes", []string{"user:email"})
|
||||
viper.SetDefault("oauth.linkedin.client_id", "")
|
||||
viper.SetDefault("oauth.linkedin.client_secret", "")
|
||||
viper.SetDefault("oauth.linkedin.redirect_url", "")
|
||||
viper.SetDefault("oauth.linkedin.scopes", []string{"r_liteprofile", "r_emailaddress"})
|
||||
viper.SetDefault("oauth.mock.enabled", false)
|
||||
viper.SetDefault("oauth.mock.base_url", "http://localhost:9999")
|
||||
viper.SetDefault("oauth.mock.client_id", "mock-client")
|
||||
viper.SetDefault("oauth.mock.client_secret", "mock-secret")
|
||||
viper.SetDefault("oauth.mock.redirect_url", "http://localhost:3000/auth/callback")
|
||||
|
||||
// RabbitMQ defaults
|
||||
viper.SetDefault("rabbitmq.host", "localhost")
|
||||
viper.SetDefault("rabbitmq.port", "5678")
|
||||
viper.SetDefault("rabbitmq.user", "root")
|
||||
viper.SetDefault("rabbitmq.password", "root")
|
||||
viper.SetDefault("rabbitmq.vhost", "/")
|
||||
viper.SetDefault("rabbitmq.exchange", "base_exchange")
|
||||
viper.SetDefault("rabbitmq.internal_exchange", "base_internal_exchange")
|
||||
viper.SetDefault("rabbitmq.max_channels", "1")
|
||||
viper.SetDefault("rabbitmq.max_retry_attempts", 3)
|
||||
viper.SetDefault("rabbitmq.prefetch_count", 5)
|
||||
viper.SetDefault("rabbitmq.retry_ttl", "10s")
|
||||
|
||||
// BarcodeMapping defaults
|
||||
viper.SetDefault("barcodemapping.host", "localhost")
|
||||
viper.SetDefault("barcodemapping.port", "8081")
|
||||
viper.SetDefault("barcodemapping.cache", false)
|
||||
viper.SetDefault("barcodemapping.prefix", "barcodemapping")
|
||||
viper.SetDefault("barcodemapping.ttl", "5m")
|
||||
|
||||
// Discount defaults
|
||||
viper.SetDefault("discount.url", "http://localhost")
|
||||
viper.SetDefault("discount.port", 8082)
|
||||
viper.SetDefault("discount.cache", false)
|
||||
viper.SetDefault("discount.prefix", "discount")
|
||||
viper.SetDefault("discount.ttl", "30s")
|
||||
|
||||
// Syslog defaults
|
||||
viper.SetDefault("syslog.host", "localhost")
|
||||
viper.SetDefault("syslog.port", "1514")
|
||||
viper.SetDefault("syslog.protocol", "udp")
|
||||
viper.SetDefault("syslog.log_level", "INFO")
|
||||
|
||||
// Auth defaults
|
||||
viper.SetDefault("vendorauth.url", "")
|
||||
viper.SetDefault("vendorauth.client_id", "base")
|
||||
viper.SetDefault("vendorauth.client_secret", "")
|
||||
viper.SetDefault("vendorauth.cache", false)
|
||||
viper.SetDefault("vendorauth.prefix", "vendorauth")
|
||||
viper.SetDefault("vendorauth.ttl", "5m")
|
||||
|
||||
viper.SetDefault("authshield.url", "http://chart-shield.auth-shield.svc.cluster.local/auth-shield/authorize")
|
||||
viper.SetDefault("authshield.cache", false)
|
||||
viper.SetDefault("authshield.prefix", "authshield")
|
||||
viper.SetDefault("authshield.ttl", "5m")
|
||||
|
||||
// Metrics defaults
|
||||
viper.SetDefault("metrics.enabled", true)
|
||||
viper.SetDefault("metrics.service_name", "base")
|
||||
viper.SetDefault("metrics.path", "/metrics")
|
||||
viper.SetDefault("metrics.port", "8080")
|
||||
|
||||
// Bind environment variables explicitly for better control
|
||||
bindEnvVars()
|
||||
|
||||
// Try to read config file, but don't fail if it doesn't exist
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
var configFileNotFoundError viper.ConfigFileNotFoundError
|
||||
if errors.As(err, &configFileNotFoundError) {
|
||||
fmt.Println("Config file not found, using environment variables and defaults")
|
||||
} else {
|
||||
return nil, fmt.Errorf("failed to read config file: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
config := &AppConfig{
|
||||
Name: viper.GetString("name"),
|
||||
Environment: viper.GetString("environment"),
|
||||
Port: viper.GetInt("port"),
|
||||
VendorLockTimeOut: viper.GetInt("vendor_lock_time_out"),
|
||||
RabbitMQ: RabbitMQConfig{
|
||||
Host: viper.GetString("rabbitmq.host"),
|
||||
Port: viper.GetInt("rabbitmq.port"),
|
||||
User: viper.GetString("rabbitmq.user"),
|
||||
Password: viper.GetString("rabbitmq.password"),
|
||||
VHost: viper.GetString("rabbitmq.vhost"),
|
||||
MaxConnections: viper.GetInt("rabbitmq.max_connections"),
|
||||
MaxChannels: viper.GetInt("rabbitmq.max_channels"),
|
||||
ConnectionTimeout: viper.GetDuration("rabbitmq.connection_timeout"),
|
||||
HeartbeatInterval: viper.GetDuration("rabbitmq.heartbeat_interval"),
|
||||
ReconnectDelay: viper.GetDuration("rabbitmq.reconnect_delay"),
|
||||
MaxReconnectDelay: viper.GetDuration("rabbitmq.max_reconnect_delay"),
|
||||
ReconnectAttempts: viper.GetInt("rabbitmq.reconnect_attempts"),
|
||||
EnableAutoReconnect: viper.GetBool("rabbitmq.enable_auto_reconnect"),
|
||||
LogLevel: viper.GetString("rabbitmq.log_level"),
|
||||
MaxRetryAttempts: viper.GetInt("rabbitmq.max_retry_attempts"),
|
||||
PrefetchCount: viper.GetInt("rabbitmq.prefetch_count"),
|
||||
RetryTTL: viper.GetDuration("rabbitmq.retry_ttl"),
|
||||
},
|
||||
Database: DatabaseConfig{
|
||||
User: viper.GetString("database.user"),
|
||||
Password: viper.GetString("database.password"),
|
||||
Host: viper.GetString("database.host"),
|
||||
Port: viper.GetString("database.port"),
|
||||
Name: viper.GetString("database.name"),
|
||||
MaxIdleConns: viper.GetInt("database.max_idle_conns"),
|
||||
MaxOpenConns: viper.GetInt("database.max_open_conns"),
|
||||
ConnMaxIdleTime: viper.GetString("database.conn_max_idle_time"),
|
||||
ConnMaxLifetime: viper.GetString("database.conn_max_lifetime"),
|
||||
},
|
||||
Redis: RedisConfig{
|
||||
Host: viper.GetString("redis.host"),
|
||||
Port: viper.GetString("redis.port"),
|
||||
Password: viper.GetString("redis.password"),
|
||||
Database: viper.GetInt("redis.database"),
|
||||
URL: viper.GetString("redis.url"),
|
||||
},
|
||||
Server: ServerConfig{
|
||||
Domain: viper.GetString("server.host"),
|
||||
HTTPPort: viper.GetString("server.port"),
|
||||
GRPCPort: viper.GetString("server.port"),
|
||||
RPCHost: viper.GetString("rpc.host"),
|
||||
RPCPort: viper.GetString("rpc.port"),
|
||||
WebHost: viper.GetString("web.host"),
|
||||
WebPort: viper.GetString("web.port"),
|
||||
MaxFileSizeMB: viper.GetInt("server.max_file_size_mb"),
|
||||
CleanupQueues: viper.GetBool("server.cleanup_queues"),
|
||||
JWTSecret: viper.GetString("server.jwt_secret"),
|
||||
},
|
||||
Syslog: SyslogConfig{
|
||||
Host: viper.GetString("syslog.host"),
|
||||
Port: viper.GetString("syslog.port"),
|
||||
Protocol: viper.GetString("syslog.protocol"),
|
||||
LogLevel: viper.GetString("syslog.log_level"),
|
||||
},
|
||||
Metrics: MetricsConfig{
|
||||
Enabled: viper.GetBool("metrics.enabled"),
|
||||
ServiceName: viper.GetString("metrics.service_name"),
|
||||
Path: viper.GetString("metrics.path"),
|
||||
Port: viper.GetString("metrics.port"),
|
||||
},
|
||||
AzureCommunicationConfig: AzureCommunicationConfig{
|
||||
Endpoint: GetStringOrDefault("email.endpoint", ""),
|
||||
AccessKey: GetStringOrDefault("email.access_key", ""),
|
||||
ApiVersion: GetStringOrDefault("email.api_version", "2025-03-01"),
|
||||
SenderAddress: GetStringOrDefault("email.sender_address", "no-reply@alinme.com"),
|
||||
},
|
||||
AzureBlobStorage: AzureBlobStorageConfig{
|
||||
BlobEndpoint: GetStringOrDefault("azure_blob_storage.blob_endpoint", "https://alinmestorage.blob.core.windows.net"),
|
||||
},
|
||||
PgDatabaseConfig: PgDatabaseConfig{
|
||||
Host: viper.GetString("pg_database.host"),
|
||||
Port: viper.GetInt("pg_database.port"),
|
||||
User: viper.GetString("pg_database.user"),
|
||||
Password: viper.GetString("pg_database.password"),
|
||||
Name: viper.GetString("pg_database.name"),
|
||||
SSLMode: viper.GetString("pg_database.ssl_mode"),
|
||||
ConnectionTimeout: viper.GetDuration("pg_database.connection_timeout"),
|
||||
QueryTimeout: viper.GetDuration("pg_database.query_timeout"),
|
||||
PoolConfig: PgPoolConfig{
|
||||
MaxConn: viper.GetInt32("pg_database.pool_config.max_conn"),
|
||||
MinConn: viper.GetInt32("pg_database.pool_config.min_conn"),
|
||||
MaxConnLifetime: viper.GetDuration("pg_database.pool_config.max_conn_lifetime"),
|
||||
MaxConnIdleTime: viper.GetDuration("pg_database.pool_config.max_conn_idle_time"),
|
||||
},
|
||||
Migrations: MigrationsConfig{
|
||||
Enabled: viper.GetBool("pg_database.migrations.enabled"),
|
||||
Dir: viper.GetString("pg_database.migrations.dir"),
|
||||
},
|
||||
},
|
||||
JWT: func() JWTConfig {
|
||||
// Use jwt.secret if set, otherwise fall back to server.jwt_secret for backward compatibility
|
||||
secret := viper.GetString("jwt.secret")
|
||||
if secret == "" || secret == "default-secret-key-change-in-production" {
|
||||
if serverSecret := viper.GetString("server.jwt_secret"); serverSecret != "" {
|
||||
secret = serverSecret
|
||||
}
|
||||
}
|
||||
return JWTConfig{
|
||||
Secret: secret,
|
||||
AccessTokenExpiration: viper.GetDuration("jwt.access_token_expiration"),
|
||||
RefreshTokenExpiration: viper.GetDuration("jwt.refresh_token_expiration"),
|
||||
}
|
||||
}(),
|
||||
OAuth: OAuthConfig{
|
||||
Google: OAuthProviderConfig{
|
||||
ClientID: viper.GetString("oauth.google.client_id"),
|
||||
ClientSecret: viper.GetString("oauth.google.client_secret"),
|
||||
RedirectURL: viper.GetString("oauth.google.redirect_url"),
|
||||
Scopes: viper.GetStringSlice("oauth.google.scopes"),
|
||||
},
|
||||
GitHub: OAuthProviderConfig{
|
||||
ClientID: viper.GetString("oauth.github.client_id"),
|
||||
ClientSecret: viper.GetString("oauth.github.client_secret"),
|
||||
RedirectURL: viper.GetString("oauth.github.redirect_url"),
|
||||
Scopes: viper.GetStringSlice("oauth.github.scopes"),
|
||||
},
|
||||
LinkedIn: OAuthProviderConfig{
|
||||
ClientID: viper.GetString("oauth.linkedin.client_id"),
|
||||
ClientSecret: viper.GetString("oauth.linkedin.client_secret"),
|
||||
RedirectURL: viper.GetString("oauth.linkedin.redirect_url"),
|
||||
Scopes: viper.GetStringSlice("oauth.linkedin.scopes"),
|
||||
},
|
||||
Mock: OAuthMockConfig{
|
||||
Enabled: viper.GetBool("oauth.mock.enabled"),
|
||||
BaseURL: viper.GetString("oauth.mock.base_url"),
|
||||
OAuthProviderConfig: OAuthProviderConfig{
|
||||
ClientID: viper.GetString("oauth.mock.client_id"),
|
||||
ClientSecret: viper.GetString("oauth.mock.client_secret"),
|
||||
RedirectURL: viper.GetString("oauth.mock.redirect_url"),
|
||||
Scopes: viper.GetStringSlice("oauth.mock.scopes"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// bindEnvVars explicitly binds environment variables for better control
|
||||
func bindEnvVars() {
|
||||
// Application level
|
||||
BindEnv("environment", "base_ENVIRONMENT")
|
||||
BindEnv("name", "APP_NAME")
|
||||
BindEnv("debug", "base_DEBUG")
|
||||
BindEnv("port", "base_PORT")
|
||||
BindEnv("vendor_lock_time_out", "base_VENDOR_LOCK_TIMEOUT")
|
||||
|
||||
// Database
|
||||
BindEnv("database.host", "base_DB_HOST")
|
||||
BindEnv("database.port", "base_DB_PORT")
|
||||
BindEnv("database.user", "base_DB_USERNAME")
|
||||
BindEnv("database.password", "base_DB_PASSWORD")
|
||||
BindEnv("database.name", "base_DB_NAME")
|
||||
BindEnv("database.max_idle_conns", "base_DB_MAX_IDLE_CONNS")
|
||||
BindEnv("database.max_open_conns", "base_DB_MAX_OPEN_CONNS")
|
||||
BindEnv("database.conn_max_idle_time", "base_DB_CONN_MAX_IDLE_TIME")
|
||||
BindEnv("database.conn_max_lifetime", "base_DB_CONN_MAX_LIFETIME")
|
||||
BindEnv("database.ro_user", "base_DB_RO_USERNAME")
|
||||
BindEnv("database.ro_password", "base_DB_RO_PASSWORD")
|
||||
BindEnv("database.ro_max_idle_conns", "base_DB_RO_MAX_IDLE_CONNS")
|
||||
BindEnv("database.ro_max_open_conns", "base_DB_RO_MAX_OPEN_CONNS")
|
||||
|
||||
// Redis
|
||||
BindEnv("redis.host", "base_REDIS_HOST")
|
||||
BindEnv("redis.port", "base_REDIS_PORT")
|
||||
BindEnv("redis.password", "base_REDIS_PASSWORD")
|
||||
BindEnv("redis.database", "base_REDIS_DATABASE")
|
||||
BindEnv("redis.url", "base_REDIS_URL")
|
||||
|
||||
// Server
|
||||
BindEnv("server.host", "base_SERVER_HOST")
|
||||
BindEnv("server.port", "base_SERVER_PORT")
|
||||
BindEnv("rpc.host", "base_RPC_HOST")
|
||||
BindEnv("rpc.port", "base_RPC_PORT")
|
||||
BindEnv("web.host", "base_WEB_HOST")
|
||||
BindEnv("web.port", "base_WEB_PORT")
|
||||
BindEnv("server.max_file_size_mb", "base_SERVER_MAX_FILE_SIZE_MB")
|
||||
BindEnv("server.cleanup_queues", "base_SERVER_CLEANUP_QUEUES")
|
||||
BindEnv("server.jwt_secret", "base_SERVER_JWT_SECRET")
|
||||
|
||||
// JWT
|
||||
BindEnv("jwt.secret", "base_JWT_SECRET")
|
||||
BindEnv("jwt.access_token_expiration", "base_JWT_ACCESS_TOKEN_EXPIRATION")
|
||||
BindEnv("jwt.refresh_token_expiration", "base_JWT_REFRESH_TOKEN_EXPIRATION")
|
||||
|
||||
// OAuth
|
||||
BindEnv("oauth.google.client_id", "base_OAUTH_GOOGLE_CLIENT_ID")
|
||||
BindEnv("oauth.google.client_secret", "base_OAUTH_GOOGLE_CLIENT_SECRET")
|
||||
BindEnv("oauth.google.redirect_url", "base_OAUTH_GOOGLE_REDIRECT_URL")
|
||||
BindEnv("oauth.github.client_id", "base_OAUTH_GITHUB_CLIENT_ID")
|
||||
BindEnv("oauth.github.client_secret", "base_OAUTH_GITHUB_CLIENT_SECRET")
|
||||
BindEnv("oauth.github.redirect_url", "base_OAUTH_GITHUB_REDIRECT_URL")
|
||||
BindEnv("oauth.linkedin.client_id", "base_OAUTH_LINKEDIN_CLIENT_ID")
|
||||
BindEnv("oauth.linkedin.client_secret", "base_OAUTH_LINKEDIN_CLIENT_SECRET")
|
||||
BindEnv("oauth.linkedin.redirect_url", "base_OAUTH_LINKEDIN_REDIRECT_URL")
|
||||
BindEnv("oauth.mock.enabled", "base_OAUTH_MOCK_ENABLED")
|
||||
BindEnv("oauth.mock.base_url", "base_OAUTH_MOCK_BASE_URL")
|
||||
BindEnv("oauth.mock.client_id", "base_OAUTH_MOCK_CLIENT_ID")
|
||||
BindEnv("oauth.mock.client_secret", "base_OAUTH_MOCK_CLIENT_SECRET")
|
||||
BindEnv("oauth.mock.redirect_url", "base_OAUTH_MOCK_REDIRECT_URL")
|
||||
|
||||
// RabbitMQ
|
||||
BindEnv("rabbitmq.host", "base_RABBITMQ_HOST")
|
||||
BindEnv("rabbitmq.port", "base_RABBITMQ_PORT")
|
||||
BindEnv("rabbitmq.user", "base_RABBIT_USERNAME")
|
||||
BindEnv("rabbitmq.password", "base_RABBIT_PASSWORD")
|
||||
BindEnv("rabbitmq.vhost", "base_RABBITMQ_VHOST")
|
||||
BindEnv("rabbitmq.max_connections", "base_RABBITMQ_MAX_CONNECTIONS")
|
||||
BindEnv("rabbitmq.max_channels", "base_RABBITMQ_MAX_CHANNELS")
|
||||
BindEnv("rabbitmq.connection_timeout", "base_RABBITMQ_CONNECTION_TIMEOUT")
|
||||
BindEnv("rabbitmq.heartbeat_interval", "base_RABBITMQ_HEARTBEAT_INTERVAL")
|
||||
BindEnv("rabbitmq.reconnect_delay", "base_RABBITMQ_RECONNECT_DELAY")
|
||||
BindEnv("rabbitmq.max_reconnect_delay", "base_RABBITMQ_MAX_RECONNECT_DELAY")
|
||||
BindEnv("rabbitmq.reconnect_attempts", "base_RABBITMQ_RECONNECT_ATTEMPTS")
|
||||
BindEnv("rabbitmq.enable_auto_reconnect", "base_RABBITMQ_ENABLE_AUTO_RECONNECT")
|
||||
BindEnv("rabbitmq.log_level", "base_RABBITMQ_LOG_LEVEL")
|
||||
BindEnv("rabbitmq.max_retry_attempts", "base_RABBITMQ_MAX_RETRY_ATTEMPTS")
|
||||
BindEnv("rabbitmq.prefetch_count", "base_RABBITMQ_PREFETCH_COUNT")
|
||||
BindEnv("rabbitmq.retry_ttl", "base_RABBITMQ_RETRY_TTL")
|
||||
|
||||
// Azure Blob Storage
|
||||
BindEnv("azure_blob_storage.blob_endpoint", "base_AZURE_BLOB_STORAGE_BLOB_ENDPOINT")
|
||||
|
||||
// Azure Service Bus
|
||||
BindEnv("azure_service_bus.connection_string", "base_AZURE_SERVICE_BUS_CONNECTION_STRING")
|
||||
BindEnv("azure_service_bus.namespace", "base_AZURE_SERVICE_BUS_NAMESPACE")
|
||||
BindEnv("azure_service_bus.use_managed_identity", "base_AZURE_SERVICE_BUS_USE_MANAGED_IDENTITY")
|
||||
|
||||
// BarcodeMapping
|
||||
BindEnv("barcodemapping.host", "base_BARCODEMAPPING_HOST")
|
||||
BindEnv("barcodemapping.port", "base_BARCODEMAPPING_PORT")
|
||||
BindEnv("barcodemapping.cache", "base_BARCODEMAPPING_CACHE")
|
||||
BindEnv("barcodemapping.ttl", "base_BARCODEMAPPING_TTL")
|
||||
BindEnv("barcodemapping.prefix", "base_BARCODEMAPPING_PREFIX")
|
||||
|
||||
// Discount
|
||||
BindEnv("discount.url", "base_DISCOUNT_URL")
|
||||
BindEnv("discount.port", "base_DISCOUNT_PORT")
|
||||
BindEnv("discount.cache", "base_DISCOUNT_CACHE")
|
||||
BindEnv("discount.ttl", "base_DISCOUNT_TTL")
|
||||
BindEnv("discount.prefix", "base_DISCOUNT_PREFIX")
|
||||
|
||||
// Syslog
|
||||
BindEnv("syslog.host", "base_SYSLOG_HOST")
|
||||
BindEnv("syslog.port", "base_SYSLOG_PORT")
|
||||
BindEnv("syslog.protocol", "base_SYSLOG_PROTOCOL")
|
||||
BindEnv("syslog.log_level", "base_SYSLOG_LOG_LEVEL")
|
||||
|
||||
// Auth
|
||||
BindEnv("vendorauth.url", "base_VENDOR_AUTH_URL")
|
||||
BindEnv("vendorauth.client_id", "base_VENDOR_AUTH_CLIENT_ID")
|
||||
BindEnv("vendorauth.client_secret", "base_VENDOR_AUTH_SECRET")
|
||||
BindEnv("vendorauth.cache", "base_VENDOR_AUTH_CACHE")
|
||||
BindEnv("vendorauth.prefix", "base_VENDOR_AUTH_PREFIX")
|
||||
BindEnv("vendorauth.ttl", "base_VENDOR_AUTH_TTL")
|
||||
|
||||
BindEnv("authshield.url", "base_AUTH_SHIELD_URL")
|
||||
BindEnv("authshield.cache", "base_AUTH_SHIELD_CACHE")
|
||||
BindEnv("authshield.prefix", "base_AUTH_SHIELD_PREFIX")
|
||||
BindEnv("authshield.ttl", "base_AUTH_SHIELD_TTL")
|
||||
|
||||
// Metrics
|
||||
BindEnv("metrics.enabled", "base_METRICS_ENABLED")
|
||||
BindEnv("metrics.service_name", "base_METRICS_SERVICE_NAME")
|
||||
BindEnv("metrics.path", "base_METRICS_PATH")
|
||||
BindEnv("metrics.port", "base_METRICS_PORT")
|
||||
|
||||
// PgDatabase
|
||||
BindEnv("pg_database.host", "base_PG_DATABASE_HOST")
|
||||
BindEnv("pg_database.port", "base_PG_DATABASE_PORT")
|
||||
BindEnv("pg_database.user", "base_PG_DATABASE_USER")
|
||||
BindEnv("pg_database.password", "base_PG_DATABASE_PASSWORD")
|
||||
BindEnv("pg_database.name", "base_PG_DATABASE_NAME")
|
||||
BindEnv("pg_database.ssl_mode", "base_PG_DATABASE_SSL_MODE")
|
||||
BindEnv("pg_database.connection_timeout", "base_PG_DATABASE_CONNECTION_TIMEOUT")
|
||||
BindEnv("pg_database.query_timeout", "base_PG_DATABASE_QUERY_TIMEOUT")
|
||||
BindEnv("pg_database.pool_config.max_conn", "base_PG_DATABASE_POOL_CONFIG_MAX_CONN")
|
||||
BindEnv("pg_database.pool_config.min_conn", "base_PG_DATABASE_POOL_CONFIG_MIN_CONN")
|
||||
BindEnv("pg_database.pool_config.max_conn_lifetime", "base_PG_DATABASE_POOL_CONFIG_MAX_CONN_LIFETIME")
|
||||
BindEnv("pg_database.pool_config.max_conn_idle_time", "base_PG_DATABASE_POOL_CONFIG_MAX_CONN_IDLE_TIME")
|
||||
BindEnv("pg_database.migrations.enabled", "base_PG_DATABASE_MIGRATIONS_ENABLED")
|
||||
BindEnv("pg_database.migrations.dir", "base_PG_DATABASE_MIGRATIONS_DIR")
|
||||
}
|
||||
|
||||
func BindEnv(input, envKey string) {
|
||||
if err := viper.BindEnv(input, envKey); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func GetStringOrDefault(key string, defaultValue string) string {
|
||||
if viper.IsSet(key) {
|
||||
return viper.GetString(key)
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
40
config/database.go
Normal file
40
config/database.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package config
|
||||
|
||||
import "time"
|
||||
|
||||
// DatabaseConfig holds configuration for database
|
||||
type DatabaseConfig struct {
|
||||
User string
|
||||
Password string
|
||||
Host string
|
||||
Port string
|
||||
Name string
|
||||
MaxIdleConns int
|
||||
MaxOpenConns int
|
||||
ConnMaxIdleTime string
|
||||
ConnMaxLifetime string
|
||||
}
|
||||
|
||||
type PgDatabaseConfig struct {
|
||||
Host string
|
||||
Port int
|
||||
User string
|
||||
Password string
|
||||
Name string
|
||||
SSLMode string
|
||||
ConnectionTimeout time.Duration
|
||||
QueryTimeout time.Duration
|
||||
PoolConfig PgPoolConfig
|
||||
Migrations MigrationsConfig
|
||||
}
|
||||
|
||||
type MigrationsConfig struct {
|
||||
Enabled bool
|
||||
Dir string
|
||||
}
|
||||
type PgPoolConfig struct {
|
||||
MaxConn int32
|
||||
MinConn int32
|
||||
MaxConnLifetime time.Duration
|
||||
MaxConnIdleTime time.Duration
|
||||
}
|
||||
7
config/env.go
Normal file
7
config/env.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package config
|
||||
|
||||
const (
|
||||
Local = "local"
|
||||
Prod = "prod"
|
||||
Stage = "stage"
|
||||
)
|
||||
10
config/jwt.go
Normal file
10
config/jwt.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package config
|
||||
|
||||
import "time"
|
||||
|
||||
// JWTConfig holds configuration for JWT token service
|
||||
type JWTConfig struct {
|
||||
Secret string `mapstructure:"secret"` // JWT secret key for token signing
|
||||
AccessTokenExpiration time.Duration `mapstructure:"access_token_expiration"` // Access token expiration duration
|
||||
RefreshTokenExpiration time.Duration `mapstructure:"refresh_token_expiration"` // Refresh token expiration duration
|
||||
}
|
||||
9
config/metrics.go
Normal file
9
config/metrics.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package config
|
||||
|
||||
// MetricsConfig holds configuration for metrics
|
||||
type MetricsConfig struct {
|
||||
Enabled bool
|
||||
ServiceName string
|
||||
Path string
|
||||
Port string
|
||||
}
|
||||
24
config/oauth.go
Normal file
24
config/oauth.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package config
|
||||
|
||||
// OAuthConfig holds configuration for OAuth providers
|
||||
type OAuthConfig struct {
|
||||
Google OAuthProviderConfig `mapstructure:"google"`
|
||||
GitHub OAuthProviderConfig `mapstructure:"github"`
|
||||
LinkedIn OAuthProviderConfig `mapstructure:"linkedin"`
|
||||
Mock OAuthMockConfig `mapstructure:"mock"`
|
||||
}
|
||||
|
||||
// OAuthMockConfig holds configuration for the mock OAuth server (local dev only)
|
||||
type OAuthMockConfig struct {
|
||||
Enabled bool `mapstructure:"enabled"`
|
||||
BaseURL string `mapstructure:"base_url"` // e.g. http://localhost:9999
|
||||
OAuthProviderConfig
|
||||
}
|
||||
|
||||
// OAuthProviderConfig holds configuration for a single OAuth provider
|
||||
type OAuthProviderConfig struct {
|
||||
ClientID string `mapstructure:"client_id"`
|
||||
ClientSecret string `mapstructure:"client_secret"` // Ov23liSo5eCfXJ11k7mr
|
||||
RedirectURL string `mapstructure:"redirect_url"`
|
||||
Scopes []string `mapstructure:"scopes"`
|
||||
}
|
||||
38
config/rabbit.go
Normal file
38
config/rabbit.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// RabbitMQConfig holds configuration for RabbitMQ
|
||||
type RabbitMQConfig struct {
|
||||
Host string
|
||||
Port int
|
||||
User string
|
||||
Password string
|
||||
VHost string
|
||||
MaxConnections int
|
||||
MaxChannels int
|
||||
ConnectionTimeout time.Duration
|
||||
HeartbeatInterval time.Duration
|
||||
ReconnectDelay time.Duration
|
||||
MaxReconnectDelay time.Duration
|
||||
ReconnectAttempts int
|
||||
EnableAutoReconnect bool
|
||||
LogLevel string
|
||||
MaxRetryAttempts int
|
||||
PrefetchCount int
|
||||
RetryTTL time.Duration
|
||||
}
|
||||
|
||||
// RabbitMQConnectionString returns the formatted RabbitMQ connection URI
|
||||
func (c *AppConfig) RabbitMQConnectionString() string {
|
||||
return fmt.Sprintf("amqp://%s:%s@%s:%d/%s",
|
||||
c.RabbitMQ.User,
|
||||
c.RabbitMQ.Password,
|
||||
c.RabbitMQ.Host,
|
||||
c.RabbitMQ.Port,
|
||||
c.RabbitMQ.VHost,
|
||||
)
|
||||
}
|
||||
10
config/redis.go
Normal file
10
config/redis.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package config
|
||||
|
||||
// RedisConfig holds configuration for Redis
|
||||
type RedisConfig struct {
|
||||
Host string
|
||||
Port string
|
||||
Password string
|
||||
Database int
|
||||
URL string
|
||||
}
|
||||
25
config/server.go
Normal file
25
config/server.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package config
|
||||
|
||||
// ServerConfig holds configuration for HTTP server
|
||||
type ServerConfig struct {
|
||||
Domain string `mapstructure:"domain"`
|
||||
HTTPPort string `mapstructure:"http_port"`
|
||||
GRPCPort string `mapstructure:"grpc_port"`
|
||||
RPCHost string `mapstructure:"rpc_host"`
|
||||
RPCPort string `mapstructure:"rpc_port"`
|
||||
WebHost string `mapstructure:"web_host"`
|
||||
WebPort string `mapstructure:"web_port"`
|
||||
MaxFileSize int64 `mapstructure:"max_file_size"` // Maximum file size in bytes
|
||||
MaxFileSizeMB int `mapstructure:"max_file_size_mb"` // Maximum file size in MB (for convenience)
|
||||
CleanupQueues bool `mapstructure:"cleanup_queues"` // Whether to cleanup existing queues on startup
|
||||
JWTSecret string `mapstructure:"jwt_secret"` // JWT secret key for token signing
|
||||
}
|
||||
|
||||
// GetMaxFileSizeBytes returns the maximum file size in bytes
|
||||
func (s *ServerConfig) GetMaxFileSizeBytes() int64 {
|
||||
if s.MaxFileSize > 0 {
|
||||
return s.MaxFileSize
|
||||
}
|
||||
// Convert MB to bytes if MaxFileSize is not set
|
||||
return int64(s.MaxFileSizeMB) * 1024 * 1024
|
||||
}
|
||||
8
config/syslog.go
Normal file
8
config/syslog.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package config
|
||||
|
||||
type SyslogConfig struct {
|
||||
Host string
|
||||
Port string
|
||||
Protocol string
|
||||
LogLevel string
|
||||
}
|
||||
Reference in New Issue
Block a user