- Add workflow filter to clear-cancelled, clear-failed, clear-running, clear-old-success
- Add any option to AI Learning runner type filter
- Fix ServerStats int64 types for FileSize template function
- Add CPULoad field with platform-specific implementations
- Fix actions list template with conditional button visibility
- Use Gitea styled modal dialogs for all clear buttons
🤖 Generated with Claude Code
116 lines
2.4 KiB
Go
116 lines
2.4 KiB
Go
// Copyright 2026 MarketAlly. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package admin
|
|
|
|
import (
|
|
"os"
|
|
"runtime"
|
|
"time"
|
|
)
|
|
|
|
// ServerStats holds server system statistics
|
|
type ServerStats struct {
|
|
CPULoad float64
|
|
NumCPU int
|
|
NumGoroutine int
|
|
MemTotal int64
|
|
MemUsed int64
|
|
MemPercent float64
|
|
DiskTotal int64
|
|
DiskUsed int64
|
|
DiskFree int64
|
|
DiskPercent float64
|
|
Uptime time.Duration
|
|
StartTime time.Time
|
|
Status string
|
|
}
|
|
|
|
var serverStartTime = time.Now()
|
|
|
|
// GetServerStats collects current server statistics
|
|
func GetServerStats() *ServerStats {
|
|
stats := &ServerStats{
|
|
NumCPU: runtime.NumCPU(),
|
|
NumGoroutine: runtime.NumGoroutine(),
|
|
StartTime: serverStartTime,
|
|
Uptime: time.Since(serverStartTime),
|
|
Status: "healthy",
|
|
CPULoad: getCPULoad(),
|
|
}
|
|
|
|
// Memory stats from runtime
|
|
var m runtime.MemStats
|
|
runtime.ReadMemStats(&m)
|
|
stats.MemUsed = int64(m.Alloc)
|
|
stats.MemTotal = int64(m.Sys)
|
|
if stats.MemTotal > 0 {
|
|
stats.MemPercent = float64(stats.MemUsed) / float64(stats.MemTotal) * 100
|
|
}
|
|
|
|
// Disk stats - try to get for root or current working directory
|
|
diskPath := "/"
|
|
if runtime.GOOS == "windows" {
|
|
diskPath = "C:\\"
|
|
}
|
|
|
|
if stat, err := getDiskUsage(diskPath); err == nil {
|
|
stats.DiskTotal = int64(stat.Total)
|
|
stats.DiskUsed = int64(stat.Used)
|
|
stats.DiskFree = int64(stat.Free)
|
|
if stats.DiskTotal > 0 {
|
|
stats.DiskPercent = float64(stats.DiskUsed) / float64(stats.DiskTotal) * 100
|
|
}
|
|
}
|
|
|
|
return stats
|
|
}
|
|
|
|
type diskUsage struct {
|
|
Total uint64
|
|
Free uint64
|
|
Used uint64
|
|
}
|
|
|
|
// FormatBytes formats bytes to human readable string
|
|
func FormatBytes(bytes uint64) string {
|
|
const unit = 1024
|
|
if bytes < unit {
|
|
return formatBytesValue(bytes, "B")
|
|
}
|
|
div, exp := uint64(unit), 0
|
|
for n := bytes / unit; n >= unit; n /= unit {
|
|
div *= unit
|
|
exp++
|
|
}
|
|
units := []string{"KB", "MB", "GB", "TB", "PB"}
|
|
return formatBytesValue(bytes/div, units[exp])
|
|
}
|
|
|
|
func formatBytesValue(val uint64, unit string) string {
|
|
if val < 10 {
|
|
return string(rune('0'+val)) + " " + unit
|
|
}
|
|
return formatUint(val) + " " + unit
|
|
}
|
|
|
|
func formatUint(n uint64) string {
|
|
if n == 0 {
|
|
return "0"
|
|
}
|
|
var buf [20]byte
|
|
i := len(buf)
|
|
for n > 0 {
|
|
i--
|
|
buf[i] = byte('0' + n%10)
|
|
n /= 10
|
|
}
|
|
return string(buf[i:])
|
|
}
|
|
|
|
// Expose to templates
|
|
func init() {
|
|
// Register template function if needed
|
|
_ = os.Getenv("HOME") // Just to use os package
|
|
}
|