Initial commit - SOGOMS v1.0.0
- sogoctl: supervisor avec health checks et restart auto - sogoway: gateway HTTP, auth JWT, routing par hostname - sogoms-db: microservice MariaDB avec pool par application - Protocol IPC Unix socket JSON length-prefixed - Config YAML multi-application (prokov) - Deploy script pour container Alpine gw3 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
182
internal/config/config.go
Normal file
182
internal/config/config.go
Normal file
@@ -0,0 +1,182 @@
|
||||
// Package config gère le chargement des configurations YAML.
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// AppConfig représente la configuration d'une application cliente.
|
||||
type AppConfig struct {
|
||||
App string `yaml:"app"`
|
||||
Version string `yaml:"version"`
|
||||
BasePath string `yaml:"base_path"`
|
||||
Hosts []string `yaml:"hosts"`
|
||||
Database Database `yaml:"database"`
|
||||
Auth Auth `yaml:"auth"`
|
||||
Routes []Route `yaml:"routes"`
|
||||
}
|
||||
|
||||
// Auth contient la configuration d'authentification.
|
||||
type Auth struct {
|
||||
JWTSecretFile string `yaml:"jwt_secret_file"`
|
||||
JWTExpiry string `yaml:"jwt_expiry"`
|
||||
jwtSecret string // Chargé depuis le fichier
|
||||
}
|
||||
|
||||
// JWTSecret retourne le secret JWT (chargé depuis le fichier).
|
||||
func (a *Auth) JWTSecret() string {
|
||||
return a.jwtSecret
|
||||
}
|
||||
|
||||
// Database contient la configuration de connexion à la base de données.
|
||||
type Database struct {
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
User string `yaml:"user"`
|
||||
PasswordFile string `yaml:"password_file"`
|
||||
Name string `yaml:"name"`
|
||||
password string // Chargé depuis le fichier
|
||||
}
|
||||
|
||||
// Password retourne le mot de passe (chargé depuis le fichier).
|
||||
func (d *Database) Password() string {
|
||||
return d.password
|
||||
}
|
||||
|
||||
// DSN retourne la chaîne de connexion MySQL/MariaDB.
|
||||
func (d *Database) DSN() string {
|
||||
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?parseTime=true&charset=utf8mb4",
|
||||
d.User, d.password, d.Host, d.Port, d.Name)
|
||||
}
|
||||
|
||||
// Route représente une route API.
|
||||
type Route struct {
|
||||
Path string `yaml:"path"`
|
||||
Method string `yaml:"method"`
|
||||
Scenario string `yaml:"scenario"`
|
||||
Auth *bool `yaml:"auth,omitempty"`
|
||||
}
|
||||
|
||||
// Registry stocke les configurations des applications.
|
||||
type Registry struct {
|
||||
configDir string
|
||||
apps map[string]*AppConfig // Par app_id
|
||||
byHost map[string]*AppConfig // Par hostname
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewRegistry crée un nouveau registre de configurations.
|
||||
func NewRegistry(configDir string) *Registry {
|
||||
return &Registry{
|
||||
configDir: configDir,
|
||||
apps: make(map[string]*AppConfig),
|
||||
byHost: make(map[string]*AppConfig),
|
||||
}
|
||||
}
|
||||
|
||||
// Load charge toutes les configurations depuis le répertoire routes.
|
||||
func (r *Registry) Load() error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
routesDir := filepath.Join(r.configDir, "routes")
|
||||
entries, err := os.ReadDir(routesDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read routes dir: %w", err)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".yaml") {
|
||||
continue
|
||||
}
|
||||
|
||||
path := filepath.Join(routesDir, entry.Name())
|
||||
cfg, err := r.loadAppConfig(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("load %s: %w", entry.Name(), err)
|
||||
}
|
||||
|
||||
r.apps[cfg.App] = cfg
|
||||
for _, host := range cfg.Hosts {
|
||||
r.byHost[host] = cfg
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadAppConfig charge une configuration d'application depuis un fichier YAML.
|
||||
func (r *Registry) loadAppConfig(path string) (*AppConfig, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var cfg AppConfig
|
||||
if err := yaml.Unmarshal(data, &cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Charger le mot de passe DB depuis le fichier
|
||||
if cfg.Database.PasswordFile != "" {
|
||||
passData, err := os.ReadFile(cfg.Database.PasswordFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read db password file: %w", err)
|
||||
}
|
||||
cfg.Database.password = strings.TrimSpace(string(passData))
|
||||
}
|
||||
|
||||
// Charger le secret JWT depuis le fichier
|
||||
if cfg.Auth.JWTSecretFile != "" {
|
||||
secretData, err := os.ReadFile(cfg.Auth.JWTSecretFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read jwt secret file: %w", err)
|
||||
}
|
||||
cfg.Auth.jwtSecret = strings.TrimSpace(string(secretData))
|
||||
}
|
||||
|
||||
// Port DB par défaut
|
||||
if cfg.Database.Port == 0 {
|
||||
cfg.Database.Port = 3306
|
||||
}
|
||||
|
||||
// Expiry JWT par défaut
|
||||
if cfg.Auth.JWTExpiry == "" {
|
||||
cfg.Auth.JWTExpiry = "24h"
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
// GetByApp retourne la configuration d'une application par son ID.
|
||||
func (r *Registry) GetByApp(appID string) (*AppConfig, bool) {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
cfg, ok := r.apps[appID]
|
||||
return cfg, ok
|
||||
}
|
||||
|
||||
// GetByHost retourne la configuration d'une application par son hostname.
|
||||
func (r *Registry) GetByHost(host string) (*AppConfig, bool) {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
cfg, ok := r.byHost[host]
|
||||
return cfg, ok
|
||||
}
|
||||
|
||||
// Apps retourne la liste des IDs d'applications chargées.
|
||||
func (r *Registry) Apps() []string {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
apps := make([]string, 0, len(r.apps))
|
||||
for app := range r.apps {
|
||||
apps = append(apps, app)
|
||||
}
|
||||
return apps
|
||||
}
|
||||
Reference in New Issue
Block a user