status.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // Implementation of GetDetailedStatus API
  2. // This feature is designed to address Issue #850, providing Nginx load monitoring functionality similar to BT Panel
  3. // Returns detailed Nginx status information, including request statistics, connections, worker processes, and other data
  4. package nginx
  5. import (
  6. "net/http"
  7. "strings"
  8. "time"
  9. "github.com/0xJacky/Nginx-UI/api"
  10. "github.com/0xJacky/Nginx-UI/internal/nginx"
  11. "github.com/0xJacky/Nginx-UI/internal/performance"
  12. "github.com/gin-gonic/gin"
  13. "github.com/uozi-tech/cosy"
  14. "github.com/uozi-tech/cosy/logger"
  15. )
  16. // NginxPerformanceInfo stores Nginx performance-related information
  17. type NginxPerformanceInfo struct {
  18. // Basic status information
  19. performance.StubStatusData
  20. // Process-related information
  21. performance.NginxProcessInfo
  22. // Configuration information
  23. performance.NginxConfigInfo
  24. }
  25. // GetDetailStatus retrieves detailed Nginx status information
  26. func GetDetailStatus(c *gin.Context) {
  27. response := performance.GetPerformanceData()
  28. c.JSON(http.StatusOK, response)
  29. }
  30. // StreamDetailStatus streams Nginx detailed status information using SSE
  31. func StreamDetailStatus(c *gin.Context) {
  32. // Set SSE response headers
  33. api.SetSSEHeaders(c)
  34. // Create context that cancels when client disconnects
  35. ctx := c.Request.Context()
  36. // Create a ticker channel to prevent goroutine leaks
  37. ticker := time.NewTicker(5 * time.Second)
  38. defer ticker.Stop()
  39. // Send initial data immediately
  40. sendPerformanceData(c)
  41. // Use goroutine to send data periodically
  42. for {
  43. select {
  44. case <-ticker.C:
  45. // Send performance data
  46. sendPerformanceData(c)
  47. case <-ctx.Done():
  48. // Client closed connection or request canceled
  49. logger.Debug("Client closed connection")
  50. return
  51. }
  52. }
  53. }
  54. // sendPerformanceData sends performance data once
  55. func sendPerformanceData(c *gin.Context) {
  56. response := performance.GetPerformanceData()
  57. // Send SSE event
  58. c.SSEvent("message", response)
  59. // Flush buffer to ensure data is sent immediately
  60. c.Writer.Flush()
  61. }
  62. // CheckStubStatus gets Nginx stub_status module status
  63. func CheckStubStatus(c *gin.Context) {
  64. stubStatus := performance.GetStubStatus()
  65. c.JSON(http.StatusOK, stubStatus)
  66. }
  67. // ToggleStubStatus enables or disables stub_status module
  68. func ToggleStubStatus(c *gin.Context) {
  69. var json struct {
  70. Enable bool `json:"enable"`
  71. }
  72. if !cosy.BindAndValid(c, &json) {
  73. return
  74. }
  75. stubStatus := performance.GetStubStatus()
  76. // If current status matches desired status, no action needed
  77. if stubStatus.Enabled == json.Enable {
  78. c.JSON(http.StatusOK, stubStatus)
  79. return
  80. }
  81. var err error
  82. if json.Enable {
  83. err = performance.EnableStubStatus()
  84. } else {
  85. err = performance.DisableStubStatus()
  86. }
  87. if err != nil {
  88. cosy.ErrHandler(c, err)
  89. return
  90. }
  91. // Reload Nginx configuration
  92. reloadOutput, err := nginx.Reload()
  93. if err != nil {
  94. cosy.ErrHandler(c, err)
  95. return
  96. }
  97. if len(reloadOutput) > 0 && (strings.Contains(strings.ToLower(reloadOutput), "error") ||
  98. strings.Contains(strings.ToLower(reloadOutput), "failed")) {
  99. cosy.ErrHandler(c, cosy.WrapErrorWithParams(nginx.ErrReloadFailed, reloadOutput))
  100. return
  101. }
  102. // Check status after operation
  103. newStubStatus := performance.GetStubStatus()
  104. c.JSON(http.StatusOK, newStubStatus)
  105. }