123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- package app
- import (
- "context"
- "fmt"
- "net/http"
- "os"
- "os/signal"
- "strconv"
- "syscall"
- "time"
- "git.linuxforward.com/byop/byop-engine/auth"
- "git.linuxforward.com/byop/byop-engine/cloud"
- "git.linuxforward.com/byop/byop-engine/config"
- "git.linuxforward.com/byop/byop-engine/dbmanager"
- "git.linuxforward.com/byop/byop-engine/handlers"
- mw "git.linuxforward.com/byop/byop-engine/middleware"
- "github.com/gin-gonic/gin"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- )
- type App struct {
- entry *logrus.Entry
- cnf *config.Config
- ctx context.Context
- cancelFunc context.CancelFunc
- rtr *gin.Engine
- // Database
- dbManager dbmanager.DbManager[dbmanager.Entity]
- dbFactory *dbmanager.DbManagerFactory
- // Services
- authService auth.Service
- tokenStore auth.TokenStore
- // Common Handlers
- authHandler *handlers.AuthHandler
- clientHandler *handlers.ClientHandler
- // Resource Handlers
- providerHandler *handlers.ProviderHandler
- deploymentHandler *handlers.DeploymentHandler
- templateHandler *handlers.TemplateHandler
- ticketHandler *handlers.TicketHandler
- monitoringHandler *handlers.MonitoringHandler
- }
- func NewApp(cnf *config.Config) (*App, error) {
- ctx, cancelFunc := context.WithCancel(context.Background())
- app := &App{
- entry: logrus.WithField("component", "app"),
- cnf: cnf,
- ctx: ctx,
- cancelFunc: cancelFunc,
- }
- // Initialize router first
- if cnf.Debug {
- gin.SetMode(gin.DebugMode)
- } else {
- // Set gin to release mode for production
- // This will disable debug logs and enable performance optimizations
- gin.SetMode(gin.ReleaseMode)
- }
- app.rtr = gin.New()
- app.rtr.Use(gin.Recovery())
- app.rtr.Use(mw.Logger)
- // Initialize database connection
- if err := app.initDatabase(); err != nil {
- return nil, errors.Wrap(err, "initialize database")
- }
- // Initialize services and handlers
- if err := app.initServices(); err != nil {
- return nil, errors.Wrap(err, "initialize services")
- }
- if err := app.initHandlers(); err != nil {
- return nil, errors.Wrap(err, "initialize handlers")
- }
- // Set up routes after all handlers are initialized
- app.setupRoutes()
- return app, nil
- }
- func (a *App) Run() error {
- srv := &http.Server{
- Addr: fmt.Sprintf(":%s", strconv.Itoa(a.cnf.Server.Port)),
- Handler: a.rtr,
- }
- go func() {
- a.entry.WithField("address", srv.Addr).Info("Starting server...")
- // Handle TLS if configured
- if a.cnf.Server.Tls.Enabled {
- a.entry.Info("Starting server with TLS...")
- err := srv.ListenAndServeTLS(a.cnf.Server.Tls.CertFile, a.cnf.Server.Tls.KeyFile)
- if err != nil && err != http.ErrServerClosed {
- a.entry.WithError(err).Fatal("Failed to start server")
- }
- } else {
- err := srv.ListenAndServe()
- if err != nil && err != http.ErrServerClosed {
- a.entry.WithError(err).Fatal("Failed to start server")
- }
- }
- a.entry.Info("Server stopped")
- }()
- quit := make(chan os.Signal, 1)
- signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
- <-quit
- a.entry.Info("Stopping server...")
- ctxTimeout, cancelFunc := context.WithTimeout(context.Background(), 30*time.Second)
- defer cancelFunc()
- err := srv.Shutdown(ctxTimeout)
- if err != nil {
- return fmt.Errorf("shutdown server: %w", err)
- }
- a.entry.Info("Server stopped successfully")
- return nil
- }
- func (a *App) initServices() error {
- // Initialize token store
- a.tokenStore = auth.NewMemoryTokenStore(time.Duration(a.cnf.Auth.CleanupInterval))
- // Initialize authentication service
- a.authService = auth.NewJWTService(
- []byte(a.cnf.Auth.PrivateKey),
- time.Duration(a.cnf.Auth.TokenDuration),
- a.tokenStore,
- )
- // Initialize providers
- if err := a.loadProviders(); err != nil {
- return errors.Wrap(err, "load providers")
- }
- a.entry.Info("Services initialized successfully")
- return nil
- }
- func (a *App) initHandlers() error {
- // Initialize authentication handler
- a.authHandler = handlers.NewAuthHandler(a.authService)
- // Initialize resource handlers
- a.providerHandler = handlers.NewProviderHandler()
- // Create managers for each entity type
- clientDbManager, err := a.dbFactory.CreateClientManager()
- if err != nil {
- return fmt.Errorf("create client db manager: %w", err)
- }
- if err := clientDbManager.Connect(); err != nil {
- return fmt.Errorf("connect to client database: %w", err)
- }
- a.clientHandler = handlers.NewClientHandler(clientDbManager)
- // Initialize other handlers...
- a.entry.Info("Handlers initialized successfully")
- return nil
- }
- func (a *App) loadProviders() error {
- for name, config := range a.cnf.Providers {
- provider, ok := cloud.GetProvider(name)
- if !ok {
- return fmt.Errorf("provider %s not found", name)
- }
- err := provider.Initialize(config)
- if err != nil {
- return fmt.Errorf("initialize provider %s: %w", name, err)
- }
- a.entry.WithField("provider", name).Info("Provider initialized")
- }
- a.entry.Info("All providers loaded successfully")
- return nil
- }
- func (a *App) setupRoutes() {
- // API version group
- v1 := a.rtr.Group("/api/v1")
- // Auth routes - no middleware required
- a.authHandler.RegisterRoutes(v1)
- // Protected routes - require authentication
- protected := v1.Group("/")
- protected.Use(mw.Auth(a.authService)) // Auth middleware with service dependency
- // Register resource routes
- providers := protected.Group("/providers")
- a.providerHandler.RegisterRoutes(providers)
- clients := protected.Group("/clients")
- a.clientHandler.RegisterRoutes(clients)
- // Register other resource routes...
- a.entry.Info("Routes configured successfully")
- }
- func (a *App) initDatabase() error {
- a.dbFactory = dbmanager.NewDbManagerFactory(a.cnf.Database.Type)
- a.entry.Info("Database factory initialized successfully")
- return nil
- }
|