main.go 4.8 KB

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