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 .WithOrigins("http://localhost:4200","http://192.168.50.52:4200","http://vmwin11:4200") .AllowAnyHeader() .AllowAnyMethod()); }); builder.Services.AddControllers().AddNewtonsoftJson(); // Read the API key from appsettings.json var configuration = builder.Configuration; var apiKey = configuration["ApiSettings:ApiKey"]; var app = builder.Build(); // Middleware to validate API key // This middleware checks for the presence of the API key in the request headers // and compares it with the expected API key from appsettings.json. // If the API key is missing or invalid, it returns a 401 Unauthorized response. // /* app.Use(async (context, next) => { if (!context.Request.Headers.TryGetValue("X-API-KEY", out var extractedApiKey) || extractedApiKey != apiKey) { context.Response.StatusCode = StatusCodes.Status401Unauthorized; await context.Response.WriteAsync("Unauthorized: Invalid API Key"); return; } await next(); }); */ // 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}"); } }); /* curl -X POST http://localhost:5000/api/force-shutdown -d "5000" */ /* Invoke-WebRequest -Uri "http://localhost:5000/api/force-shutdown" -Method POST -Body "50000" -ContentType "text/plain" */ app.MapPost("/api/force-shutdown", async context => { try { var requestBody = await new StreamReader(context.Request.Body).ReadToEndAsync(); var parameters = JsonConvert.DeserializeObject(requestBody); string action = parameters?.Action?.ToString()?.ToLower(); // "shutdown" or "restart" int delaySeconds = parameters?.DelaySeconds ?? 0; // Validate action input if (action != "shutdown" && action != "restart" && action != "cancel") { await context.Response.WriteAsync("Invalid action. Use 'shutdown', 'restart', or 'cancel'."); return; } //if action is stop, then cancel the shutdown if (action == "cancel") { var processStartInfoCancel = new ProcessStartInfo { FileName = "shutdown", Arguments = "/a", CreateNoWindow = true, UseShellExecute = false }; Process.Start(processStartInfoCancel); await context.Response.WriteAsync("Shutdown cancelled."); return; } // Validate delay input if (delaySeconds < 0) { await context.Response.WriteAsync("Delay must be a non-negative integer."); return; } // Determine the shutdown command string shutdownCommand = action == "shutdown" ? $"/s /f /t {delaySeconds}" : $"/r /f /t {delaySeconds}"; var processStartInfo = new ProcessStartInfo { FileName = "shutdown", Arguments = shutdownCommand, CreateNoWindow = true, UseShellExecute = false }; Process.Start(processStartInfo); await context.Response.WriteAsync($"{action.ToUpper()} command executed with a delay of {delaySeconds} seconds."); } catch (Exception ex) { await context.Response.WriteAsync($"An error occurred: {ex.Message}"); } }); app.MapGet("/api/stop", async context => { await context.Response.WriteAsync("Stopping the service..."); _lifetime.StopApplication(); }); app.MapGet("/", () => "Resource Monitor Service is running."); app.MapGet("/api/current-time", () => Results.Ok(GetCurrentTime())); app.MapGet("/api/computer-info", () => Results.Ok(GetComputerInfo())); app.MapGet("/api/cpu-usage", () => Results.Ok(GetCpuUsage())); app.MapGet("/api/ram-usage", () => Results.Ok(GetRamUsage())); app.MapGet("/api/gpu-usage", () => Results.Ok(GetGpuUsage())); app.MapGet("/api/running-game", () => Results.Ok(GetCurrentlyRunningGame())); app.MapGet("/api/total-physical-memory", () => Results.Ok(GetTotalPhysicalMemory())); app.MapGet("/api/total-available-memory", () => Results.Ok(new { TotalAvailableMemory = Environment.WorkingSet })); app.MapGet("/health", () => Results.Ok("Service is healthy.")); _ = 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() .Select(p => { try { return new { Process = p, TotalProcessorTime = p.TotalProcessorTime }; } catch { return null; // Skip processes that throw exceptions } }) .Where(p => p != null) .OrderByDescending(p => p.TotalProcessorTime) .Select(p => p.Process) .ToList(); // 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, IsAvailable = false, Error = "" }; } 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"); } } }