mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2026-05-10 15:56:17 +08:00
- Introduced `WebSocketTrustedOrigins` setting in `app.example.ini` and corresponding documentation. - Refactored WebSocket origin checks across multiple API endpoints to utilize the new middleware for improved security. - Added tests for the new origin validation logic to ensure proper handling of trusted origins and node secret requests.
124 lines
2.9 KiB
Go
124 lines
2.9 KiB
Go
package analytic
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/0xJacky/Nginx-UI/internal/analytic"
|
|
"github.com/0xJacky/Nginx-UI/internal/helper"
|
|
"github.com/0xJacky/Nginx-UI/internal/kernel"
|
|
"github.com/0xJacky/Nginx-UI/internal/middleware"
|
|
"github.com/0xJacky/Nginx-UI/internal/version"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/gorilla/websocket"
|
|
"github.com/shirou/gopsutil/v4/cpu"
|
|
"github.com/uozi-tech/cosy/logger"
|
|
)
|
|
|
|
func GetNodeStat(c *gin.Context) {
|
|
var upGrader = websocket.Upgrader{
|
|
CheckOrigin: middleware.CheckWebSocketOrigin,
|
|
}
|
|
// upgrade http to websocket
|
|
ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
|
if err != nil {
|
|
logger.Error(err)
|
|
return
|
|
}
|
|
|
|
defer ws.Close()
|
|
|
|
// Counter to track iterations for periodic full info update
|
|
counter := 0
|
|
const fullInfoInterval = 6 // Send full info every 6 iterations (every minute if interval is 10s)
|
|
|
|
for {
|
|
var data interface{}
|
|
|
|
// Every fullInfoInterval iterations, send complete node information including version
|
|
if counter%fullInfoInterval == 0 {
|
|
// Get complete node information including version
|
|
runtimeInfo, err := version.GetRuntimeInfo()
|
|
if err != nil {
|
|
logger.Error("Failed to get runtime info:", err)
|
|
// Fallback to stat only
|
|
data = analytic.GetNodeStat()
|
|
} else {
|
|
cpuInfo, _ := cpu.Info()
|
|
memory, _ := analytic.GetMemoryStat()
|
|
ver := version.GetVersionInfo()
|
|
diskUsage, _ := analytic.GetDiskStat()
|
|
|
|
nodeInfo := analytic.NodeInfo{
|
|
NodeRuntimeInfo: runtimeInfo,
|
|
CPUNum: len(cpuInfo),
|
|
MemoryTotal: memory.Total,
|
|
DiskTotal: diskUsage.Total,
|
|
Version: ver.Version,
|
|
}
|
|
|
|
stat := analytic.GetNodeStat()
|
|
|
|
// Send complete node information
|
|
data = analytic.Node{
|
|
NodeInfo: nodeInfo,
|
|
NodeStat: stat,
|
|
}
|
|
}
|
|
} else {
|
|
// Send only stat information for performance
|
|
data = analytic.GetNodeStat()
|
|
}
|
|
|
|
// write
|
|
err = ws.WriteJSON(data)
|
|
if err != nil {
|
|
if helper.IsUnexpectedWebsocketError(err) {
|
|
logger.Error(err)
|
|
}
|
|
break
|
|
}
|
|
|
|
counter++
|
|
|
|
select {
|
|
case <-kernel.Context.Done():
|
|
logger.Debug("GetNodeStat: Context cancelled, closing WebSocket")
|
|
return
|
|
case <-time.After(10 * time.Second):
|
|
}
|
|
}
|
|
}
|
|
|
|
func GetNodesAnalytic(c *gin.Context) {
|
|
var upGrader = websocket.Upgrader{
|
|
CheckOrigin: middleware.CheckWebSocketOrigin,
|
|
}
|
|
// upgrade http to websocket
|
|
ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
|
if err != nil {
|
|
logger.Error(err)
|
|
return
|
|
}
|
|
|
|
defer ws.Close()
|
|
|
|
for {
|
|
// Send snapshot of NodeMap data to client to avoid concurrent access
|
|
nodeSnapshot := analytic.SnapshotNodeMap()
|
|
err = ws.WriteJSON(nodeSnapshot)
|
|
if err != nil {
|
|
if helper.IsUnexpectedWebsocketError(err) {
|
|
logger.Error(err)
|
|
}
|
|
break
|
|
}
|
|
|
|
select {
|
|
case <-kernel.Context.Done():
|
|
logger.Debug("GetNodesAnalytic: Context cancelled, closing WebSocket")
|
|
return
|
|
case <-time.After(10 * time.Second):
|
|
}
|
|
}
|
|
}
|