Improve portable launch, forge persistence, and operator auth UX.
Persist build extra_files for Build Manager history, print dashboard login on every start, add libp2p for Mesh P2P forge, defer WebSocket until login, and split devrun.bat from LAUNCH.bat with USB deck auto-detection.
This commit is contained in:
@@ -17,6 +17,20 @@ func filetimeToUint64(ft filetime) uint64 {
|
||||
return (uint64(ft.HighDateTime) << 32) | uint64(ft.LowDateTime)
|
||||
}
|
||||
|
||||
func cpuBusyPercentFromDeltas(idleDelta, totalDelta float64) float64 {
|
||||
if totalDelta <= 0 {
|
||||
return 0
|
||||
}
|
||||
busyPct := (1.0 - idleDelta/totalDelta) * 100
|
||||
if busyPct < 0 {
|
||||
return 0
|
||||
}
|
||||
if busyPct > 100 {
|
||||
return 100
|
||||
}
|
||||
return busyPct
|
||||
}
|
||||
|
||||
func (r *Reporter) SystemCPUPercent() float64 {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
@@ -49,15 +63,5 @@ func (r *Reporter) SystemCPUPercent() float64 {
|
||||
r.lastKernel = kernelTicks
|
||||
r.lastUser = userTicks
|
||||
|
||||
if totalDelta <= 0 {
|
||||
return 0
|
||||
}
|
||||
busyPct := (1.0 - idleDelta/totalDelta) * 100
|
||||
if busyPct < 0 {
|
||||
return 0
|
||||
}
|
||||
if busyPct > 100 {
|
||||
return 100
|
||||
}
|
||||
return busyPct
|
||||
return cpuBusyPercentFromDeltas(idleDelta, totalDelta)
|
||||
}
|
||||
|
||||
35
agent/stats/cpu_windows_test.go
Normal file
35
agent/stats/cpu_windows_test.go
Normal file
@@ -0,0 +1,35 @@
|
||||
//go:build windows
|
||||
|
||||
package stats
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestFiletimeToUint64(t *testing.T) {
|
||||
ft := filetime{LowDateTime: 0xDEADBEEF, HighDateTime: 0x00001234}
|
||||
want := (uint64(0x1234) << 32) | 0xDEADBEEF
|
||||
if got := filetimeToUint64(ft); got != want {
|
||||
t.Fatalf("got %x want %x", got, want)
|
||||
}
|
||||
if filetimeToUint64(filetime{}) != 0 {
|
||||
t.Fatal("zero filetime should be 0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCPUBusyPercentFromDeltas(t *testing.T) {
|
||||
tests := []struct {
|
||||
idle, total float64
|
||||
want float64
|
||||
}{
|
||||
{idle: 25, total: 100, want: 75},
|
||||
{idle: 0, total: 100, want: 100},
|
||||
{idle: 100, total: 100, want: 0},
|
||||
{idle: 0, total: 0, want: 0},
|
||||
{idle: -10, total: 50, want: 100}, // over 100% busy clamped
|
||||
{idle: 200, total: 100, want: 0}, // negative busy clamped to 0
|
||||
}
|
||||
for _, tc := range tests {
|
||||
if got := cpuBusyPercentFromDeltas(tc.idle, tc.total); got != tc.want {
|
||||
t.Fatalf("idle=%v total=%v: got %v want %v", tc.idle, tc.total, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,17 +18,24 @@ func (r *Reporter) memoryStatus() (total, avail uint64) {
|
||||
if err != nil {
|
||||
return total, total / 2
|
||||
}
|
||||
// Rough available estimate from vm_stat free pages
|
||||
var pageSize uint64 = 4096
|
||||
var freePages uint64
|
||||
for _, line := range strings.Split(string(out), "\n") {
|
||||
avail = parseVmStatFreeBytes(string(out))
|
||||
return total, avail
|
||||
}
|
||||
|
||||
func parseVmStatFreeBytes(out string) uint64 {
|
||||
const pageSize uint64 = 4096
|
||||
return parseVmStatFreePages(out) * pageSize
|
||||
}
|
||||
|
||||
func parseVmStatFreePages(out string) uint64 {
|
||||
for _, line := range strings.Split(out, "\n") {
|
||||
if strings.Contains(line, "Pages free") {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) >= 3 {
|
||||
freePages, _ = strconv.ParseUint(strings.Trim(parts[2], "."), 10, 64)
|
||||
v, _ := strconv.ParseUint(strings.Trim(parts[2], "."), 10, 64)
|
||||
return v
|
||||
}
|
||||
}
|
||||
}
|
||||
avail = freePages * pageSize
|
||||
return total, avail
|
||||
return 0
|
||||
}
|
||||
|
||||
25
agent/stats/reporter_darwin_test.go
Normal file
25
agent/stats/reporter_darwin_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
//go:build darwin
|
||||
|
||||
package stats
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestParseVmStatFreePages(t *testing.T) {
|
||||
out := `Mach Virtual Memory Statistics: (page size of 4096 bytes)
|
||||
Pages free: 12345.
|
||||
Pages active: 67890.
|
||||
`
|
||||
if got := parseVmStatFreePages(out); got != 12345 {
|
||||
t.Fatalf("got %d", got)
|
||||
}
|
||||
if parseVmStatFreePages("no free pages here") != 0 {
|
||||
t.Fatal("missing line should return 0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseVmStatFreeBytes(t *testing.T) {
|
||||
out := "Pages free: 1000.\n"
|
||||
if got := parseVmStatFreeBytes(out); got != 1000*4096 {
|
||||
t.Fatalf("got %d", got)
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ package stats
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -15,8 +16,12 @@ func (r *Reporter) memoryStatus() (total, avail uint64) {
|
||||
return 0, 0
|
||||
}
|
||||
defer f.Close()
|
||||
return parseMeminfo(f)
|
||||
}
|
||||
|
||||
func parseMeminfo(r io.Reader) (total, avail uint64) {
|
||||
var memTotal, memAvail uint64
|
||||
sc := bufio.NewScanner(f)
|
||||
sc := bufio.NewScanner(r)
|
||||
for sc.Scan() {
|
||||
line := sc.Text()
|
||||
if strings.HasPrefix(line, "MemTotal:") {
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
package stats
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseKB(t *testing.T) {
|
||||
if got := parseKB("MemTotal: 16384000 kB"); got != 16384000 {
|
||||
@@ -11,4 +14,30 @@ func TestParseKB(t *testing.T) {
|
||||
if parseKB("short") != 0 {
|
||||
t.Fatal("invalid line should return 0")
|
||||
}
|
||||
if parseKB("MemAvailable: 0 kB") != 0 {
|
||||
t.Fatal("zero kB should parse as 0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMeminfo(t *testing.T) {
|
||||
content := strings.Join([]string{
|
||||
"MemTotal: 16384000 kB",
|
||||
"MemFree: 8192000 kB",
|
||||
"MemAvailable: 4096000 kB",
|
||||
}, "\n")
|
||||
total, avail := parseMeminfo(strings.NewReader(content))
|
||||
if total != 16384000*1024 {
|
||||
t.Fatalf("total %d", total)
|
||||
}
|
||||
if avail != 4096000*1024 {
|
||||
t.Fatalf("avail %d", avail)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMeminfoMissingTotal(t *testing.T) {
|
||||
content := "MemAvailable: 4096000 kB\n"
|
||||
total, avail := parseMeminfo(strings.NewReader(content))
|
||||
if total != 0 || avail != 0 {
|
||||
t.Fatalf("missing MemTotal: total=%d avail=%d", total, avail)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user