status.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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/internal/nginx"
  10. "github.com/0xJacky/Nginx-UI/internal/performance"
  11. "github.com/gin-gonic/gin"
  12. "github.com/uozi-tech/cosy"
  13. "github.com/uozi-tech/cosy/logger"
  14. )
  15. // NginxPerformanceInfo stores Nginx performance-related information
  16. type NginxPerformanceInfo struct {
  17. // Basic status information
  18. performance.StubStatusData
  19. // Process-related information
  20. performance.NginxProcessInfo
  21. // Configuration information
  22. performance.NginxConfigInfo
  23. }
  24. // GetDetailStatus retrieves detailed Nginx status information
  25. func GetDetailStatus(c *gin.Context) {
  26. response := performance.GetPerformanceData()
  27. c.JSON(http.StatusOK, response)
  28. }
  29. // StreamDetailStatus streams Nginx detailed status information using SSE
  30. func StreamDetailStatus(c *gin.Context) {
  31. // Set SSE response headers
  32. c.Header("Content-Type", "text/event-stream")
  33. c.Header("Cache-Control", "no-cache")
  34. c.Header("Connection", "keep-alive")
  35. c.Header("Access-Control-Allow-Origin", "*")
  36. // Create context that cancels when client disconnects
  37. ctx := c.Request.Context()
  38. // Create a ticker channel to prevent goroutine leaks
  39. ticker := time.NewTicker(5 * time.Second)
  40. defer ticker.Stop()
  41. // Send initial data immediately
  42. sendPerformanceData(c)
  43. // Use goroutine to send data periodically
  44. for {
  45. select {
  46. case <-ticker.C:
  47. // Send performance data
  48. if err := sendPerformanceData(c); err != nil {
  49. logger.Warn("Error sending SSE data:", err)
  50. return
  51. }
  52. case <-ctx.Done():
  53. // Client closed connection or request canceled
  54. logger.Debug("Client closed connection")
  55. return
  56. }
  57. }
  58. }
  59. // sendPerformanceData sends performance data once
  60. func sendPerformanceData(c *gin.Context) error {
  61. response := performance.GetPerformanceData()
  62. // Send SSE event
  63. c.SSEvent("message", response)
  64. // Flush buffer to ensure data is sent immediately
  65. c.Writer.Flush()
  66. return nil
  67. }
  68. // CheckStubStatus gets Nginx stub_status module status
  69. func CheckStubStatus(c *gin.Context) {
  70. stubStatus := performance.GetStubStatus()
  71. c.JSON(http.StatusOK, stubStatus)
  72. }
  73. // ToggleStubStatus enables or disables stub_status module
  74. func ToggleStubStatus(c *gin.Context) {
  75. var json struct {
  76. Enable bool `json:"enable"`
  77. }
  78. if !cosy.BindAndValid(c, &json) {
  79. return
  80. }
  81. stubStatus := performance.GetStubStatus()
  82. // If current status matches desired status, no action needed
  83. if stubStatus.Enabled == json.Enable {
  84. c.JSON(http.StatusOK, stubStatus)
  85. return
  86. }
  87. var err error
  88. if json.Enable {
  89. err = performance.EnableStubStatus()
  90. } else {
  91. err = performance.DisableStubStatus()
  92. }
  93. if err != nil {
  94. cosy.ErrHandler(c, err)
  95. return
  96. }
  97. // Reload Nginx configuration
  98. reloadOutput, err := nginx.Reload()
  99. if err != nil {
  100. cosy.ErrHandler(c, err)
  101. return
  102. }
  103. if len(reloadOutput) > 0 && (strings.Contains(strings.ToLower(reloadOutput), "error") ||
  104. strings.Contains(strings.ToLower(reloadOutput), "failed")) {
  105. cosy.ErrHandler(c, cosy.WrapErrorWithParams(nginx.ErrReloadFailed, reloadOutput))
  106. return
  107. }
  108. // Check status after operation
  109. newStubStatus := performance.GetStubStatus()
  110. c.JSON(http.StatusOK, newStubStatus)
  111. }