1
0

main.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. package main
  2. import (
  3. "context"
  4. "crypto/tls"
  5. "fmt"
  6. "net"
  7. "os"
  8. "os/signal"
  9. "syscall"
  10. "github.com/0xJacky/Nginx-UI/internal/cert"
  11. "github.com/0xJacky/Nginx-UI/internal/cmd"
  12. "github.com/0xJacky/Nginx-UI/internal/process"
  13. "code.pfad.fr/risefront"
  14. "github.com/0xJacky/Nginx-UI/internal/kernel"
  15. "github.com/0xJacky/Nginx-UI/internal/migrate"
  16. "github.com/0xJacky/Nginx-UI/model"
  17. "github.com/0xJacky/Nginx-UI/router"
  18. "github.com/0xJacky/Nginx-UI/settings"
  19. "github.com/gin-gonic/gin"
  20. "github.com/uozi-tech/cosy"
  21. cKernel "github.com/uozi-tech/cosy/kernel"
  22. "github.com/uozi-tech/cosy/logger"
  23. cRouter "github.com/uozi-tech/cosy/router"
  24. cSettings "github.com/uozi-tech/cosy/settings"
  25. )
  26. func Program(ctx context.Context, confPath string) func(l []net.Listener) error {
  27. return func(l []net.Listener) error {
  28. listener := l[0]
  29. cosy.RegisterMigrationsBeforeAutoMigrate(migrate.BeforeAutoMigrate)
  30. cosy.RegisterModels(model.GenerateAllModel()...)
  31. cosy.RegisterMigration(migrate.Migrations)
  32. cosy.RegisterInitFunc(func() {
  33. kernel.Boot(ctx)
  34. router.InitRouter()
  35. })
  36. // Initialize settings package
  37. settings.Init(confPath)
  38. // Set gin mode
  39. gin.SetMode(cSettings.ServerSettings.RunMode)
  40. // Initialize logger package
  41. logger.Init(cSettings.ServerSettings.RunMode)
  42. defer logger.Sync()
  43. defer logger.Info("Server exited")
  44. // Gin router initialization
  45. cRouter.Init()
  46. // Kernel boot
  47. cKernel.Boot(ctx)
  48. // Get the HTTP handler from Cosy router
  49. handler := cRouter.GetEngine()
  50. // Configure TLS if HTTPS is enabled
  51. var tlsConfig *tls.Config
  52. if cSettings.ServerSettings.EnableHTTPS {
  53. // Load TLS certificate
  54. err := cert.LoadServerTLSCertificate()
  55. if err != nil {
  56. logger.Fatalf("Failed to load TLS certificate: %v", err)
  57. return err
  58. }
  59. // Configure ALPN protocols based on settings
  60. // Protocol negotiation priority is fixed: h3 -> h2 -> h1
  61. var nextProtos []string
  62. if cSettings.ServerSettings.EnableH3 {
  63. nextProtos = append(nextProtos, "h3")
  64. }
  65. if cSettings.ServerSettings.EnableH2 {
  66. nextProtos = append(nextProtos, "h2")
  67. }
  68. // HTTP/1.1 is always supported as fallback
  69. nextProtos = append(nextProtos, "http/1.1")
  70. tlsConfig = &tls.Config{
  71. GetCertificate: func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
  72. return cert.GetServerTLSCertificate()
  73. },
  74. MinVersion: tls.VersionTLS12,
  75. NextProtos: nextProtos,
  76. }
  77. }
  78. // Create and initialize the server factory
  79. serverFactory := cKernel.NewServerFactory(handler, tlsConfig)
  80. if err := serverFactory.Initialize(); err != nil {
  81. logger.Fatalf("Failed to initialize server factory: %v", err)
  82. return err
  83. }
  84. go func() {
  85. logger.Info("Started graceful shutdown handler goroutine")
  86. // Wait for context cancellation
  87. <-ctx.Done()
  88. // Graceful shutdown
  89. logger.Info("Shutting down servers...")
  90. if err := serverFactory.Shutdown(ctx); err != nil {
  91. if kernel.IsUnknownServerListenError(err) {
  92. logger.Errorf("Error during server shutdown: %v", err)
  93. }
  94. }
  95. logger.Info("Graceful shutdown handler goroutine completed")
  96. }()
  97. // Start the servers
  98. if err := serverFactory.Start(ctx, listener); err != nil {
  99. logger.Fatalf("Failed to start servers: %v", err)
  100. return err
  101. }
  102. <-ctx.Done()
  103. // Graceful shutdown
  104. logger.Info("Shutting down servers...")
  105. if err := serverFactory.Shutdown(ctx); err != nil {
  106. if kernel.IsUnknownServerListenError(err) {
  107. logger.Errorf("Error during server shutdown: %v", err)
  108. }
  109. }
  110. return nil
  111. }
  112. }
  113. //go:generate go generate ./cmd/...
  114. func main() {
  115. appCmd := cmd.NewAppCmd()
  116. confPath := appCmd.String("config")
  117. settings.Init(confPath)
  118. mainCtx, mainCancel := signal.NotifyContext(context.Background(), syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
  119. defer mainCancel()
  120. pidPath := appCmd.String("pidfile")
  121. if pidPath != "" {
  122. if err := process.WritePIDFile(pidPath); err != nil {
  123. logger.Fatalf("Failed to write PID file: %v", err)
  124. }
  125. defer process.RemovePIDFile(pidPath)
  126. }
  127. kernel.Anchor()
  128. var programCancel context.CancelFunc
  129. err := risefront.New(mainCtx, risefront.Config{
  130. Run: func(l []net.Listener) error {
  131. // Create a new context for the program itself, derived from the main context.
  132. programCtx, cancel := context.WithCancel(mainCtx)
  133. // Store the cancel function so the Shutdown callback can use it.
  134. programCancel = cancel
  135. return Program(programCtx, confPath)(l)
  136. },
  137. Shutdown: func() {
  138. // This is called by risefront.Restart() to shut down the old program.
  139. if programCancel != nil {
  140. programCancel()
  141. }
  142. },
  143. Name: "nginx-ui",
  144. Addresses: []string{fmt.Sprintf("%s:%d", cSettings.ServerSettings.Host, cSettings.ServerSettings.Port)},
  145. LogHandler: func(loglevel risefront.LogLevel, kind string, args ...any) {
  146. logger := logger.GetLogger()
  147. args = append([]any{kind}, args...)
  148. switch loglevel {
  149. case risefront.DebugLevel:
  150. logger.Debug(args...)
  151. case risefront.InfoLevel:
  152. logger.Info(args...)
  153. case risefront.WarnLevel:
  154. logger.Warn(args...)
  155. case risefront.ErrorLevel:
  156. logger.Error(args...)
  157. case risefront.FatalLevel:
  158. logger.Fatal(args...)
  159. case risefront.PanicLevel:
  160. logger.Panic(args...)
  161. default:
  162. logger.Error(args...)
  163. }
  164. },
  165. })
  166. if err != nil && kernel.IsUnknownServerListenError(err) {
  167. logger.Error(err)
  168. os.Exit(1)
  169. }
  170. }