320 lines
12 KiB
C#
320 lines
12 KiB
C#
using System.Diagnostics;
|
|
using Microsoft.AspNetCore.Builder;
|
|
using Microsoft.AspNetCore.Hosting;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Newtonsoft.Json;
|
|
using Microsoft.AspNetCore.Http;
|
|
using System.Runtime.InteropServices;
|
|
using System.Management;
|
|
|
|
namespace ResourceMonitorService
|
|
{
|
|
public class Worker : BackgroundService
|
|
{
|
|
private readonly IHostApplicationLifetime _lifetime;
|
|
|
|
public Worker(IHostApplicationLifetime lifetime)
|
|
{
|
|
_lifetime = lifetime;
|
|
}
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
{
|
|
var builder = WebApplication.CreateBuilder();
|
|
builder.Services.AddCors(options =>
|
|
{
|
|
options.AddPolicy("AllowAllOrigins",
|
|
builder => builder.AllowAnyOrigin()
|
|
.AllowAnyHeader()
|
|
.AllowAnyMethod());
|
|
});
|
|
builder.Services.AddControllers().AddNewtonsoftJson();
|
|
var app = builder.Build();
|
|
// Apply CORS policy to allow all origins
|
|
app.UseCors("AllowAllOrigins");
|
|
|
|
app.MapGet("/api/resource-usage", async context =>
|
|
{
|
|
var currentTime = GetCurrentTime();
|
|
|
|
var computerInfo = GetComputerInfo();
|
|
var cpuUsage = GetCpuUsage();
|
|
var ramUsage = GetRamUsage();
|
|
var gpuUsage = GetGpuUsage();
|
|
var runningGame = GetCurrentlyRunningGame();
|
|
|
|
var resourceUsage = new
|
|
{
|
|
CurrentTime = currentTime,
|
|
ComputerInfo = computerInfo,
|
|
CPU = cpuUsage,
|
|
RAM = ramUsage,
|
|
GPU = gpuUsage,
|
|
CurrentlyRunningGame = runningGame
|
|
};
|
|
|
|
var json = JsonConvert.SerializeObject(resourceUsage);
|
|
context.Response.ContentType = "application/json";
|
|
await context.Response.WriteAsync(json);
|
|
});
|
|
|
|
app.MapPost("/api/kill-process", async context =>
|
|
{
|
|
try
|
|
{
|
|
var idStr = await new StreamReader(context.Request.Body).ReadToEndAsync();
|
|
int processId = Convert.ToInt32(idStr);
|
|
|
|
Process[] processes = Process.GetProcesses().Where(p => p.Id == processId).ToArray();
|
|
|
|
if (processes.Length > 0)
|
|
{
|
|
foreach (var process in processes)
|
|
{
|
|
try
|
|
{
|
|
process.Kill();
|
|
await context.Response.WriteAsync($"Process with ID {processId} has been killed.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await context.Response.WriteAsync($"Error killing process with ID {processId}: {ex.Message}");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
await context.Response.WriteAsync($"No process found with ID {processId}.");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await context.Response.WriteAsync($"An error occurred: {ex.Message}");
|
|
}
|
|
});
|
|
|
|
_ = app.RunAsync(stoppingToken);
|
|
|
|
await Task.Delay(Timeout.Infinite, stoppingToken);
|
|
}
|
|
|
|
private object GetComputerInfo()
|
|
{
|
|
return new
|
|
{
|
|
MachineName = Environment.MachineName,
|
|
OSVersion = RuntimeInformation.OSDescription,
|
|
OSArchitecture = RuntimeInformation.OSArchitecture.ToString(),
|
|
ProcessorCount = Environment.ProcessorCount
|
|
};
|
|
}
|
|
|
|
private object GetCpuUsage()
|
|
{
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
cpuCounter.NextValue();
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
Thread.Sleep(1000); // Wait a second to get a valid reading
|
|
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
var usage = cpuCounter.NextValue();
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
if (usage > 80)
|
|
{
|
|
// Get the current processes and sort them by CPU usage in descending order
|
|
var processes = Process.GetProcesses().OrderByDescending(p => p.TotalProcessorTime);
|
|
|
|
// Create a new anonymous type containing the CPU usage, RAM usage, and the top 3 highest CPU-using processes
|
|
return new
|
|
{
|
|
Usage = usage,
|
|
Process1 = new
|
|
{
|
|
Name = processes.ElementAt(0).ProcessName,
|
|
TotalProcessorTime = processes.ElementAt(0).TotalProcessorTime,
|
|
WorkingSet64 = processes.ElementAt(0).WorkingSet64 / (1024 * 1024) // Convert to MB
|
|
},
|
|
Process2 = new
|
|
{
|
|
Name = processes.ElementAt(1).ProcessName,
|
|
TotalProcessorTime = processes.ElementAt(1).TotalProcessorTime,
|
|
WorkingSet64 = processes.ElementAt(1).WorkingSet64 / (1024 * 1024) // Convert to MB
|
|
},
|
|
Process3 = new
|
|
{
|
|
Name = processes.ElementAt(2).ProcessName,
|
|
TotalProcessorTime = processes.ElementAt(2).TotalProcessorTime,
|
|
WorkingSet64 = processes.ElementAt(2).WorkingSet64 / (1024 * 1024) // Convert to MB
|
|
}
|
|
};
|
|
}
|
|
|
|
return new
|
|
{
|
|
Usage = usage
|
|
};
|
|
}
|
|
|
|
private float GetRamUsage()
|
|
{
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
var ramCounter = new PerformanceCounter("Memory", "Available MBytes");
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
var totalMemory = GetTotalPhysicalMemory();
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
var availableMemory = ramCounter.NextValue() * 1024 * 1024;
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
return (float)(totalMemory - availableMemory) / totalMemory * 100;
|
|
}
|
|
|
|
private ulong GetTotalPhysicalMemory()
|
|
{
|
|
ulong totalMemory = 0;
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
var searcher = new ManagementObjectSearcher("SELECT TotalPhysicalMemory FROM Win32_ComputerSystem");
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
foreach (var obj in searcher.Get())
|
|
{
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
totalMemory = (ulong)obj["TotalPhysicalMemory"];
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
}
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
return totalMemory;
|
|
}
|
|
|
|
private object GetGpuUsage()
|
|
{
|
|
if (!IsNvidiaGpuPresent())
|
|
{
|
|
return new
|
|
{
|
|
Usage = 0,
|
|
Temperature = 0,
|
|
FanSpeed = 0,
|
|
IsAvailable = false,
|
|
Message = "No NVIDIA GPU detected"
|
|
};
|
|
}
|
|
|
|
try
|
|
{
|
|
|
|
NvmlWrapper.NvmlInit();
|
|
IntPtr device;
|
|
NvmlWrapper.NvmlDeviceGetHandleByIndex(0, out device);
|
|
NvmlWrapper.NvmlUtilization utilization;
|
|
NvmlWrapper.NvmlDeviceGetUtilizationRates(device, out utilization);
|
|
|
|
uint temperature;
|
|
NvmlWrapper.NvmlDeviceGetTemperature(device, 0, out temperature);
|
|
|
|
uint fanSpeed;
|
|
NvmlWrapper.NvmlDeviceGetFanSpeed(device, out fanSpeed);
|
|
|
|
NvmlWrapper.NvmlShutdown();
|
|
|
|
return new
|
|
{
|
|
Usage = utilization.Gpu,
|
|
Temperature = temperature,
|
|
FanSpeed = fanSpeed
|
|
};
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return new
|
|
{
|
|
Usage = 0,
|
|
Temperature = 0,
|
|
FanSpeed = 0,
|
|
IsAvailable = false,
|
|
Error = ex.Message
|
|
};
|
|
}
|
|
}
|
|
|
|
private bool IsNvidiaGpuPresent()
|
|
{
|
|
try
|
|
{
|
|
// Method 1: Try to initialize NVML
|
|
NvmlWrapper.NvmlInit();
|
|
uint deviceCount = 0;
|
|
NvmlWrapper.NvmlDeviceGetCount(ref deviceCount);
|
|
NvmlWrapper.NvmlShutdown();
|
|
|
|
return deviceCount > 0;
|
|
}
|
|
catch
|
|
{
|
|
// Method 2: Fallback to checking using WMI
|
|
try
|
|
{
|
|
using (var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_VideoController WHERE Name LIKE '%NVIDIA%'"))
|
|
{
|
|
var collection = searcher.Get();
|
|
return collection.Count > 0;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private object GetCurrentlyRunningGame()
|
|
{
|
|
var processes = Process.GetProcesses();
|
|
|
|
foreach (var process in processes)
|
|
{
|
|
try
|
|
{
|
|
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
|
var filePath = process.MainModule.FileName;
|
|
#pragma warning restore CS8602 // Dereference of a possibly null reference.
|
|
if (filePath.Contains(@"\steamapps\common\"))
|
|
{
|
|
// Extract the game directory name
|
|
var parts = filePath.Split(new[] { @"\steamapps\common\" }, StringSplitOptions.None);
|
|
if (parts.Length > 1)
|
|
{
|
|
var gamePath = parts[1];
|
|
var gameName = gamePath.Split(Path.DirectorySeparatorChar)[0];
|
|
return new
|
|
{
|
|
GameName = gameName,
|
|
ExecutableName = Path.GetFileName(filePath),
|
|
FullPath = filePath,
|
|
ProcessId = process.Id,
|
|
MemoryUsage = process.WorkingSet64 / (1024 * 1024) + " MB", // Memory usage in MB
|
|
CpuTime = process.TotalProcessorTime.ToString(),
|
|
StartTime = process.StartTime.ToString("G"), // General date/time pattern
|
|
UserName = Environment.UserName // The user running the process
|
|
};
|
|
}
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// Handle access exceptions or continue if not important
|
|
}
|
|
}
|
|
return "No Steam game is currently running.";
|
|
}
|
|
private string GetCurrentTime()
|
|
{
|
|
return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
|
}
|
|
|
|
|
|
}
|
|
}
|