im 管理后台

This commit is contained in:
richjohnrambo
2026-08-11 23:13:51 +08:00
parent 0397fe5f22
commit 331a55751d
1407 changed files with 162069 additions and 2 deletions
@@ -0,0 +1,198 @@
// Package admin
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
package admin
import (
"fmt"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/disk"
"github.com/shirou/gopsutil/v3/host"
"github.com/shirou/gopsutil/v3/mem"
"github.com/shirou/gopsutil/v3/process"
"hotgo/internal/consts"
"hotgo/internal/model"
"hotgo/internal/service"
"hotgo/internal/websocket"
"hotgo/utility/file"
"hotgo/utility/format"
"hotgo/utility/simple"
"os"
"runtime"
"time"
)
var (
Monitor = cMonitor{}
)
type cMonitor struct{}
type MonitorHeadExtra struct {
Data interface{} `json:"data"`
Data1 string `json:"data1,omitempty"`
}
type MonitorHead struct {
Title string `json:"title"`
Data string `json:"data"`
BottomTitle string `json:"bottomTitle"`
TotalSum string `json:"totalSum"`
IconClass string `json:"iconClass"`
Extra MonitorHeadExtra `json:"extra"`
}
// RunInfo 运行信息
func (c *cMonitor) RunInfo(client *websocket.Client, req *websocket.WRequest) {
var (
meta = service.AdminMonitor().GetMeta(client.Context())
mHost, _ = host.Info()
pwd, _ = os.Getwd()
gm runtime.MemStats
)
runtime.ReadMemStats(&gm)
data := g.Map{
// 服务器信息
"hostname": mHost.Hostname,
"os": mHost.OS,
"arch": mHost.KernelArch,
"intranet_ip": meta.IntranetIP,
"public_ip": meta.PublicIP,
// 运行信息
"version": runtime.Version(), // GO 版本
"hgVersion": consts.VersionApp, // HG 版本
"startTime": gtime.New(meta.STartTime),
"runTime": gtime.Now().Timestamp() - meta.STartTime,
"rootPath": runtime.GOROOT(),
"pwd": pwd,
"goroutine": runtime.NumGoroutine(),
"goMem": format.FileSize(int64(gm.Sys)),
"goSize": file.DirSize(pwd),
}
if simple.IsDemo(client.Context()) {
data["rootPath"] = consts.DemoTips
data["pwd"] = consts.DemoTips
data["intranet_ip"] = consts.DemoTips
data["public_ip"] = consts.DemoTips
}
websocket.SendSuccess(client, req.Event, data)
}
// Trends 实时数据
func (c *cMonitor) Trends(client *websocket.Client, req *websocket.WRequest) {
type NetC struct {
Time *gtime.Time `json:"time"`
BytesSent string `json:"bytesSent"` // number of bytes sent
BytesRecv string `json:"bytesRecv"` // number of bytes received
Down float64 `json:"down"`
UP float64 `json:"up"`
}
var (
mCpu, cpuErr = cpu.Info()
mCpuUsed float64
mMem, memErr = mem.VirtualMemory()
mMemUsed float64
mDisk, diskErr = disk.Usage("/")
mProcess, processErr = process.Pids()
mLoadAvg = new(model.LoadAvgStats)
monitorHeads []MonitorHead
nets []NetC
meta = service.AdminMonitor().GetMeta(client.Context())
)
if cpuErr != nil {
g.Log().Infof(client.Context(), "read CPU info fail:%+v", cpuErr)
mCpu = []cpu.InfoStat{{VendorID: "", ModelName: ""}}
}
if memErr != nil {
g.Log().Infof(client.Context(), "read mem info fail:%+v", memErr)
mMem = new(mem.VirtualMemoryStat)
}
if diskErr != nil {
g.Log().Infof(client.Context(), "read disk info fail:%+v", diskErr)
mDisk = new(disk.UsageStat)
}
if processErr != nil {
g.Log().Infof(client.Context(), "read process.Pids fail:%+v", processErr)
}
// cpu使用率
cu, err := cpu.Percent(time.Second, false)
if err == nil {
mCpuUsed = gconv.Float64(fmt.Sprintf("%.2f", cu[0]))
}
// 内存使用率
mMemUsed = gconv.Float64(fmt.Sprintf("%.2f", mMem.UsedPercent))
// 负载
if len(meta.LoadAvg) > 0 {
mLoadAvg = meta.LoadAvg[len(meta.LoadAvg)-1]
}
monitorHeads = append(monitorHeads, MonitorHead{
Title: "CPU",
Data: "使用率 " + format.Round2String(mCpuUsed) + "%",
BottomTitle: "CPU数量",
TotalSum: gconv.String(runtime.NumCPU()) + "核心",
IconClass: "HardwareChip",
Extra: MonitorHeadExtra{
Data: mCpu[0].VendorID,
Data1: mCpu[0].ModelName,
}},
MonitorHead{
Title: "内存",
Data: "使用率 " + format.Round2String(mMemUsed) + "%",
BottomTitle: "总内存",
TotalSum: format.FileSize(int64(mMem.Total)),
IconClass: "AppsSharp",
Extra: MonitorHeadExtra{
Data: format.FileSize(int64(mMem.Used)),
Data1: format.FileSize(int64(mMem.Total - mMem.Used)),
}},
MonitorHead{
Title: "磁盘",
Data: "已用 " + format.FileSize(int64(mDisk.Used)),
BottomTitle: "总容量",
TotalSum: format.FileSize(int64(mDisk.Total)),
IconClass: "PieChart",
Extra: MonitorHeadExtra{
Data: format.Round2String(mDisk.UsedPercent),
}},
MonitorHead{
Title: "负载",
Data: format.Round2String(mLoadAvg.Ratio) + "%",
BottomTitle: "总进程数",
TotalSum: gconv.String(len(mProcess)) + "个",
IconClass: "Analytics",
})
for _, v := range meta.NetIO {
nets = append(nets, NetC{
Time: v.Time,
BytesSent: format.FileSize(int64(v.BytesSent)), // 转换为最大整数单位
BytesRecv: format.FileSize(int64(v.BytesRecv)),
Down: format.Round2Float64(v.Down / 1024), // 转换为kb
UP: format.Round2Float64(v.UP / 1024),
})
}
websocket.SendSuccess(client, req.Event, g.Map{
"head": monitorHeads,
"load": meta.LoadAvg,
"net": nets,
})
}
@@ -0,0 +1,39 @@
// Package common
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
package common
import (
"github.com/gogf/gf/v2/util/gconv"
"hotgo/internal/websocket"
)
var (
Site = cSite{}
)
type cSite struct{}
func (c *cSite) Join(client *websocket.Client, req *websocket.WRequest) {
name := gconv.String(req.Data["id"])
if !client.Tags.Contains(name) {
client.Tags.Append(name)
}
websocket.SendSuccess(client, req.Event, client.Tags.Slice())
}
func (c *cSite) Quit(client *websocket.Client, req *websocket.WRequest) {
name := gconv.String(req.Data["id"])
if client.Tags.Contains(name) {
client.Tags.RemoveValue(name)
}
websocket.SendSuccess(client, req.Event, client.Tags.Slice())
}
func (c *cSite) Ping(client *websocket.Client, req *websocket.WRequest) {
websocket.SendSuccess(client, req.Event)
}
@@ -0,0 +1,29 @@
// Package websocket
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
package websocket
import (
"context"
"hotgo/api/websocket/base"
"hotgo/internal/websocket"
"hotgo/utility/simple"
)
// Send 通过http发送ws消息
var Send = send{}
type send struct{}
// SendToTag 发送标签消息
func (c *send) SendToTag(ctx context.Context, req *base.SendToTagReq) (res *base.SendToTagRes, err error) {
simple.SafeGo(ctx, func(ctx context.Context) {
websocket.SendToTag(req.Tag, &websocket.WResponse{
Event: req.Response.Event,
Data: req.Response,
})
})
return
}