Files
warpbox-dev/backend/libs/config/config.go
Daniel Legt 9b8ef16474 feat: initialize warpbox.dev project structure and backend
Initialize the repository with the core Go backend architecture and a frontend mockup for warpbox.dev, a self-hosted file-sharing application.

- Set up Go backend modules for configuration, HTTP server, middleware, handlers, and templates.
- Add local development scripts, environment templates, and basic project configuration.
- Include a React-based frontend mockup under the docs directory.
2026-05-25 15:36:49 +03:00

119 lines
2.9 KiB
Go

package config
import (
"fmt"
"math"
"os"
"path/filepath"
"strconv"
"strings"
"time"
)
type Config struct {
AppName string
Environment string
Addr string
BaseURL string
StaticDir string
TemplateDir string
ReadTimeout time.Duration
WriteTimeout time.Duration
IdleTimeout time.Duration
MaxUploadSize int64
}
func Load() (Config, error) {
cfg := Config{
AppName: envString("WARPBOX_APP_NAME", "warpbox.dev"),
Environment: envString("WARPBOX_ENV", "development"),
Addr: envString("WARPBOX_ADDR", ":8080"),
BaseURL: strings.TrimRight(envString("WARPBOX_BASE_URL", "http://localhost:8080"), "/"),
StaticDir: envString("WARPBOX_STATIC_DIR", defaultPath("static")),
TemplateDir: envString("WARPBOX_TEMPLATE_DIR", defaultPath("templates")),
ReadTimeout: envDuration("WARPBOX_READ_TIMEOUT", 15*time.Second),
WriteTimeout: envDuration("WARPBOX_WRITE_TIMEOUT", 60*time.Second),
IdleTimeout: envDuration("WARPBOX_IDLE_TIMEOUT", 120*time.Second),
MaxUploadSize: envMegabytes("WARPBOX_MAX_UPLOAD_SIZE_MB", 2048), // 2 GiB default.
}
if cfg.BaseURL == "" {
return Config{}, fmt.Errorf("WARPBOX_BASE_URL cannot be empty")
}
if cfg.MaxUploadSize <= 0 {
return Config{}, fmt.Errorf("WARPBOX_MAX_UPLOAD_SIZE_MB must be positive")
}
return cfg, nil
}
func defaultPath(name string) string {
candidates := []string{
filepath.Join("backend", name),
name,
}
for _, candidate := range candidates {
if info, err := os.Stat(candidate); err == nil && info.IsDir() {
return candidate
}
}
return filepath.Join("backend", name)
}
func envString(key, fallback string) string {
if value := strings.TrimSpace(os.Getenv(key)); value != "" {
return value
}
return fallback
}
func envDuration(key string, fallback time.Duration) time.Duration {
value := strings.TrimSpace(os.Getenv(key))
if value == "" {
return fallback
}
parsed, err := time.ParseDuration(value)
if err != nil {
return fallback
}
return parsed
}
func envMegabytes(key string, fallback float64) int64 {
value := strings.TrimSpace(os.Getenv(key))
if value == "" {
return megabytesToBytes(fallback)
}
parsed, err := parseMegabytes(value)
if err != nil {
return megabytesToBytes(fallback)
}
return parsed
}
func parseMegabytes(value string) (int64, error) {
normalized := strings.TrimSpace(value)
normalized = strings.TrimSuffix(normalized, "MB")
normalized = strings.TrimSuffix(normalized, "Mb")
normalized = strings.TrimSuffix(normalized, "mb")
normalized = strings.TrimSpace(normalized)
sizeMB, err := strconv.ParseFloat(normalized, 64)
if err != nil {
return 0, fmt.Errorf("invalid megabyte value %q: %w", value, err)
}
if sizeMB <= 0 {
return 0, fmt.Errorf("megabyte value must be positive")
}
return megabytesToBytes(sizeMB), nil
}
func megabytesToBytes(sizeMB float64) int64 {
return int64(math.Round(sizeMB * 1024 * 1024))
}