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() }; 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(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 ""; } } } }