Files
TWA-App/TWASys-App/Models/ServerInfo/SysInfoReader.cs
2025-10-22 09:41:40 +07:00

186 lines
6.5 KiB
C#

using System.Diagnostics;
using System.Runtime.InteropServices;
#if WINDOWS
using System.Management; // NuGet: System.Management
using Microsoft.Win32;
#endif
namespace TWASys_App.Models.ServerInfo
{
public record SysInfo(int SocketCount, string? CpuName, ulong TotalRamBytes);
public static class SysInfoReader
{
public static SysInfo Get()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return GetWindows();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return GetLinux();
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return GetMac();
return new SysInfo(0, null, 0);
}
// ---------- Windows ----------
static SysInfo GetWindows()
{
string? name = null;
int sockets = 0;
#if WINDOWS
// CPU name: registry
try
{
using var k = Registry.LocalMachine.OpenSubKey(
@"HARDWARE\DESCRIPTION\System\CentralProcessor\0");
name = k?.GetValue("ProcessorNameString")?.ToString()?.Trim();
} catch { }
// Sockets: mỗi Win32_Processor ~ 1 physical socket
try
{
using var s = new ManagementObjectSearcher(
"SELECT SocketDesignation FROM Win32_Processor");
foreach (ManagementObject _ in s.Get()) sockets++;
}
catch
{
// Fallback
try
{
using var s2 = new ManagementObjectSearcher(
"SELECT NumberOfProcessors FROM Win32_ComputerSystem");
foreach (ManagementObject mo in s2.Get())
sockets = Convert.ToInt32(mo["NumberOfProcessors"]);
} catch { }
}
#endif
// RAM: GlobalMemoryStatusEx
ulong total = GetTotalRamWindows();
return new SysInfo(sockets, name, total);
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct MEMORYSTATUSEX
{
public uint dwLength;
public uint dwMemoryLoad;
public ulong ullTotalPhys;
public ulong ullAvailPhys;
public ulong ullTotalPageFile;
public ulong ullAvailPageFile;
public ulong ullTotalVirtual;
public ulong ullAvailVirtual;
public ulong ullAvailExtendedVirtual;
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);
static ulong GetTotalRamWindows()
{
var st = new MEMORYSTATUSEX { dwLength = (uint)Marshal.SizeOf<MEMORYSTATUSEX>() };
return GlobalMemoryStatusEx(ref st) ? st.ullTotalPhys : 0UL;
}
// ---------- Linux ----------
static SysInfo GetLinux()
{
// CPU name
string? name = null;
try
{
foreach (var line in File.ReadLines("/proc/cpuinfo"))
if (line.StartsWith("model name", StringComparison.OrdinalIgnoreCase))
{ name = line[(line.IndexOf(':') + 1)..].Trim(); break; }
}
catch { }
if (string.IsNullOrWhiteSpace(name))
name = Run("bash", "-lc \"lscpu | grep -i 'Model name' | cut -d: -f2- | xargs\"");
// Socket count
int sockets = 0;
try
{
var set = new HashSet<string>(StringComparer.Ordinal);
foreach (var dir in Directory.GetDirectories("/sys/devices/system/cpu", "cpu*"))
{
var dn = Path.GetFileName(dir);
if (!dn.StartsWith("cpu") || !int.TryParse(dn[3..], out _)) continue;
var p = Path.Combine(dir, "topology", "physical_package_id");
if (File.Exists(p)) { var v = File.ReadAllText(p).Trim(); if (v != "") set.Add(v); }
}
sockets = set.Count;
}
catch { }
if (sockets == 0)
{
var s = Run("bash", "-lc \"lscpu | grep -i 'Socket(s)' | awk -F: '{print $2}' | xargs\"");
int.TryParse(s, out sockets);
}
// Total RAM: /proc/meminfo (MemTotal: kB)
ulong total = 0;
try
{
foreach (var line in File.ReadLines("/proc/meminfo"))
{
if (line.StartsWith("MemTotal:", StringComparison.Ordinal))
{
var parts = line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
// ví dụ: "MemTotal: 16367472 kB"
if (parts.Length >= 2 && ulong.TryParse(parts[1], out var kb))
total = kb * 1024UL;
break;
}
}
}
catch { }
if (total == 0)
{
var s = Run("bash", "-lc \"free -b | awk '/^Mem:/ {print $2}'\"");
ulong.TryParse(s, out total);
}
return new SysInfo(sockets, string.IsNullOrWhiteSpace(name) ? null : name, total);
}
// ---------- macOS ----------
static SysInfo GetMac()
{
var name = Run("sysctl", "-n machdep.cpu.brand_string");
var sSockets = Run("sysctl", "-n hw.packages"); // số package
int.TryParse(sSockets, out var sockets);
var mem = Run("sysctl", "-n hw.memsize");
ulong.TryParse(mem, out var total);
return new SysInfo(sockets, string.IsNullOrWhiteSpace(name) ? null : name.Trim(), total);
}
static string Run(string file, string args)
{
try
{
var p = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = file,
Arguments = args,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
p.Start();
var txt = p.StandardOutput.ReadToEnd();
p.WaitForExit(2000);
return txt.Trim();
}
catch { return ""; }
}
}
}