initiate repo

This commit is contained in:
renaldybrada
2026-01-27 11:41:51 +07:00
commit ccf12a95b1
33 changed files with 8209 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
package config
import (
"log"
"os"
"strings"
"github.com/joho/godotenv"
)
func LoadConfig() *Config {
errLoadEnv := godotenv.Load()
if errLoadEnv != nil {
log.Println("error loading .env")
}
config := &Config{
Server: ServerConfig{
Port: getEnvAsInt("PORT", 8080),
Mode: getEnv("GIN_MODE", "debug"),
},
Databases: make(map[string]DatabaseConfig),
}
config.loadCustomDatabaseConfigs()
return config
}
func (c *Config) loadCustomDatabaseConfigs() {
envVars := os.Environ()
dbConfigs := make(map[string]map[string]string)
// Parse database configurations from environment variables
for _, envVar := range envVars {
parts := strings.SplitN(envVar, "=", 2)
if len(parts) != 2 {
continue
}
key := parts[0]
value := parts[1]
// Parse specific database configurations
if strings.HasSuffix(key, "_CONNECTION") || strings.HasSuffix(key, "_HOST") ||
strings.HasSuffix(key, "_DATABASE") || strings.HasSuffix(key, "_USERNAME") ||
strings.HasSuffix(key, "_PASSWORD") || strings.HasSuffix(key, "_PORT") ||
strings.HasSuffix(key, "_NAME") {
segments := strings.Split(key, "_")
if len(segments) >= 2 {
dbName := strings.ToLower(strings.Join(segments[:len(segments)-1], "_"))
property := strings.ToLower(segments[len(segments)-1])
if dbConfigs[dbName] == nil {
dbConfigs[dbName] = make(map[string]string)
}
dbConfigs[dbName][property] = value
}
}
}
// Create DatabaseConfig from parsed configurations for additional databases
for name, config := range dbConfigs {
// Skip empty configurations or system configurations
if name == "" || strings.Contains(name, "chrome_crashpad_pipe") || name == "primary" {
continue
}
dbType := getEnvFromMap(config, "connection", getEnvFromMap(config, "type", "postgres"))
// Skip if username is empty and it's not a system config
username := getEnvFromMap(config, "username", "")
if username == "" && !strings.HasPrefix(name, "chrome") {
continue
}
dbConfig := DatabaseConfig{
Name: name,
Type: dbType,
Host: getEnvFromMap(config, "host", "localhost"),
Port: getEnvAsIntFromMap(config, "port", getDefaultPort(dbType)),
Username: username,
Password: getEnvFromMap(config, "password", ""),
Database: getEnvFromMap(config, "database", getEnvFromMap(config, "name", name)),
Schema: getEnvFromMap(config, "schema", getDefaultSchema(dbType)),
SSLMode: getEnvFromMap(config, "sslmode", getDefaultSSLMode(dbType)),
Path: getEnvFromMap(config, "path", ""),
Options: getEnvFromMap(config, "options", ""),
MaxOpenConns: getEnvAsIntFromMap(config, "max_open_conns", getDefaultMaxOpenConns(dbType)),
MaxIdleConns: getEnvAsIntFromMap(config, "max_idle_conns", getDefaultMaxIdleConns(dbType)),
ConnMaxLifetime: parseDuration(getEnvFromMap(config, "conn_max_lifetime", getDefaultConnMaxLifetime(dbType))),
// Security settings
RequireSSL: getEnvAsBoolFromMap(config, "require_ssl", false),
SSLRootCert: getEnvFromMap(config, "ssl_root_cert", ""),
SSLCert: getEnvFromMap(config, "ssl_cert", ""),
SSLKey: getEnvFromMap(config, "ssl_key", ""),
Timeout: parseDuration(getEnvFromMap(config, "timeout", "30s")),
ConnectTimeout: parseDuration(getEnvFromMap(config, "connect_timeout", "10s")),
ReadTimeout: parseDuration(getEnvFromMap(config, "read_timeout", "30s")),
WriteTimeout: parseDuration(getEnvFromMap(config, "write_timeout", "30s")),
StatementTimeout: parseDuration(getEnvFromMap(config, "statement_timeout", "360s")),
// Connection pool settings
MaxLifetime: parseDuration(getEnvFromMap(config, "max_lifetime", "1h")),
MaxIdleTime: parseDuration(getEnvFromMap(config, "max_idle_time", "5m")),
HealthCheckPeriod: parseDuration(getEnvFromMap(config, "health_check_period", "1m")),
}
c.Databases[name] = dbConfig
}
}
+157
View File
@@ -0,0 +1,157 @@
package config
import (
"os"
"strconv"
"time"
)
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
func getEnvAsInt(key string, defaultValue int) int {
valueStr := getEnv(key, "")
if value, err := strconv.Atoi(valueStr); err == nil {
return value
}
return defaultValue
}
func getEnvFromMap(config map[string]string, key, defaultValue string) string {
if value, exists := config[key]; exists {
return value
}
return defaultValue
}
func getEnvAsIntFromMap(config map[string]string, key string, defaultValue int) int {
if value, exists := config[key]; exists {
if intValue, err := strconv.Atoi(value); err == nil {
return intValue
}
}
return defaultValue
}
func getEnvAsBoolFromMap(config map[string]string, key string, defaultValue bool) bool {
if value, exists := config[key]; exists {
if boolValue, err := strconv.ParseBool(value); err == nil {
return boolValue
}
}
return defaultValue
}
// Helper functions for getting default values based on database type
func getDefaultPort(dbType string) int {
switch dbType {
case "postgres":
return 5432
case "mysql":
return 3306
case "sqlserver":
return 1433
case "mongodb":
return 27017
case "sqlite":
return 0 // SQLite doesn't use port
default:
return 5432
}
}
func getDefaultSchema(dbType string) string {
switch dbType {
case "postgres":
return "public"
case "mysql":
return ""
case "sqlserver":
return "dbo"
case "mongodb":
return ""
case "sqlite":
return ""
default:
return "public"
}
}
func getDefaultSSLMode(dbType string) string {
switch dbType {
case "postgres":
return "disable"
case "mysql":
return "false"
case "sqlserver":
return "false"
case "mongodb":
return "false"
case "sqlite":
return ""
default:
return "disable"
}
}
func getDefaultMaxOpenConns(dbType string) int {
switch dbType {
case "postgres":
return 25
case "mysql":
return 25
case "sqlserver":
return 25
case "mongodb":
return 100
case "sqlite":
return 1 // SQLite only supports one writer at a time
default:
return 25
}
}
func getDefaultMaxIdleConns(dbType string) int {
switch dbType {
case "postgres":
return 25
case "mysql":
return 25
case "sqlserver":
return 25
case "mongodb":
return 10
case "sqlite":
return 1 // SQLite only supports one writer at a time
default:
return 25
}
}
func getDefaultConnMaxLifetime(dbType string) string {
switch dbType {
case "postgres":
return "5m"
case "mysql":
return "5m"
case "sqlserver":
return "5m"
case "mongodb":
return "30m"
case "sqlite":
return "5m"
default:
return "5m"
}
}
func parseDuration(durationStr string) time.Duration {
if duration, err := time.ParseDuration(durationStr); err == nil {
return duration
}
return 5 * time.Minute
}
+45
View File
@@ -0,0 +1,45 @@
package config
import "time"
type Config struct {
Server ServerConfig
Databases map[string]DatabaseConfig
ReadReplicas map[string][]DatabaseConfig
}
type ServerConfig struct {
Port int
Mode string
}
type DatabaseConfig struct {
Name string
Type string // postgres, mysql, sqlserver, sqlite, mongodb
Host string
Port int
Username string
Password string
Database string
Schema string
SSLMode string
Path string // For SQLite
Options string // Additional connection options
MaxOpenConns int // Max open connections
MaxIdleConns int // Max idle connections
ConnMaxLifetime time.Duration // Connection max lifetime
// Security settings
RequireSSL bool // Require SSL connection
SSLRootCert string // Path to SSL root certificate
SSLCert string // Path to SSL client certificate
SSLKey string // Path to SSL client key
Timeout time.Duration // Connection timeout
ConnectTimeout time.Duration // Connect timeout
ReadTimeout time.Duration // Read timeout
WriteTimeout time.Duration // Write timeout
StatementTimeout time.Duration // Statement timeout for PostgreSQL
// Connection pool settings
MaxLifetime time.Duration // Maximum amount of time a connection may be reused
MaxIdleTime time.Duration // Maximum amount of time a connection may be idle
HealthCheckPeriod time.Duration // Health check period
}