feat(startup): wire runner, engine, and scheduler into foreground mode
Derives a 32-byte AES key from the configured secret via SHA-256, constructs the ConnectionService, Runner, and Engine, and starts the Scheduler so enabled rules fire automatically. Injects the shared services into the HTTP server via a new Dependencies struct so API handlers can reuse them.
This commit is contained in:
@@ -3,15 +3,22 @@ package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/config"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/crypto"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/db"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/logging"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/repository"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/rules/engine"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/rules/runner"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/scheduler"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/server"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/services"
|
||||
)
|
||||
|
||||
// RunInit initializes the application: validates config, initializes DB, runs migrations
|
||||
@@ -62,13 +69,39 @@ func RunForeground() error {
|
||||
return fmt.Errorf("running migrations: %w", err)
|
||||
}
|
||||
|
||||
// Create and start server
|
||||
srv := server.New(cfg, database, logger)
|
||||
// Derive a 32-byte AES key from the configured secret key
|
||||
keyHash := sha256.Sum256(cfg.SecretKey)
|
||||
encryptor, err := crypto.NewEncryptor(keyHash[:])
|
||||
if err != nil {
|
||||
return fmt.Errorf("initializing encryptor: %w", err)
|
||||
}
|
||||
|
||||
// Build services, repositories, and the execution pipeline
|
||||
connService := services.NewConnectionService(database.Conn(), encryptor, logger)
|
||||
ruleRunner := runner.New(database.Conn(), connService, logger)
|
||||
deps := server.Dependencies{
|
||||
Runner: ruleRunner,
|
||||
Engine: engine.NewEngine(logger),
|
||||
ConnService: connService,
|
||||
RuleRepo: repository.NewRuleRepository(database.Conn()),
|
||||
ConnRepo: repository.NewConnectionRepository(database.Conn()),
|
||||
RunRepo: repository.NewRuleRunRepository(database.Conn()),
|
||||
}
|
||||
|
||||
// Setup graceful shutdown
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// Start the scheduler so enabled rules fire automatically
|
||||
sched := scheduler.New(database.Conn(), ruleRunner, logger)
|
||||
if err := sched.Start(ctx); err != nil {
|
||||
return fmt.Errorf("starting scheduler: %w", err)
|
||||
}
|
||||
defer sched.Stop()
|
||||
|
||||
// Create HTTP server
|
||||
srv := server.New(cfg, database, deps, logger)
|
||||
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
|
||||
@@ -10,27 +10,43 @@ import (
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/config"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/db"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/logging"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/repository"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/rules/engine"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/rules/runner"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/services"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/version"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/go-chi/cors"
|
||||
)
|
||||
|
||||
// Dependencies bundles the services the server needs to satisfy its routes.
|
||||
type Dependencies struct {
|
||||
Runner *runner.Runner
|
||||
Engine *engine.Engine
|
||||
ConnService *services.ConnectionService
|
||||
RuleRepo *repository.RuleRepository
|
||||
ConnRepo *repository.ConnectionRepository
|
||||
RunRepo *repository.RuleRunRepository
|
||||
}
|
||||
|
||||
// Server represents the HTTP server
|
||||
type Server struct {
|
||||
config *config.Config
|
||||
db *db.DB
|
||||
logger *logging.Logger
|
||||
router *chi.Mux
|
||||
httpSrv *http.Server
|
||||
config *config.Config
|
||||
db *db.DB
|
||||
logger *logging.Logger
|
||||
deps Dependencies
|
||||
router *chi.Mux
|
||||
httpSrv *http.Server
|
||||
}
|
||||
|
||||
// New creates a new Server instance
|
||||
func New(cfg *config.Config, database *db.DB, logger *logging.Logger) *Server {
|
||||
func New(cfg *config.Config, database *db.DB, deps Dependencies, logger *logging.Logger) *Server {
|
||||
s := &Server{
|
||||
config: cfg,
|
||||
db: database,
|
||||
logger: logger,
|
||||
deps: deps,
|
||||
router: chi.NewRouter(),
|
||||
}
|
||||
s.setupMiddleware()
|
||||
@@ -41,10 +57,10 @@ func New(cfg *config.Config, database *db.DB, logger *logging.Logger) *Server {
|
||||
func (s *Server) setupMiddleware() {
|
||||
// Request ID
|
||||
s.router.Use(middleware.RequestID)
|
||||
|
||||
|
||||
// Real IP from trusted proxies
|
||||
s.router.Use(middleware.RealIP)
|
||||
|
||||
|
||||
// Request logging
|
||||
s.router.Use(func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -54,10 +70,10 @@ func (s *Server) setupMiddleware() {
|
||||
s.logger.Info("HTTP", "%s %s %d %s", r.Method, r.URL.Path, ww.Status(), time.Since(start))
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
// Panic recovery
|
||||
s.router.Use(middleware.Recoverer)
|
||||
|
||||
|
||||
// CORS
|
||||
s.router.Use(cors.Handler(cors.Options{
|
||||
AllowedOrigins: s.config.CORS.AllowedOrigins,
|
||||
@@ -73,13 +89,13 @@ func (s *Server) setupRoutes() {
|
||||
// Health check (unauthenticated)
|
||||
s.router.Get("/health", s.handleHealth)
|
||||
s.router.Get("/api/health", s.handleHealth)
|
||||
|
||||
|
||||
// API v1 routes
|
||||
s.router.Route("/api/v1", func(r chi.Router) {
|
||||
// System endpoints
|
||||
r.Get("/version", s.handleVersion)
|
||||
r.Get("/health", s.handleHealth)
|
||||
|
||||
|
||||
// Auth endpoints (to be implemented)
|
||||
r.Route("/auth", func(r chi.Router) {
|
||||
r.Post("/login", s.handleNotImplemented)
|
||||
@@ -87,7 +103,7 @@ func (s *Server) setupRoutes() {
|
||||
r.Get("/me", s.handleNotImplemented)
|
||||
r.Get("/csrf", s.handleNotImplemented)
|
||||
})
|
||||
|
||||
|
||||
// Users (to be implemented)
|
||||
r.Route("/users", func(r chi.Router) {
|
||||
r.Get("/", s.handleNotImplemented)
|
||||
@@ -96,7 +112,7 @@ func (s *Server) setupRoutes() {
|
||||
r.Put("/{id}", s.handleNotImplemented)
|
||||
r.Delete("/{id}", s.handleNotImplemented)
|
||||
})
|
||||
|
||||
|
||||
// Credentials
|
||||
r.Route("/credentials", func(r chi.Router) {
|
||||
r.Get("/", s.handleNotImplemented)
|
||||
@@ -106,7 +122,7 @@ func (s *Server) setupRoutes() {
|
||||
r.Delete("/{id}", s.handleNotImplemented)
|
||||
r.Post("/{id}/test", s.handleNotImplemented)
|
||||
})
|
||||
|
||||
|
||||
// AD Connections
|
||||
r.Route("/ad-connections", func(r chi.Router) {
|
||||
r.Get("/", s.handleNotImplemented)
|
||||
@@ -118,7 +134,7 @@ func (s *Server) setupRoutes() {
|
||||
r.Post("/{id}/test", s.handleNotImplemented)
|
||||
r.Post("/{id}/query-preview", s.handleNotImplemented)
|
||||
})
|
||||
|
||||
|
||||
// Schedules
|
||||
r.Route("/schedules", func(r chi.Router) {
|
||||
r.Get("/", s.handleNotImplemented)
|
||||
@@ -127,7 +143,7 @@ func (s *Server) setupRoutes() {
|
||||
r.Put("/{id}", s.handleNotImplemented)
|
||||
r.Delete("/{id}", s.handleNotImplemented)
|
||||
})
|
||||
|
||||
|
||||
// Rules
|
||||
r.Route("/rules", func(r chi.Router) {
|
||||
r.Get("/", s.handleNotImplemented)
|
||||
@@ -140,14 +156,14 @@ func (s *Server) setupRoutes() {
|
||||
r.Post("/{id}/enable", s.handleNotImplemented)
|
||||
r.Post("/{id}/disable", s.handleNotImplemented)
|
||||
})
|
||||
|
||||
|
||||
// Backups
|
||||
r.Route("/backups", func(r chi.Router) {
|
||||
r.Get("/", s.handleNotImplemented)
|
||||
r.Post("/", s.handleNotImplemented)
|
||||
r.Post("/{id}/restore", s.handleNotImplemented)
|
||||
})
|
||||
|
||||
|
||||
// API Keys
|
||||
r.Route("/api-keys", func(r chi.Router) {
|
||||
r.Get("/", s.handleNotImplemented)
|
||||
@@ -167,7 +183,7 @@ func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Server) handleVersion(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprintf(w, `{"version":"%s","build_time":"%s","git_commit":"%s"}`,
|
||||
fmt.Fprintf(w, `{"version":"%s","build_time":"%s","git_commit":"%s"}`,
|
||||
version.Version, version.BuildTime, version.GitCommit)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user