main.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "log"
  6. "net/http"
  7. "os"
  8. "os/signal"
  9. "syscall"
  10. "time"
  11. "github.com/alecthomas/kong"
  12. "github.com/gin-gonic/gin"
  13. "git.linuxforward.com/byom/byom-onboard/internal/common/jwt"
  14. "git.linuxforward.com/byom/byom-onboard/internal/domain/billing"
  15. "git.linuxforward.com/byom/byom-onboard/internal/domain/register"
  16. "git.linuxforward.com/byom/byom-onboard/internal/platform/config"
  17. "git.linuxforward.com/byom/byom-onboard/internal/platform/database"
  18. "git.linuxforward.com/byom/byom-onboard/internal/platform/mailer"
  19. )
  20. var (
  21. // Build information - values will be set during build
  22. version = "dev"
  23. commit = "none"
  24. buildDate = "unknown"
  25. )
  26. type CLI struct {
  27. Config string `help:"Config file path" default:"config.yaml" type:"path"`
  28. Debug bool `help:"Enable debug mode"`
  29. Version VersionCmd `cmd:"" help:"Show version information"`
  30. Serve ServeCmd `cmd:"" help:"Start the HTTP server"`
  31. }
  32. type VersionCmd struct{}
  33. func (v VersionCmd) Run() error {
  34. fmt.Printf("Version:\t%s\n", version)
  35. fmt.Printf("Commit:\t\t%s\n", commit)
  36. fmt.Printf("Built:\t\t%s\n", buildDate)
  37. return nil
  38. }
  39. // ServeCmd handles the serve command
  40. type ServeCmd struct {
  41. Port int `help:"Port to listen on" default:"8080"`
  42. Host string `help:"Host to bind to" default:"0.0.0.0"`
  43. }
  44. func (s *ServeCmd) Run(cli *CLI) error {
  45. // Load configuration
  46. cfg, err := config.Load()
  47. if err != nil {
  48. return fmt.Errorf("failed to load configuration: %w", err)
  49. }
  50. // Initialize Gin
  51. gin.SetMode(gin.ReleaseMode)
  52. r := gin.New()
  53. r.Use(gin.Logger())
  54. r.Use(gin.Recovery())
  55. if cli.Debug {
  56. log.Printf("Debug mode enabled")
  57. gin.SetMode(gin.DebugMode)
  58. log.Printf("Using config file: %s", cli.Config)
  59. }
  60. // Initialize database
  61. db, err := database.NewDatabase(cfg.Database.DSN)
  62. if err != nil {
  63. return fmt.Errorf("failed to initialize database: %w", err)
  64. }
  65. jwtClient := jwt.NewJWTClient([]byte(cfg.JWT.Secret))
  66. // Initialize services
  67. stripeClient := billing.NewStripeClient(cfg.Stripe.SecretKey, cfg.Stripe.WebhookSecret)
  68. mailerClient := mailer.NewMailer(&cfg.Mailer)
  69. //ovhClient := provisioning.NewOvhClient(cfg.OVH.Endpoint, cfg.OVH.AppKey, cfg.OVH.AppSecret)
  70. // Initialize handlers
  71. billingHandler := billing.NewHandler(stripeClient, db)
  72. //provisioningHandler := provisioning.NewHandler(ovhClient, db)
  73. registerHandler := register.NewHandler(mailerClient, db, jwtClient)
  74. // Setup server
  75. server := setupServer(r, billingHandler, registerHandler, cfg)
  76. server.Addr = fmt.Sprintf(":%d", s.Port)
  77. // Start server in a goroutine
  78. go func() {
  79. log.Printf("Starting server on port %d", s.Port)
  80. if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
  81. log.Fatalf("Failed to start server: %v", err)
  82. }
  83. }()
  84. // Setup graceful shutdown
  85. quit := make(chan os.Signal, 1)
  86. signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
  87. <-quit
  88. log.Println("Shutting down server...")
  89. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  90. defer cancel()
  91. if err := server.Shutdown(ctx); err != nil {
  92. return fmt.Errorf("server forced to shutdown: %w", err)
  93. }
  94. log.Println("Server exited properly")
  95. return nil
  96. }
  97. func setupServer(
  98. r *gin.Engine,
  99. billingHandler *billing.Handler,
  100. registerHandler *register.Handler,
  101. config *config.Config,
  102. ) *http.Server {
  103. api := r.Group("/api/v1")
  104. {
  105. // Public routes
  106. api.POST("/check-email", registerHandler.CheckEmail)
  107. api.POST("/register", registerHandler.Register)
  108. api.GET("/validate-email", registerHandler.ValidateEmail)
  109. // Payment routes
  110. api.POST("/payment", billingHandler.CreatePayment)
  111. api.POST("/payment/webhook", billingHandler.HandleWebhook)
  112. }
  113. return &http.Server{
  114. Addr: config.Server.Address,
  115. Handler: r,
  116. }
  117. }
  118. func main() {
  119. cli := CLI{}
  120. ctx := kong.Parse(&cli,
  121. kong.Name("byom"),
  122. kong.Description("BYOM - Onboarding service"),
  123. kong.UsageOnError(),
  124. kong.ConfigureHelp(kong.HelpOptions{
  125. Compact: true,
  126. Summary: true,
  127. }),
  128. )
  129. err := ctx.Run(&cli)
  130. ctx.FatalIfErrorf(err)
  131. }