main.go 4.9 KB

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