137 lines
3.3 KiB
Go
137 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log/slog"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v3"
|
|
"github.com/gofiber/fiber/v3/middleware/cors"
|
|
"github.com/gofiber/fiber/v3/middleware/recover"
|
|
"github.com/rogeecn/database_render/internal/config"
|
|
"github.com/rogeecn/database_render/internal/database"
|
|
"github.com/rogeecn/database_render/internal/handler"
|
|
"github.com/rogeecn/database_render/internal/repository"
|
|
"github.com/rogeecn/database_render/internal/service"
|
|
"github.com/rogeecn/database_render/internal/template"
|
|
)
|
|
|
|
func main() {
|
|
// Initialize structured logging
|
|
opts := &slog.HandlerOptions{
|
|
Level: slog.LevelInfo,
|
|
}
|
|
logger := slog.New(slog.NewJSONHandler(os.Stdout, opts))
|
|
slog.SetDefault(logger)
|
|
|
|
// Load configuration
|
|
cfg, err := config.LoadConfig("")
|
|
if err != nil {
|
|
slog.Error("failed to load configuration", "error", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Initialize database
|
|
db, err := database.NewConnectionManager(cfg)
|
|
if err != nil {
|
|
slog.Error("failed to initialize database", "error", err)
|
|
os.Exit(1)
|
|
}
|
|
defer func() {
|
|
if err := db.Close(); err != nil {
|
|
slog.Error("failed to close database", "error", err)
|
|
}
|
|
}()
|
|
|
|
// Initialize repository and services
|
|
repo := repository.NewDataRepository(db, cfg)
|
|
svc := service.NewDataService(repo, cfg)
|
|
if err := svc.ValidateConfiguration(); err != nil {
|
|
slog.Error("configuration validation failed", "error", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Keep using original renderer, now integrated with new template system
|
|
renderer, err := template.NewRenderer(svc, cfg)
|
|
if err != nil {
|
|
slog.Error("failed to initialize renderer", "error", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Initialize handlers
|
|
dataHandler := handler.NewDataHandler(svc)
|
|
|
|
// Initialize Fiber app
|
|
app := fiber.New(fiber.Config{
|
|
ReadTimeout: 30 * time.Second,
|
|
WriteTimeout: 30 * time.Second,
|
|
IdleTimeout: 60 * time.Second,
|
|
ErrorHandler: renderer.ErrorHandler,
|
|
Views: nil, // Using custom renderer
|
|
})
|
|
|
|
// Setup middleware
|
|
app.Use(recover.New())
|
|
app.Use(cors.New(cors.Config{
|
|
AllowOrigins: []string{"*"},
|
|
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
|
AllowHeaders: []string{"Origin", "Content-Type", "Accept"},
|
|
}))
|
|
|
|
// Setup routes
|
|
// API routes
|
|
dataHandler.SetupRoutes(app)
|
|
|
|
// Template routes
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
tableName := c.Query("table")
|
|
if tableName == "" {
|
|
return renderer.RenderIndex(c)
|
|
}
|
|
return renderer.RenderList(c, tableName)
|
|
})
|
|
|
|
// Setup static file serving
|
|
renderer.ServeStatic(app)
|
|
|
|
// Health check endpoint
|
|
app.Get("/health", func(c fiber.Ctx) error {
|
|
return c.JSON(map[string]string{
|
|
"status": "ok",
|
|
"timestamp": time.Now().Format(time.RFC3339),
|
|
})
|
|
})
|
|
|
|
// Start server
|
|
port := cfg.App.Port
|
|
if port == 0 {
|
|
port = 8080
|
|
}
|
|
|
|
// Start server in a goroutine
|
|
go func() {
|
|
slog.Info("starting server", "port", port)
|
|
if err := app.Listen(fmt.Sprintf(":%d", port)); err != nil {
|
|
slog.Error("server error", "error", err)
|
|
os.Exit(1)
|
|
}
|
|
}()
|
|
|
|
// Wait for interrupt signal to gracefully shutdown the server
|
|
quit := make(chan os.Signal, 1)
|
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
|
<-quit
|
|
|
|
slog.Info("shutting down server...")
|
|
|
|
// Shutdown server
|
|
if err := app.Shutdown(); err != nil {
|
|
slog.Error("server shutdown error", "error", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
slog.Info("server gracefully stopped")
|
|
} |