Compare commits
9 Commits
2377530fab
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 095f2845f6 | |||
| 2f6bea41d5 | |||
| 5ef7937d3c | |||
| b412b8f9d1 | |||
| 9bdc92252e | |||
| 62143a5a32 | |||
| 2c103af9d8 | |||
| d39713a196 | |||
| 8f1325800c |
+123
-87
@@ -143,12 +143,16 @@ type GPUInfo struct {
|
|||||||
MemClock float64 `json:"mem_clock_mhz"`
|
MemClock float64 `json:"mem_clock_mhz"`
|
||||||
Power float64 `json:"power"`
|
Power float64 `json:"power"`
|
||||||
PowerLimit float64 `json:"power_limit"`
|
PowerLimit float64 `json:"power_limit"`
|
||||||
|
PowerMax float64 `json:"power_max"`
|
||||||
FanSpeed float64 `json:"fan_speed"`
|
FanSpeed float64 `json:"fan_speed"`
|
||||||
PState string `json:"pstate"`
|
PState string `json:"pstate"`
|
||||||
Persistence string `json:"persistence_mode"`
|
|
||||||
ComputeMode string `json:"compute_mode"`
|
ComputeMode string `json:"compute_mode"`
|
||||||
DriverVersion string `json:"driver_version"`
|
DriverVersion string `json:"driver_version"`
|
||||||
CudaVersion string `json:"cuda_version"`
|
UtilMemory float64 `json:"util_memory"`
|
||||||
|
UtilEncoder float64 `json:"util_encoder"`
|
||||||
|
UtilDecoder float64 `json:"util_decoder"`
|
||||||
|
ClocksMaxGfx float64 `json:"clocks_max_graphics"`
|
||||||
|
ClocksMaxMem float64 `json:"clocks_max_memory"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════
|
// ═══════════════════════════════════════════════
|
||||||
@@ -549,7 +553,8 @@ func (m model) viewMonitor() string {
|
|||||||
if tw < 60 {
|
if tw < 60 {
|
||||||
tw = 60
|
tw = 60
|
||||||
}
|
}
|
||||||
innerW := tw - 4
|
gap := 2
|
||||||
|
halfW := (tw - gap) / 2
|
||||||
|
|
||||||
// ── 顶栏 ──
|
// ── 顶栏 ──
|
||||||
wsDot := "○"
|
wsDot := "○"
|
||||||
@@ -569,23 +574,28 @@ func (m model) viewMonitor() string {
|
|||||||
)
|
)
|
||||||
sep := stDim.Render(strings.Repeat("─", tw))
|
sep := stDim.Render(strings.Repeat("─", tw))
|
||||||
|
|
||||||
// ── 内容:全部垂直排列 ──
|
// ── 第一行: CPU + Memory ──
|
||||||
cpuBox := m.viewCPUBox(innerW)
|
cpuBox := m.viewCPUBox(halfW - 4)
|
||||||
memBox := m.viewMemBox(innerW)
|
memBox := m.viewMemBox(halfW - 4)
|
||||||
histBox := m.viewHistBox(innerW)
|
row1 := lipgloss.JoinHorizontal(lipgloss.Top,
|
||||||
gpuBox := m.viewGPUBox(innerW)
|
cpuBox, strings.Repeat(" ", gap), memBox,
|
||||||
|
)
|
||||||
|
|
||||||
|
// ── 第二行: GPU + History ──
|
||||||
|
gpuBox := m.viewGPUBox(halfW - 4)
|
||||||
|
histBox := m.viewHistBox(halfW - 4)
|
||||||
|
row2 := lipgloss.JoinHorizontal(lipgloss.Top,
|
||||||
|
gpuBox, strings.Repeat(" ", gap), histBox,
|
||||||
|
)
|
||||||
|
|
||||||
full := lipgloss.JoinVertical(lipgloss.Left,
|
full := lipgloss.JoinVertical(lipgloss.Left,
|
||||||
header, sep, "",
|
header, sep, "",
|
||||||
cpuBox, "",
|
row1, "",
|
||||||
memBox, "",
|
row2, "",
|
||||||
histBox, "",
|
|
||||||
gpuBox, "",
|
|
||||||
sep,
|
sep,
|
||||||
stDim.Render(" q 退出 · r 重新配置 · 连接: "+m.cfg.Server),
|
stDim.Render(" q 退出 · r 重新配置 · 连接: "+m.cfg.Server),
|
||||||
)
|
)
|
||||||
|
|
||||||
// 截断到终端高度,防止滚动
|
|
||||||
lines := strings.Split(full, "\n")
|
lines := strings.Split(full, "\n")
|
||||||
if len(lines) > m.h {
|
if len(lines) > m.h {
|
||||||
lines = lines[:m.h]
|
lines = lines[:m.h]
|
||||||
@@ -599,40 +609,38 @@ func (m model) viewCPUBox(innerW int) string {
|
|||||||
c := m.cpu
|
c := m.cpu
|
||||||
pct := c.UsageTotal
|
pct := c.UsageTotal
|
||||||
|
|
||||||
// 标题
|
|
||||||
modelName := c.Model
|
modelName := c.Model
|
||||||
maxNameW := innerW - 10
|
maxNameW := innerW - 8
|
||||||
if len(modelName) > maxNameW && maxNameW > 3 {
|
if len(modelName) > maxNameW && maxNameW > 3 {
|
||||||
modelName = modelName[:maxNameW-1] + "…"
|
modelName = modelName[:maxNameW-1] + "…"
|
||||||
}
|
}
|
||||||
titleLine := stTitle.Render("CPU") + " " + stFg.Render(modelName)
|
|
||||||
|
|
||||||
// 百分比进度条
|
// 标题 + 核心/频率/温度 一行
|
||||||
|
coresStr := fmt.Sprintf("%dC/%dT", c.CoresPhysical, c.CoresLogical)
|
||||||
|
freqStr := fmt.Sprintf("%.0fMHz", c.FreqMHz)
|
||||||
|
tempStr := tempText(c.Temperature)
|
||||||
|
titleLine := lipgloss.JoinHorizontal(lipgloss.Left,
|
||||||
|
stTitle.Render("CPU"),
|
||||||
|
" ", stFg.Render(modelName),
|
||||||
|
" ", stLabel.Render(coresStr),
|
||||||
|
" ", stVal.Render(freqStr),
|
||||||
|
" ", tempStyle(c.Temperature).Render(tempStr),
|
||||||
|
)
|
||||||
|
|
||||||
|
// 进度条 + 百分比 一行
|
||||||
barW := innerW - 8
|
barW := innerW - 8
|
||||||
if barW < 10 {
|
if barW < 10 {
|
||||||
barW = 10
|
barW = 10
|
||||||
}
|
}
|
||||||
bar := renderBar(pct, barW)
|
bar := renderBar(pct, barW)
|
||||||
pctStr := pctStyle(pct).Bold(true).Render(fmt.Sprintf("%5.1f%%", pct))
|
pctStr := pctStyle(pct).Bold(true).Render(fmt.Sprintf("%.1f%%", pct))
|
||||||
barLine := lipgloss.JoinHorizontal(lipgloss.Center, bar, " ", pctStr)
|
barLine := lipgloss.JoinHorizontal(lipgloss.Center, bar, " ", pctStr)
|
||||||
|
|
||||||
// 信息行
|
|
||||||
coresStr := fmt.Sprintf("%dC/%dT", c.CoresPhysical, c.CoresLogical)
|
|
||||||
freqStr := fmt.Sprintf("%.0f MHz", c.FreqMHz)
|
|
||||||
tempStr := tempText(c.Temperature)
|
|
||||||
infoLine := lipgloss.JoinHorizontal(lipgloss.Left,
|
|
||||||
stLabel.Render("核心 "), stVal.Render(coresStr),
|
|
||||||
" ",
|
|
||||||
stLabel.Render("频率 "), stVal.Render(freqStr),
|
|
||||||
" ",
|
|
||||||
stLabel.Render("温度 "), tempStyle(c.Temperature).Render(tempStr),
|
|
||||||
)
|
|
||||||
|
|
||||||
// 核心热力图
|
// 核心热力图
|
||||||
coreLine := m.viewCoreHeatmap(innerW)
|
coreLine := m.viewCoreHeatmap(innerW)
|
||||||
|
|
||||||
body := lipgloss.JoinVertical(lipgloss.Left,
|
body := lipgloss.JoinVertical(lipgloss.Left,
|
||||||
titleLine, "", barLine, infoLine, "", coreLine,
|
titleLine, barLine, coreLine,
|
||||||
)
|
)
|
||||||
return stBox.Width(innerW + 4).Render(body)
|
return stBox.Width(innerW + 4).Render(body)
|
||||||
}
|
}
|
||||||
@@ -671,10 +679,16 @@ func (m model) viewCoreHeatmap(innerW int) string {
|
|||||||
func (m model) viewMemBox(innerW int) string {
|
func (m model) viewMemBox(innerW int) string {
|
||||||
pct := m.mem.Percent
|
pct := m.mem.Percent
|
||||||
|
|
||||||
titleLine := stTitle.Render("MEMORY")
|
usedGB := fmtBytes(m.mem.UsedBytes)
|
||||||
|
totalGB := fmtBytes(m.mem.TotalBytes)
|
||||||
|
|
||||||
// 百分比
|
// 标题 + 详情 一行
|
||||||
pctStr := pctStyle(pct).Bold(true).Render(fmt.Sprintf("%.1f%%", pct))
|
titleLine := lipgloss.JoinHorizontal(lipgloss.Left,
|
||||||
|
stTitle.Render("MEMORY"),
|
||||||
|
" ", stLabel.Render("已用 "), stVal.Render(usedGB),
|
||||||
|
" / ", stVal.Render(totalGB),
|
||||||
|
" ", pctStyle(pct).Bold(true).Render(fmt.Sprintf("%.1f%%", pct)),
|
||||||
|
)
|
||||||
|
|
||||||
// 进度条
|
// 进度条
|
||||||
barW := innerW - 8
|
barW := innerW - 8
|
||||||
@@ -682,19 +696,10 @@ func (m model) viewMemBox(innerW int) string {
|
|||||||
barW = 10
|
barW = 10
|
||||||
}
|
}
|
||||||
bar := renderBar(pct, barW)
|
bar := renderBar(pct, barW)
|
||||||
barLine := lipgloss.JoinHorizontal(lipgloss.Center, bar, " ", pctStr)
|
barLine := lipgloss.JoinHorizontal(lipgloss.Center, bar)
|
||||||
|
|
||||||
// 详情
|
|
||||||
usedGB := fmtBytes(m.mem.UsedBytes)
|
|
||||||
totalGB := fmtBytes(m.mem.TotalBytes)
|
|
||||||
detailLine := lipgloss.JoinHorizontal(lipgloss.Left,
|
|
||||||
stLabel.Render("已用 "), stVal.Render(usedGB),
|
|
||||||
" ",
|
|
||||||
stLabel.Render("总计 "), stVal.Render(totalGB),
|
|
||||||
)
|
|
||||||
|
|
||||||
body := lipgloss.JoinVertical(lipgloss.Left,
|
body := lipgloss.JoinVertical(lipgloss.Left,
|
||||||
titleLine, "", pctStr, barLine, "", detailLine,
|
titleLine, barLine,
|
||||||
)
|
)
|
||||||
return stBox.Width(innerW + 4).Render(body)
|
return stBox.Width(innerW + 4).Render(body)
|
||||||
}
|
}
|
||||||
@@ -976,6 +981,9 @@ func collectLoop(done <-chan struct{}, wsURL, name string, interval time.Duratio
|
|||||||
case dataCh <- data:
|
case dataCh <- data:
|
||||||
default: // 满了就丢弃
|
default: // 满了就丢弃
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 每 10 轮触发一次 GC,减少内存占用
|
||||||
|
runtime.GC()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1160,28 +1168,62 @@ func collectGPUs() []GPUInfo {
|
|||||||
if len(gpus) > 0 {
|
if len(gpus) > 0 {
|
||||||
return gpus
|
return gpus
|
||||||
}
|
}
|
||||||
return tryWMIGPU()
|
wmi := tryWMIGPU()
|
||||||
|
return filterPCIeGPUs(wmi)
|
||||||
case "linux":
|
case "linux":
|
||||||
gpus := tryNvidiaSMI()
|
gpus := tryNvidiaSMI()
|
||||||
if len(gpus) > 0 {
|
if len(gpus) > 0 {
|
||||||
return gpus
|
return gpus
|
||||||
}
|
}
|
||||||
return tryLinuxGPU()
|
lspci := tryLinuxGPU()
|
||||||
|
return filterPCIeGPUs(lspci)
|
||||||
case "darwin":
|
case "darwin":
|
||||||
gpus := tryNvidiaSMI()
|
gpus := tryNvidiaSMI()
|
||||||
if len(gpus) > 0 {
|
mac := tryMacGPU()
|
||||||
return gpus
|
return filterPCIeGPUs(append(gpus, mac...))
|
||||||
}
|
|
||||||
return tryMacGPU()
|
|
||||||
}
|
}
|
||||||
return tryNvidiaSMI()
|
return tryNvidiaSMI()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func filterPCIeGPUs(gpus []GPUInfo) []GPUInfo {
|
||||||
|
var result []GPUInfo
|
||||||
|
for _, g := range gpus {
|
||||||
|
if !isVirtualGPU(g.Name) {
|
||||||
|
result = append(result, g)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func isVirtualGPU(name string) bool {
|
||||||
|
name = strings.ToLower(name)
|
||||||
|
blacklist := []string{
|
||||||
|
"microsoft", "basic render", "vmware", "virtual", "hyper-v",
|
||||||
|
"parallels", "virtualbox", "intel", "remote", "rdp", "citrix",
|
||||||
|
"teamviewer", "anydesk", "parsec", "splashtop", "oray",
|
||||||
|
"sunlogin", "todesk", "amdgpu-pro",
|
||||||
|
}
|
||||||
|
for _, v := range blacklist {
|
||||||
|
if strings.Contains(name, v) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func tryNvidiaSMI() []GPUInfo {
|
func tryNvidiaSMI() []GPUInfo {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
out, err := exec.CommandContext(ctx, "nvidia-smi",
|
out, err := exec.CommandContext(ctx, "nvidia-smi",
|
||||||
"--query-gpu=index,name,memory.total,memory.used,memory.free,temperature.gpu,utilization.gpu,clocks.current.graphics,clocks.current.memory,power.draw,power.limit,fan.speed,pstate,persistence_mode,compute_mode,driver_version,cuda_version",
|
"--query-gpu=index,name,uuid,pci.bus_id,driver_version,vbios_version,"+
|
||||||
|
"temperature.gpu,temperature.memory,fan.speed,"+
|
||||||
|
"power.draw,power.limit,power.default_limit,power.min_limit,power.max_limit,"+
|
||||||
|
"clocks.current.graphics,clocks.current.sm,clocks.current.memory,"+
|
||||||
|
"clocks.max.graphics,clocks.max.memory,"+
|
||||||
|
"utilization.gpu,utilization.memory,utilization.encoder,utilization.decoder,"+
|
||||||
|
"memory.total,memory.used,memory.free,"+
|
||||||
|
"ecc.errors.corrected.volatile.total,ecc.errors.uncorrected.volatile.total,"+
|
||||||
|
"compute_mode,pstate",
|
||||||
"--format=csv,noheader,nounits",
|
"--format=csv,noheader,nounits",
|
||||||
).Output()
|
).Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1190,7 +1232,7 @@ func tryNvidiaSMI() []GPUInfo {
|
|||||||
var gpus []GPUInfo
|
var gpus []GPUInfo
|
||||||
for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {
|
for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {
|
||||||
parts := strings.Split(line, ",")
|
parts := strings.Split(line, ",")
|
||||||
if len(parts) < 9 {
|
if len(parts) < 24 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for i := range parts {
|
for i := range parts {
|
||||||
@@ -1198,40 +1240,34 @@ func tryNvidiaSMI() []GPUInfo {
|
|||||||
parts[i] = strings.Trim(parts[i], "[]")
|
parts[i] = strings.Trim(parts[i], "[]")
|
||||||
}
|
}
|
||||||
|
|
||||||
g := GPUInfo{
|
// 0:index 1:name 2:uuid 3:bus_id 4:driver 5:vbios
|
||||||
Name: parts[1],
|
// 6:temp_gpu 7:temp_mem 8:fan 9:power 10:power_limit
|
||||||
VRAMTotalMB: parseFloat(parts[2]),
|
// 11:power_default 12:power_min 13:power_max
|
||||||
VRAMUsedMB: parseFloat(parts[3]),
|
// 14:clk_gfx 15:clk_sm 16:clk_mem 17:clk_max_gfx 18:clk_max_mem
|
||||||
Temperature: parseFloat(parts[5]),
|
// 19:util_gpu 20:util_mem 21:util_enc 22:util_dec
|
||||||
LoadPercent: parseFloat(parts[6]),
|
// 23:vram_total 24:vram_used 25:vram_free
|
||||||
CoreClock: parseFloat(parts[7]),
|
// 26:ecc_corr 27:ecc_uncorr 28:compute_mode 29:pstate
|
||||||
MemClock: parseFloat(parts[8]),
|
gpus = append(gpus, GPUInfo{
|
||||||
}
|
Name: cleanStr(parts[1]),
|
||||||
if len(parts) > 9 {
|
DriverVersion: cleanStr(parts[4]),
|
||||||
g.Power = parseFloatSafe(parts[9])
|
Temperature: parseFloat(parts[6]),
|
||||||
}
|
FanSpeed: parseFloat(parts[8]),
|
||||||
if len(parts) > 10 {
|
Power: parseFloat(parts[9]),
|
||||||
g.PowerLimit = parseFloatSafe(parts[10])
|
PowerLimit: parseFloat(parts[10]),
|
||||||
}
|
PowerMax: parseFloat(parts[13]),
|
||||||
if len(parts) > 11 {
|
CoreClock: parseFloat(parts[14]),
|
||||||
g.FanSpeed = parseFloatSafe(parts[11])
|
MemClock: parseFloat(parts[16]),
|
||||||
}
|
ClocksMaxGfx: parseFloat(parts[17]),
|
||||||
if len(parts) > 12 {
|
ClocksMaxMem: parseFloat(parts[18]),
|
||||||
g.PState = cleanStr(parts[12])
|
LoadPercent: parseFloat(parts[19]),
|
||||||
}
|
UtilMemory: parseFloat(parts[20]),
|
||||||
if len(parts) > 13 {
|
UtilEncoder: parseFloat(parts[21]),
|
||||||
g.Persistence = cleanStr(parts[13])
|
UtilDecoder: parseFloat(parts[22]),
|
||||||
}
|
VRAMTotalMB: parseFloat(parts[23]),
|
||||||
if len(parts) > 14 {
|
VRAMUsedMB: parseFloat(parts[24]),
|
||||||
g.ComputeMode = cleanStr(parts[14])
|
ComputeMode: cleanStr(parts[28]),
|
||||||
}
|
PState: cleanStr(parts[29]),
|
||||||
if len(parts) > 15 {
|
})
|
||||||
g.DriverVersion = cleanStr(parts[15])
|
|
||||||
}
|
|
||||||
if len(parts) > 16 {
|
|
||||||
g.CudaVersion = cleanStr(parts[16])
|
|
||||||
}
|
|
||||||
gpus = append(gpus, g)
|
|
||||||
}
|
}
|
||||||
return gpus
|
return gpus
|
||||||
}
|
}
|
||||||
|
|||||||
+82
-15
@@ -11,6 +11,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -374,6 +375,72 @@ func (h *Hub) saveYAML() {
|
|||||||
os.WriteFile(h.devicesAbs, append([]byte(hdr), out...), 0644)
|
os.WriteFile(h.devicesAbs, append([]byte(hdr), out...), 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func filterGPURaw(raw json.RawMessage) json.RawMessage {
|
||||||
|
var data map[string]interface{}
|
||||||
|
if json.Unmarshal(raw, &data) != nil {
|
||||||
|
return raw
|
||||||
|
}
|
||||||
|
gpusRaw, ok := data["gpus"]
|
||||||
|
if !ok {
|
||||||
|
return raw
|
||||||
|
}
|
||||||
|
gpus, ok := gpusRaw.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
return raw
|
||||||
|
}
|
||||||
|
var filtered []interface{}
|
||||||
|
for _, g := range gpus {
|
||||||
|
gpu, ok := g.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
gpuName, _ := gpu["name"].(string)
|
||||||
|
if isVirtualGPU(gpuName) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
filtered = append(filtered, g)
|
||||||
|
}
|
||||||
|
data["gpus"] = filtered
|
||||||
|
out, _ := json.Marshal(data)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func isVirtualGPU(name string) bool {
|
||||||
|
name = strings.ToLower(name)
|
||||||
|
blacklist := []string{
|
||||||
|
"microsoft",
|
||||||
|
"basic render",
|
||||||
|
"vmware",
|
||||||
|
"virtual",
|
||||||
|
"hyper-v",
|
||||||
|
"parallels",
|
||||||
|
"virtualbox",
|
||||||
|
"intel uhd",
|
||||||
|
"intel iris",
|
||||||
|
"intel(r) uhd",
|
||||||
|
"intel(r) iris",
|
||||||
|
"uhd graphics",
|
||||||
|
"iris graphics",
|
||||||
|
"remote",
|
||||||
|
"rdp",
|
||||||
|
"citrix",
|
||||||
|
"teamviewer",
|
||||||
|
"anydesk",
|
||||||
|
"parsec",
|
||||||
|
"splashtop",
|
||||||
|
"amdgpu-pro",
|
||||||
|
"oray",
|
||||||
|
"sunlogin",
|
||||||
|
"todesk",
|
||||||
|
}
|
||||||
|
for _, v := range blacklist {
|
||||||
|
if strings.Contains(name, v) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Hub) UpdateDevice(raw json.RawMessage) {
|
func (h *Hub) UpdateDevice(raw json.RawMessage) {
|
||||||
var p AgentPayload
|
var p AgentPayload
|
||||||
if json.Unmarshal(raw, &p) != nil || p.MachineName == "" {
|
if json.Unmarshal(raw, &p) != nil || p.MachineName == "" {
|
||||||
@@ -398,7 +465,7 @@ func (h *Hub) UpdateDevice(raw json.RawMessage) {
|
|||||||
rec.GPUs = append(rec.GPUs, GPURec{Name: g.Name, VRAM: g.VRAM})
|
rec.GPUs = append(rec.GPUs, GPURec{Name: g.Name, VRAM: g.VRAM})
|
||||||
}
|
}
|
||||||
cp := *rec
|
cp := *rec
|
||||||
h.live[name] = raw
|
h.live[name] = filterGPURaw(raw)
|
||||||
var md *MiningData
|
var md *MiningData
|
||||||
var hist []HashratePoint
|
var hist []HashratePoint
|
||||||
if m, ok := h.miningData[name]; ok {
|
if m, ok := h.miningData[name]; ok {
|
||||||
@@ -416,10 +483,23 @@ func (h *Hub) UpdateDevice(raw json.RawMessage) {
|
|||||||
h.saveYAML()
|
h.saveYAML()
|
||||||
h.broadcast(BrowserMsg{
|
h.broadcast(BrowserMsg{
|
||||||
Type: "device", Machine: name,
|
Type: "device", Machine: name,
|
||||||
Device: &BrowserDevice{Info: &cp, Live: raw, Online: true, Mining: md, History: hist},
|
Device: &BrowserDevice{Info: &cp, Live: filterGPURaw(raw), Online: true, Mining: md, History: hist},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Hub) DeleteDevice(name string) {
|
||||||
|
h.mu.Lock()
|
||||||
|
_, ok := h.records[name]
|
||||||
|
delete(h.records, name)
|
||||||
|
delete(h.live, name)
|
||||||
|
h.mu.Unlock()
|
||||||
|
if ok {
|
||||||
|
h.saveYAML()
|
||||||
|
h.broadcast(BrowserMsg{Type: "remove", Machine: name})
|
||||||
|
logInfo("delete", "%s", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Hub) MarkOffline(name string) {
|
func (h *Hub) MarkOffline(name string) {
|
||||||
h.mu.Lock()
|
h.mu.Lock()
|
||||||
_, had := h.live[name]
|
_, had := h.live[name]
|
||||||
@@ -449,19 +529,6 @@ func (h *Hub) MarkOffline(name string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Hub) DeleteDevice(name string) {
|
|
||||||
h.mu.Lock()
|
|
||||||
_, ok := h.records[name]
|
|
||||||
delete(h.records, name)
|
|
||||||
delete(h.live, name)
|
|
||||||
h.mu.Unlock()
|
|
||||||
if ok {
|
|
||||||
h.saveYAML()
|
|
||||||
h.broadcast(BrowserMsg{Type: "remove", Machine: name})
|
|
||||||
logInfo("delete", "%s", name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Hub) AddMonitor(c *websocket.Conn) {
|
func (h *Hub) AddMonitor(c *websocket.Conn) {
|
||||||
h.mu.Lock()
|
h.mu.Lock()
|
||||||
h.monitors[c] = struct{}{}
|
h.monitors[c] = struct{}{}
|
||||||
|
|||||||
+1595
-333
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user