feat: add server foundation (config, database, auth, main)

- config: Load from env vars (SERVER_PORT, DATABASE_URL, JWT_SECRET, CAS_DIR, etc.)
- database: pgx/v5 connection pool, models (User, YggdrasilSession, Modpack, GlobalFile, LauncherRelease)
- auth: Yggdrasil endpoints (authenticate, refresh, validate) with SHA-256 password hashing, token rotation
- main: graceful shutdown, HTTP server on configured port
- go.mod: module gitea.mrixs.me/Mrixs/MrixsCraft-server, pgx/v5 dependency

Co-Authored-By: OWL <noreply@anthropic.com>
This commit is contained in:
2026-05-26 13:03:21 +03:00
parent 551c75a232
commit aa7d3a8509
5 changed files with 506 additions and 13 deletions

View File

@@ -1,2 +1,62 @@
// package config handles server configuration (env vars, config files).
// package config handles server configuration from environment variables.
package config
import (
"fmt"
"os"
"strconv"
)
// Config holds all server configuration.
type Config struct {
// HTTP
Port int `json:"port"`
// Database
DatabaseURL string `json:"database_url"`
// Storage
CASDir string `json:"cas_dir"` // Content-Addressable Storage root
SkinsDir string `json:"skins_dir"` // Uploaded skins
// Auth
JWTSecret string `json:"jwt_secret"`
CIsecret string `json:"ci_secret"` // Token for CI/CD launcher release endpoint
// Public
BaseURL string `json:"base_url"` // External URL for CDN links
}
// Load reads configuration from environment variables with sensible defaults.
func Load() (*Config, error) {
port, err := strconv.Atoi(getEnv("SERVER_PORT", "8080"))
if err != nil {
return nil, fmt.Errorf("invalid SERVER_PORT: %w", err)
}
cfg := &Config{
Port: port,
DatabaseURL: getEnv("DATABASE_URL", ""),
CASDir: getEnv("CAS_DIR", "/var/www/cdn/files"),
SkinsDir: getEnv("SKINS_DIR", "/var/www/cdn/skins"),
JWTSecret: getEnv("JWT_SECRET", ""),
CIsecret: getEnv("CI_SECRET", ""),
BaseURL: getEnv("BASE_URL", "https://minecraft.mrixs.me"),
}
if cfg.DatabaseURL == "" {
return nil, fmt.Errorf("DATABASE_URL is required")
}
if cfg.JWTSecret == "" {
return nil, fmt.Errorf("JWT_SECRET is required")
}
return cfg, nil
}
func getEnv(key, fallback string) string {
if v := os.Getenv(key); v != "" {
return v
}
return fallback
}