nginx-ui/api/nginx/status.go

132 lines
3.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// GetDetailedStatus API 实现
// 该功能用于解决 Issue #850提供类似宝塔面板的 Nginx 负载监控功能
// 返回详细的 Nginx 状态信息,包括请求统计、连接数、工作进程等数据
package nginx
import (
"errors"
"net/http"
"strings"
"time"
"github.com/0xJacky/Nginx-UI/internal/nginx"
"github.com/gin-gonic/gin"
"github.com/uozi-tech/cosy"
"github.com/uozi-tech/cosy/logger"
)
// NginxPerformanceInfo 存储 Nginx 性能相关信息
type NginxPerformanceInfo struct {
// 基本状态信息
nginx.StubStatusData
// 进程相关信息
nginx.NginxProcessInfo
// 配置信息
nginx.NginxConfigInfo
}
// GetDetailStatus 获取 Nginx 详细状态信息
func GetDetailStatus(c *gin.Context) {
response := nginx.GetPerformanceData()
c.JSON(http.StatusOK, response)
}
// StreamDetailStatus 使用 SSE 流式推送 Nginx 详细状态信息
func StreamDetailStatus(c *gin.Context) {
// 设置 SSE 的响应头
c.Header("Content-Type", "text/event-stream")
c.Header("Cache-Control", "no-cache")
c.Header("Connection", "keep-alive")
c.Header("Access-Control-Allow-Origin", "*")
// 创建上下文,当客户端断开连接时取消
ctx := c.Request.Context()
// 为防止 goroutine 泄漏,创建一个计时器通道
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
// 立即发送一次初始数据
sendPerformanceData(c)
// 使用 goroutine 定期发送数据
for {
select {
case <-ticker.C:
// 发送性能数据
if err := sendPerformanceData(c); err != nil {
logger.Warn("Error sending SSE data:", err)
return
}
case <-ctx.Done():
// 客户端断开连接或请求被取消
logger.Debug("Client closed connection")
return
}
}
}
// sendPerformanceData 发送一次性能数据
func sendPerformanceData(c *gin.Context) error {
response := nginx.GetPerformanceData()
// 发送 SSE 事件
c.SSEvent("message", response)
// 刷新缓冲区,确保数据立即发送
c.Writer.Flush()
return nil
}
// CheckStubStatus 获取 Nginx stub_status 模块状态
func CheckStubStatus(c *gin.Context) {
stubStatus := nginx.GetStubStatus()
c.JSON(http.StatusOK, stubStatus)
}
// ToggleStubStatus 启用或禁用 stub_status 模块
func ToggleStubStatus(c *gin.Context) {
var json struct {
Enable bool `json:"enable"`
}
if !cosy.BindAndValid(c, &json) {
return
}
stubStatus := nginx.GetStubStatus()
// 如果当前状态与期望状态相同,则无需操作
if stubStatus.Enabled == json.Enable {
c.JSON(http.StatusOK, stubStatus)
return
}
var err error
if json.Enable {
err = nginx.EnableStubStatus()
} else {
err = nginx.DisableStubStatus()
}
if err != nil {
cosy.ErrHandler(c, err)
return
}
// 重新加载 Nginx 配置
reloadOutput := nginx.Reload()
if len(reloadOutput) > 0 && (strings.Contains(strings.ToLower(reloadOutput), "error") ||
strings.Contains(strings.ToLower(reloadOutput), "failed")) {
cosy.ErrHandler(c, errors.New("Reload Nginx failed"))
return
}
// 检查操作后的状态
newStubStatus := nginx.GetStubStatus()
c.JSON(http.StatusOK, newStubStatus)
}