feat: init project

This commit is contained in:
yanghao05
2025-08-05 17:26:59 +08:00
parent c5d621ad03
commit e034a2e54e
30 changed files with 5159 additions and 0 deletions

51
cmd/root.go Normal file
View File

@@ -0,0 +1,51 @@
/*
Copyright © 2025 NAME HERE <EMAIL ADDRESS>
*/
package cmd
import (
"os"
"github.com/spf13/cobra"
)
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "database_render",
Short: "A brief description of your application",
Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
// Uncomment the following line if your bare application
// has an action associated with it:
// Run: func(cmd *cobra.Command, args []string) { },
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
func init() {
// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.database_render.yaml)")
// Cobra also supports local flags, which will only run
// when this action is called directly.
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

137
cmd/server/main.go Normal file
View File

@@ -0,0 +1,137 @@
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)
}
// Initialize renderer
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")
}