2024-08-08 16:49:30 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
2024-11-26 07:46:03 +01:00
|
|
|
"fmt"
|
2024-08-08 16:49:30 +02:00
|
|
|
"os"
|
2024-11-26 07:46:03 +01:00
|
|
|
"path/filepath"
|
2024-08-08 16:49:30 +02:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
2024-11-26 07:46:03 +01:00
|
|
|
"syscall"
|
2024-10-13 00:04:46 +02:00
|
|
|
"time"
|
2024-08-08 16:49:30 +02:00
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
"github.com/shirou/gopsutil/mem"
|
2024-08-08 16:49:30 +02:00
|
|
|
"gopkg.in/ini.v1"
|
|
|
|
)
|
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
var configFilePath = "./config.ini"
|
|
|
|
|
|
|
|
type CacheConfig struct {
|
|
|
|
Duration time.Duration
|
|
|
|
MaxUsageBytes uint64 // Store as bytes for uniformity
|
|
|
|
Path string
|
|
|
|
}
|
|
|
|
|
|
|
|
type Config struct {
|
|
|
|
Port int // Added
|
|
|
|
AuthCode string // Added
|
|
|
|
PeerID string // Added
|
|
|
|
Peers []string
|
|
|
|
Domain string // Added
|
|
|
|
NodesEnabled bool // Added
|
|
|
|
CrawlerEnabled bool // Added
|
|
|
|
WebsiteEnabled bool // Added
|
|
|
|
RamCacheEnabled bool
|
|
|
|
DriveCacheEnabled bool // Added
|
|
|
|
LogLevel int // Added
|
|
|
|
|
|
|
|
DriveCache CacheConfig
|
|
|
|
RamCache CacheConfig
|
|
|
|
}
|
|
|
|
|
|
|
|
var defaultConfig = Config{
|
|
|
|
Port: 5000,
|
|
|
|
Domain: "localhost",
|
|
|
|
Peers: []string{},
|
|
|
|
AuthCode: generateStrongRandomString(64),
|
|
|
|
NodesEnabled: false,
|
|
|
|
CrawlerEnabled: true,
|
|
|
|
WebsiteEnabled: true,
|
|
|
|
RamCacheEnabled: true,
|
|
|
|
DriveCacheEnabled: false,
|
|
|
|
LogLevel: 1,
|
|
|
|
DriveCache: CacheConfig{
|
|
|
|
Duration: 48 * time.Hour, // Added
|
|
|
|
Path: "./cache", // Added
|
|
|
|
MaxUsageBytes: parseMaxUsageDrive("90 %", config.DriveCache.Path), // Added
|
|
|
|
},
|
|
|
|
RamCache: CacheConfig{
|
|
|
|
Duration: 6 * time.Hour, // Added
|
|
|
|
MaxUsageBytes: parseMaxUsageRam("90%"), // Added
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2024-08-08 16:49:30 +02:00
|
|
|
func initConfig() error {
|
2024-11-26 07:46:03 +01:00
|
|
|
// Check if the configuration file exists
|
2024-08-08 16:49:30 +02:00
|
|
|
if _, err := os.Stat(configFilePath); os.IsNotExist(err) {
|
2024-11-26 07:46:03 +01:00
|
|
|
// If not, create a new configuration
|
2024-08-08 16:49:30 +02:00
|
|
|
return createConfig()
|
|
|
|
}
|
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
printInfo("Configuration file already exists. Loading configuration.")
|
|
|
|
// Load existing configuration
|
2024-08-08 16:49:30 +02:00
|
|
|
config = loadConfig()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func createConfig() error {
|
|
|
|
reader := bufio.NewReader(os.Stdin)
|
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
printMessage("Configuration file not found. Let's set it up.")
|
|
|
|
printMessage("Do you want to use default values? (yes/NO): ")
|
2024-08-08 16:49:30 +02:00
|
|
|
useDefaults, _ := reader.ReadString('\n')
|
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
if strings.TrimSpace(strings.ToLower(useDefaults)) != "yes" {
|
|
|
|
// Server settings
|
2024-08-10 13:27:23 +02:00
|
|
|
printMessage("Enter port (default 5000): ")
|
2024-08-08 16:49:30 +02:00
|
|
|
portStr, _ := reader.ReadString('\n')
|
2024-11-26 07:46:03 +01:00
|
|
|
portStr = strings.TrimSpace(portStr)
|
|
|
|
if portStr != "" {
|
|
|
|
port, err := strconv.Atoi(portStr)
|
|
|
|
if err == nil {
|
2024-08-08 16:49:30 +02:00
|
|
|
config.Port = port
|
2024-11-26 07:46:03 +01:00
|
|
|
} else {
|
|
|
|
printWarn("Invalid port, using default (5000).")
|
|
|
|
config.Port = defaultConfig.Port
|
2024-08-08 16:49:30 +02:00
|
|
|
}
|
2024-11-26 07:46:03 +01:00
|
|
|
} else {
|
|
|
|
config.Port = defaultConfig.Port
|
2024-08-08 16:49:30 +02:00
|
|
|
}
|
|
|
|
|
2024-08-10 13:27:23 +02:00
|
|
|
printMessage("Enter your domain address (default localhost): ")
|
2024-08-08 16:49:30 +02:00
|
|
|
domain, _ := reader.ReadString('\n')
|
2024-11-26 07:46:03 +01:00
|
|
|
config.Domain = strings.TrimSpace(domain)
|
|
|
|
if config.Domain == "" {
|
|
|
|
config.Domain = defaultConfig.Domain
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cache settings
|
|
|
|
printMessage("Would you like to configure Cache settings (yes/NO): ")
|
|
|
|
configureCache, _ := reader.ReadString('\n')
|
|
|
|
if strings.TrimSpace(strings.ToLower(configureCache)) == "yes" {
|
|
|
|
// RamCache settings
|
|
|
|
printMessage("Enter duration to store results in Ram (default 6h): ")
|
|
|
|
ramDurationStr, _ := reader.ReadString('\n')
|
|
|
|
ramDurationStr = strings.TrimSpace(ramDurationStr)
|
|
|
|
if ramDurationStr == "" {
|
|
|
|
config.RamCache.Duration = defaultConfig.RamCache.Duration
|
|
|
|
config.RamCacheEnabled = true
|
|
|
|
} else if ramDurationStr == "0h" {
|
|
|
|
config.RamCacheEnabled = false
|
|
|
|
} else {
|
|
|
|
ramDuration, err := time.ParseDuration(ramDurationStr)
|
|
|
|
if err != nil {
|
|
|
|
printWarn("Invalid duration, using default (6h).")
|
|
|
|
config.RamCache.Duration = defaultConfig.RamCache.Duration
|
|
|
|
config.RamCacheEnabled = true
|
|
|
|
} else {
|
|
|
|
config.RamCache.Duration = ramDuration
|
|
|
|
config.RamCacheEnabled = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
printMessage("Enter RamCache max usage, e.g., 2 GiB or 80%% (default 90%%): ")
|
|
|
|
ramMaxUsage, _ := reader.ReadString('\n')
|
|
|
|
ramMaxUsage = strings.TrimSpace(ramMaxUsage)
|
|
|
|
if ramMaxUsage == "" {
|
|
|
|
config.RamCache.MaxUsageBytes = defaultConfig.RamCache.MaxUsageBytes
|
|
|
|
} else if ramMaxUsage == "0" || parseMaxUsageRam(ramMaxUsage) == 0 {
|
|
|
|
config.RamCacheEnabled = false
|
|
|
|
} else {
|
|
|
|
config.RamCache.MaxUsageBytes = parseMaxUsageRam(ramMaxUsage)
|
|
|
|
if config.RamCache.MaxUsageBytes == 0 {
|
|
|
|
printWarn("Invalid RamCache max usage, using default (90%%).")
|
|
|
|
config.RamCache.MaxUsageBytes = defaultConfig.RamCache.MaxUsageBytes
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// DriveCache settings
|
|
|
|
printMessage("Enter duration to store results in DriveCache (default 0h): ")
|
|
|
|
driveDurationStr, _ := reader.ReadString('\n')
|
|
|
|
driveDurationStr = strings.TrimSpace(driveDurationStr)
|
|
|
|
if driveDurationStr == "" {
|
|
|
|
config.DriveCache.Duration = defaultConfig.DriveCache.Duration
|
|
|
|
config.DriveCacheEnabled = config.DriveCache.Duration > 0
|
|
|
|
} else if driveDurationStr == "0h" {
|
|
|
|
config.DriveCacheEnabled = false
|
|
|
|
} else {
|
|
|
|
driveDuration, err := time.ParseDuration(driveDurationStr)
|
|
|
|
if err != nil {
|
|
|
|
printWarn("Invalid duration, using default (48h).")
|
|
|
|
config.DriveCache.Duration = defaultConfig.DriveCache.Duration
|
|
|
|
config.DriveCacheEnabled = config.DriveCache.Duration > 0
|
|
|
|
} else {
|
|
|
|
config.DriveCache.Duration = driveDuration
|
|
|
|
config.DriveCacheEnabled = config.DriveCache.Duration > 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
printMessage("Enter DriveCache path (default ./cache): ")
|
|
|
|
drivePath, _ := reader.ReadString('\n')
|
|
|
|
drivePath = strings.TrimSpace(drivePath)
|
|
|
|
if drivePath == "" {
|
|
|
|
config.DriveCache.Path = defaultConfig.DriveCache.Path
|
|
|
|
} else {
|
|
|
|
config.DriveCache.Path = drivePath
|
|
|
|
}
|
|
|
|
|
|
|
|
printMessage("Enter DriveCache max usage, e.g., 2 GiB or 90%% (default 90%%): ")
|
|
|
|
driveMaxUsage, _ := reader.ReadString('\n')
|
|
|
|
driveMaxUsage = strings.TrimSpace(driveMaxUsage)
|
|
|
|
if driveMaxUsage == "" {
|
|
|
|
config.DriveCache.MaxUsageBytes = defaultConfig.DriveCache.MaxUsageBytes
|
|
|
|
} else if driveMaxUsage == "0" || parseMaxUsageDrive(driveMaxUsage, drivePath) == 0 {
|
|
|
|
config.DriveCacheEnabled = false
|
|
|
|
} else {
|
|
|
|
config.DriveCache.MaxUsageBytes = parseMaxUsageDrive(driveMaxUsage, drivePath)
|
|
|
|
if config.DriveCache.MaxUsageBytes == 0 {
|
|
|
|
printWarn("Invalid DriveCache max usage, using default (1 TiB).")
|
|
|
|
config.DriveCache.MaxUsageBytes = defaultConfig.DriveCache.MaxUsageBytes
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
printInfo("Cache settings skipped. Using default values.")
|
|
|
|
config.RamCache = defaultConfig.RamCache
|
|
|
|
config.DriveCache = defaultConfig.DriveCache
|
2024-08-08 16:49:30 +02:00
|
|
|
}
|
|
|
|
} else {
|
2024-11-26 07:46:03 +01:00
|
|
|
// Use default configuration
|
2024-08-08 16:49:30 +02:00
|
|
|
config = defaultConfig
|
|
|
|
}
|
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
// Generate AuthCode if missing
|
2024-08-08 16:49:30 +02:00
|
|
|
if config.AuthCode == "" {
|
|
|
|
config.AuthCode = generateStrongRandomString(64)
|
2024-08-10 13:27:23 +02:00
|
|
|
printMessage("Generated connection code: %s\n", config.AuthCode)
|
2024-08-08 16:49:30 +02:00
|
|
|
}
|
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
// Set other default values
|
|
|
|
config.NodesEnabled = defaultConfig.NodesEnabled
|
|
|
|
config.CrawlerEnabled = defaultConfig.CrawlerEnabled
|
|
|
|
config.WebsiteEnabled = defaultConfig.WebsiteEnabled
|
|
|
|
config.LogLevel = defaultConfig.LogLevel
|
2024-08-09 15:55:14 +02:00
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
// Save configuration to file
|
2024-08-08 16:49:30 +02:00
|
|
|
saveConfig(config)
|
2024-11-26 07:46:03 +01:00
|
|
|
printInfo("Configuration saved successfully.")
|
2024-08-08 16:49:30 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func saveConfig(config Config) {
|
|
|
|
cfg := ini.Empty()
|
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
// Server section
|
|
|
|
sec := cfg.Section("Server")
|
|
|
|
sec.Key("Port").SetValue(strconv.Itoa(config.Port))
|
2024-08-08 16:49:30 +02:00
|
|
|
sec.Key("Domain").SetValue(config.Domain)
|
2024-08-10 13:27:23 +02:00
|
|
|
sec.Key("LogLevel").SetValue(strconv.Itoa(config.LogLevel))
|
2024-11-26 07:46:03 +01:00
|
|
|
|
|
|
|
// Peers section
|
|
|
|
peersSec := cfg.Section("Peers")
|
|
|
|
peersSec.Key("AuthCode").SetValue(config.AuthCode)
|
|
|
|
peersSec.Key("PeerID").SetValue(config.PeerID)
|
|
|
|
peersSec.Key("Peers").SetValue(strings.Join(config.Peers, ","))
|
|
|
|
|
|
|
|
// Features section
|
|
|
|
featuresSec := cfg.Section("Features")
|
|
|
|
featuresSec.Key("Nodes").SetValue(strconv.FormatBool(config.NodesEnabled))
|
|
|
|
featuresSec.Key("Crawler").SetValue(strconv.FormatBool(config.CrawlerEnabled))
|
|
|
|
featuresSec.Key("Website").SetValue(strconv.FormatBool(config.WebsiteEnabled))
|
|
|
|
featuresSec.Key("RamCache").SetValue(strconv.FormatBool(config.RamCacheEnabled))
|
|
|
|
featuresSec.Key("DriveCache").SetValue(strconv.FormatBool(config.DriveCacheEnabled))
|
|
|
|
|
|
|
|
// DriveCache section
|
|
|
|
driveSec := cfg.Section("DriveCache")
|
|
|
|
driveSec.Key("Duration").SetValue(config.DriveCache.Duration.String())
|
|
|
|
driveSec.Key("MaxUsage").SetValue(formatMaxUsage(config.DriveCache.MaxUsageBytes))
|
|
|
|
driveSec.Key("Path").SetValue(config.DriveCache.Path)
|
|
|
|
// driveSec.Key("MaxConcurrentDownloads.Thumbnail").SetValue(strconv.Itoa(config.DriveCache.MaxConcurrentThumbnailDownloads))
|
|
|
|
|
|
|
|
// RamCache section
|
|
|
|
ramSec := cfg.Section("RamCache")
|
|
|
|
ramSec.Key("Duration").SetValue(config.RamCache.Duration.String())
|
|
|
|
ramSec.Key("MaxUsage").SetValue(formatMaxUsage(config.RamCache.MaxUsageBytes))
|
2024-08-08 16:49:30 +02:00
|
|
|
|
|
|
|
err := cfg.SaveTo(configFilePath)
|
|
|
|
if err != nil {
|
2024-08-10 13:27:23 +02:00
|
|
|
printErr("Error writing to config file: %v", err)
|
2024-08-08 16:49:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func loadConfig() Config {
|
|
|
|
cfg, err := ini.Load(configFilePath)
|
|
|
|
if err != nil {
|
2024-08-10 13:27:23 +02:00
|
|
|
printErr("Error opening config file: %v", err)
|
2024-08-08 16:49:30 +02:00
|
|
|
}
|
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
// Server
|
|
|
|
port, _ := cfg.Section("Server").Key("Port").Int()
|
|
|
|
domain := cfg.Section("Server").Key("Domain").String()
|
|
|
|
logLevel, _ := cfg.Section("Server").Key("LogLevel").Int()
|
|
|
|
|
|
|
|
// Peers
|
|
|
|
authCode := cfg.Section("Peers").Key("AuthCode").String()
|
|
|
|
peersStr := cfg.Section("Peers").Key("Peers").String()
|
|
|
|
peers := strings.Split(peersStr, ",")
|
|
|
|
|
|
|
|
// Features
|
|
|
|
nodesEnabled, _ := cfg.Section("Features").Key("Nodes").Bool()
|
|
|
|
crawlerEnabled, _ := cfg.Section("Features").Key("Crawler").Bool()
|
|
|
|
websiteEnabled, _ := cfg.Section("Features").Key("Website").Bool()
|
|
|
|
ramCacheEnabled, _ := cfg.Section("Features").Key("RamCache").Bool()
|
|
|
|
driveCacheEnabled, _ := cfg.Section("Features").Key("DriveCache").Bool()
|
|
|
|
|
|
|
|
// DriveCache
|
|
|
|
driveDuration, _ := time.ParseDuration(cfg.Section("DriveCache").Key("Duration").String())
|
|
|
|
drivePath := cfg.Section("DriveCache").Key("Path").String()
|
|
|
|
driveMaxUsage := parseMaxUsageDrive(cfg.Section("DriveCache").Key("MaxUsage").String(), drivePath)
|
|
|
|
// maxConcurrentDownloads, _ := cfg.Section("DriveCache").Key("MaxConcurrentDownloads.Thumbnail").Int()
|
|
|
|
// if maxConcurrentDownloads == 0 {
|
|
|
|
// maxConcurrentDownloads = defaultConfig.DriveCache.MaxConcurrentThumbnailDownloads
|
|
|
|
// }
|
|
|
|
|
|
|
|
// RamCache
|
|
|
|
ramDuration, _ := time.ParseDuration(cfg.Section("RamCache").Key("Duration").String())
|
|
|
|
ramMaxUsage := parseMaxUsageRam(cfg.Section("RamCache").Key("MaxUsage").String())
|
|
|
|
|
|
|
|
return Config{
|
|
|
|
Port: port,
|
|
|
|
Domain: domain,
|
|
|
|
LogLevel: logLevel,
|
|
|
|
AuthCode: authCode, // Assign AuthCode here
|
|
|
|
Peers: peers,
|
|
|
|
NodesEnabled: nodesEnabled,
|
|
|
|
CrawlerEnabled: crawlerEnabled,
|
|
|
|
WebsiteEnabled: websiteEnabled,
|
|
|
|
RamCacheEnabled: ramCacheEnabled,
|
|
|
|
DriveCacheEnabled: driveCacheEnabled,
|
|
|
|
DriveCache: CacheConfig{
|
|
|
|
Duration: driveDuration,
|
|
|
|
MaxUsageBytes: driveMaxUsage,
|
|
|
|
Path: drivePath,
|
|
|
|
// MaxConcurrentThumbnailDownloads: maxConcurrentDownloads,
|
|
|
|
},
|
|
|
|
RamCache: CacheConfig{
|
|
|
|
Duration: ramDuration,
|
|
|
|
MaxUsageBytes: ramMaxUsage,
|
|
|
|
},
|
2024-08-08 16:49:30 +02:00
|
|
|
}
|
2024-11-26 07:46:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Helper to parse MaxUsage string into bytes
|
|
|
|
func parseMaxUsageRam(value string) uint64 {
|
|
|
|
const GiB = 1024 * 1024 * 1024
|
|
|
|
value = strings.TrimSpace(value)
|
|
|
|
valueNoSpaces := strings.ReplaceAll(value, " ", "")
|
2024-08-08 16:49:30 +02:00
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
if strings.HasSuffix(valueNoSpaces, "%") {
|
|
|
|
percentStr := strings.TrimSuffix(valueNoSpaces, "%")
|
|
|
|
percent, err := strconv.ParseFloat(percentStr, 64)
|
|
|
|
if err != nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
totalMem := getTotalMemory()
|
|
|
|
return uint64(float64(totalMem) * (percent / 100))
|
|
|
|
} else if strings.HasSuffix(valueNoSpaces, "GiB") {
|
|
|
|
sizeStr := strings.TrimSuffix(valueNoSpaces, "GiB")
|
|
|
|
size, err := strconv.ParseFloat(sizeStr, 64)
|
|
|
|
if err != nil {
|
|
|
|
return 0
|
2024-08-08 16:49:30 +02:00
|
|
|
}
|
2024-11-26 07:46:03 +01:00
|
|
|
return uint64(size * GiB)
|
2024-08-08 16:49:30 +02:00
|
|
|
}
|
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
return 0
|
|
|
|
}
|
2024-08-08 16:49:30 +02:00
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
// Helper to parse MaxUsage string into bytes based on drive space
|
|
|
|
func parseMaxUsageDrive(value string, cachePath string) uint64 {
|
|
|
|
const GiB = 1024 * 1024 * 1024
|
|
|
|
value = strings.TrimSpace(value)
|
|
|
|
valueNoSpaces := strings.ReplaceAll(value, " ", "")
|
2024-08-09 15:55:14 +02:00
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
totalDiskSpace := getTotalDiskSpace(cachePath)
|
|
|
|
if totalDiskSpace == 0 {
|
|
|
|
printErr("Failed to retrieve disk space for path: %s", cachePath)
|
|
|
|
return 0
|
2024-08-10 13:27:23 +02:00
|
|
|
}
|
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
if strings.HasSuffix(valueNoSpaces, "%") {
|
|
|
|
percentStr := strings.TrimSuffix(valueNoSpaces, "%")
|
|
|
|
percent, err := strconv.ParseFloat(percentStr, 64)
|
|
|
|
if err != nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return uint64(float64(totalDiskSpace) * (percent / 100))
|
|
|
|
} else if strings.HasSuffix(valueNoSpaces, "GiB") {
|
|
|
|
sizeStr := strings.TrimSuffix(valueNoSpaces, "GiB")
|
|
|
|
size, err := strconv.ParseFloat(sizeStr, 64)
|
|
|
|
if err != nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return uint64(size * GiB)
|
2024-08-10 13:27:23 +02:00
|
|
|
}
|
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get total disk space of the system where cachePath resides
|
|
|
|
func getTotalDiskSpace(cachePath string) uint64 {
|
|
|
|
var stat syscall.Statfs_t
|
|
|
|
|
|
|
|
// Get filesystem stats for the cache path
|
|
|
|
absPath, err := filepath.Abs(cachePath)
|
|
|
|
if err != nil {
|
|
|
|
printErr("Failed to resolve absolute path for: %s", cachePath)
|
|
|
|
return 0
|
2024-08-10 13:27:23 +02:00
|
|
|
}
|
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
err = syscall.Statfs(absPath, &stat)
|
|
|
|
if err != nil {
|
|
|
|
printErr("Failed to retrieve filesystem stats for: %s", absPath)
|
|
|
|
return 0
|
2024-10-13 00:04:46 +02:00
|
|
|
}
|
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
// Total disk space in bytes
|
|
|
|
return stat.Blocks * uint64(stat.Bsize)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Helper to format bytes back to human-readable string
|
|
|
|
func formatMaxUsage(bytes uint64) string {
|
|
|
|
const GiB = 1024 * 1024 * 1024
|
|
|
|
if bytes >= GiB {
|
|
|
|
return fmt.Sprintf("%.2fGiB", float64(bytes)/GiB)
|
2024-08-08 16:49:30 +02:00
|
|
|
}
|
2024-11-26 07:46:03 +01:00
|
|
|
return fmt.Sprintf("%dbytes", bytes)
|
|
|
|
}
|
2024-08-08 16:49:30 +02:00
|
|
|
|
2024-11-26 07:46:03 +01:00
|
|
|
// Get total memory of the system
|
|
|
|
func getTotalMemory() uint64 {
|
|
|
|
v, err := mem.VirtualMemory()
|
|
|
|
if err != nil {
|
|
|
|
printErr("Failed to retrieve system memory: %v", err)
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return v.Total
|
2024-08-08 16:49:30 +02:00
|
|
|
}
|