Files
u-desk/internal/agent/handler/system_handler.go
T
lxy 6bee55b96f 新增:SFTP直连+连接池+autoConnect+文件服务器端口自动回退
- SFTP模块:连接/断开/文件CRUD/系统信息采集/base64二进制写入
- 连接池:多服务器同时在线,瞬间切换profile
- autoConnect:启动时自动连接所有非本地服务器
- 端口自动回退:listenWithFallback消除TOCTOU,解决端口冲突崩溃
- 文件服务器URL集中管理:file-server.ts消除8+处硬编码端口
- Sidebar设置面板:添加服务器/自动连接/自动刷新开关
- 修复:validateFilePath越界panic、正则预编译
- 修复:注释准确性(RemoveAll/端口8073/动态端口文档)
2026-05-04 15:33:19 +08:00

154 lines
3.7 KiB
Go

package handler
import (
"fmt"
"net/http"
"os"
"runtime"
"strings"
"u-desk/internal/agent/model"
"github.com/labstack/echo/v4"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/disk"
"github.com/shirou/gopsutil/v3/mem"
)
// Ping 健康检查
func (h *Handler) Ping(c echo.Context) error {
return c.JSON(http.StatusOK, model.OK(map[string]string{
"status": "ok",
}))
}
// Info 返回 Agent 信息
func (h *Handler) Info(c echo.Context) error {
hostname, _ := os.Hostname()
return c.JSON(http.StatusOK, model.OK(map[string]interface{}{
"version": "0.1.0",
"os": runtime.GOOS,
"arch": runtime.GOARCH,
"hostname": hostname,
}))
}
// CommonPaths 返回常用系统路径
func (h *Handler) CommonPaths(c echo.Context) error {
paths := map[string]string{}
home, _ := os.UserHomeDir()
if home != "" {
paths["home"] = home
paths["desktop"] = home + "/Desktop"
paths["documents"] = home + "/Documents"
paths["downloads"] = home + "/Downloads"
}
// 根据平台添加盘符/根路径
if runtime.GOOS == "windows" {
for _, drive := range "ABCDEFGHIJKLMNOPQRSTUVWXYZ" {
_, err := os.Stat(string(drive) + ":\\")
if err == nil {
paths["drive_"+strings.ToLower(string(drive))] = string(drive) + ":\\"
}
}
} else {
paths["root"] = "/"
_, err := os.Stat("/home")
if err == nil {
paths["users"] = "/home"
}
}
return c.JSON(http.StatusOK, model.OK(paths))
}
// Drives 返回可用磁盘列表
func (h *Handler) Drives(c echo.Context) error {
type DriveInfo struct {
Name string `json:"name"`
Path string `json:"path"`
FsType string `json:"fs_type,omitempty"`
Total uint64 `json:"total"`
Free uint64 `json:"free"`
}
var drives []DriveInfo
if runtime.GOOS == "windows" {
for _, drive := range "ABCDEFGHIJKLMNOPQRSTUVWXYZ" {
drivePath := string(drive) + ":\\"
if _, err := os.Stat(drivePath); err != nil {
continue
}
drives = append(drives, DriveInfo{
Name: strings.ToLower(string(drive)),
Path: drivePath,
Total: 0,
Free: 0,
})
}
} else {
parts, err := os.ReadDir("/")
if err == nil {
for _, p := range parts {
name := p.Name()
if len(name) == 2 && name[0] != '.' && name[1] != '.' && p.IsDir() {
// 可能是挂载点
fullPath := "/" + name
if stat, err := os.Stat(fullPath); err == nil && stat.IsDir() {
drives = append(drives, DriveInfo{
Name: name,
Path: fullPath,
})
_ = stat
}
}
}
}
// 至少返回根目录
if len(drives) == 0 {
drives = append(drives, DriveInfo{Name: "/", Path: "/"})
}
}
return c.JSON(http.StatusOK, model.OK(drives))
}
// Stats 返回系统资源使用统计(CPU/内存/磁盘)
func (h *Handler) Stats(c echo.Context) error {
info := make(map[string]interface{})
// CPU
if cores, err := cpu.Counts(true); err == nil {
info["cpu_cores"] = cores
}
if percents, err := cpu.Percent(0, false); err == nil && len(percents) > 0 {
info["cpu_usage"] = fmt.Sprintf("%.0f%%", percents[0])
}
// 内存
if memInfo, err := mem.VirtualMemory(); err == nil {
info["mem_total"] = memInfo.Total
info["mem_used"] = memInfo.Used
info["mem_usage"] = fmt.Sprintf("%.0f%%", memInfo.UsedPercent)
}
// 磁盘(取根分区)
if partitions, err := disk.Partitions(false); err == nil {
for _, p := range partitions {
if p.Mountpoint == "/" || (runtime.GOOS == "windows" && len(p.Mountpoint) == 3 && p.Mountpoint[1] == ':') {
if usage, err := disk.Usage(p.Mountpoint); err == nil {
info["disk_total"] = usage.Total
info["disk_used"] = usage.Used
info["disk_usage"] = fmt.Sprintf("%.0f%%", usage.UsedPercent)
}
break
}
}
}
return c.JSON(http.StatusOK, model.OK(info))
}