goGoFetch/src/providers/systemstats.go
2026-06-25 18:59:32 +03:00

236 lines
5.1 KiB
Go

package providers
import (
"bufio"
"fmt"
"os"
"os/exec"
"path"
"regexp"
"strconv"
"strings"
"time"
)
var id, prettyName string
func GetDist() (string, string) {
f, _ := os.Open("/etc/os-release")
defer func(f *os.File) {
err := f.Close()
if err != nil {
fmt.Println("Error closing file:", err)
}
}(f)
s := bufio.NewScanner(f)
for s.Scan() {
t := s.Text()
if strings.HasPrefix(t, "ID=") {
id = strings.TrimPrefix(t, "ID=")
}
if strings.HasPrefix(t, "PRETTY_NAME=") {
prettyName = strings.TrimPrefix(t, "PRETTY_NAME=")
prettyName = strings.Trim(prettyName, "\"")
}
}
if id == "" && prettyName == "" {
return "unknown", "unknown"
}
return id, prettyName
}
func GetRam() string {
f, err := os.Open("/proc/meminfo")
if err != nil {
return "error"
}
var total, available int
s := bufio.NewScanner(f)
for s.Scan() {
line := s.Text()
if strings.HasPrefix(line, "MemTotal:") {
_, err2 := fmt.Sscanf(line, "MemTotal: %d kB", &total)
if err2 != nil {
return ""
}
}
if strings.HasPrefix(line, "MemAvailable:") {
_, err := fmt.Sscanf(line, "MemAvailable: %d kB", &available)
if err != nil {
return ""
}
}
}
totalMB := total / 1024
availableMB := available / 1024
usedMB := totalMB - availableMB
ram := fmt.Sprintf("%d / %d MiB", usedMB, totalMB)
ram = strings.TrimSpace(ram)
return ram
}
func GetCpu() string {
f, err := os.Open("/proc/cpuinfo")
if err != nil {
return "unknown"
}
var cpu string
s := bufio.NewScanner(f)
for s.Scan() {
line := s.Text()
if strings.HasPrefix(line, "model name") {
parts := strings.SplitN(line, ":", 2)
if len(parts) > 1 {
cpu := strings.TrimSpace(parts[1])
return cpu
}
}
}
return strings.TrimSpace(cpu)
}
func GetGpu() string {
out, err := exec.Command("sh", "-c", `lspci -mm | awk -F'"' '$2=="VGA compatible controller" || $2=="3D controller" || $2=="Display controller"'`).Output()
if err != nil || len(out) == 0 {
return "unknown GPU"
}
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
var gpus []string
for _, line := range lines {
re := regexp.MustCompile(`"([^"]+)"`)
matches := re.FindAllStringSubmatch(line, -1)
if len(matches) >= 3 {
vendor := matches[1][1]
device := matches[2][1]
cleaned := cleanGpuString(vendor + " " + device)
gpus = append(gpus, cleaned)
}
}
if len(gpus) > 0 {
return strings.Join(gpus, " / ")
}
return "GPU not found"
}
func cleanGpuString(raw string) string {
prettyNameRe := regexp.MustCompile(`\[(.*?)]`)
match := prettyNameRe.FindStringSubmatch(raw)
res := raw
if len(match) > 1 {
vendor := ""
if strings.Contains(strings.ToLower(raw), "nvidia") {
vendor = "NVIDIA "
}
if strings.Contains(strings.ToLower(raw), "intel") {
vendor = "Intel "
}
if strings.Contains(strings.ToLower(raw), "amd") {
vendor = "AMD "
}
res = vendor + match[1]
}
re := regexp.MustCompile(`\(.*?\)|\[.*?]`)
res = re.ReplaceAllString(res, "")
fluff := []string{"Corporation", "Controller", "VGA compatible", "3D", "Graphics", "Device"}
for _, word := range fluff {
res = strings.ReplaceAll(res, word, "")
}
return strings.Join(strings.Fields(res), " ")
}
func GetKernel() string {
out, err := os.ReadFile("/proc/version")
if err != nil {
return "unknown"
}
str := strings.TrimSpace(string(out))
str = strings.ReplaceAll(str, " version ", " ")
if idx := strings.Index(str, "("); idx != -1 {
str = str[:idx]
}
return strings.TrimSpace(str)
}
func GetHostname() string {
hostname, err := os.ReadFile("/etc/hostname")
if err != nil {
return "unknown"
}
username := os.Getenv("USER")
if username == "" {
username = os.Getenv("LOGNAME")
}
if username == "" {
return "unknown"
}
return fmt.Sprintf("%s@%s", username, strings.TrimSpace(string(hostname)))
}
func GetTerminal() string {
shellPID := os.Getppid()
out, err := exec.Command("ps", "-p", fmt.Sprint(shellPID), "-o", "ppid=").Output()
if err != nil {
return os.Getenv("TERM")
}
terminalPID := strings.TrimSpace(string(out))
nameOut, err := exec.Command("ps", "-p", terminalPID, "-o", "comm=").Output()
if err != nil {
return os.Getenv("TERM")
}
// those subprocess ARE NOT SLOWING DOWN THE FETCH MELVI, execution time is the same, you can check it
return strings.TrimSpace(string(nameOut))
}
func GetDE() string {
de := os.Getenv("XDG_CURRENT_DESKTOP")
if de == "" {
return "unknown or w/o GUI"
}
return strings.TrimSpace(de)
}
func GetUptime() string {
data, err := os.ReadFile("/proc/uptime")
if err != nil {
return "0"
}
uptimeStr := strings.Fields(string(data))[0]
seconds, err := strconv.ParseFloat(uptimeStr, 64)
if err != nil {
_, err := fmt.Fprintf(os.Stderr, "Error: %v\n", err)
if err != nil {
return "error printing uptime"
}
return ""
}
d := time.Duration(seconds) * time.Second
formatted := d.Round(time.Second).String()
spaced := strings.NewReplacer("h", "h ", "m", "m ", "s", "s ").Replace(formatted)
return spaced
}
func GetShell() string {
out, err := exec.Command("ps", "-p", strconv.Itoa(os.Getppid()), "-o", "comm=").Output()
if err != nil {
return path.Base(os.Getenv("SHELL"))
}
return strings.TrimSpace(string(out))
}