Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ea2fe47263 | |||
| 294438145a | |||
| 413360ece2 | |||
| a0b9f05ae3 | |||
| caa7436d51 |
@@ -9,6 +9,15 @@ public static class NvmlWrapper
|
|||||||
[DllImport("nvml.dll", EntryPoint = "nvmlShutdown")]
|
[DllImport("nvml.dll", EntryPoint = "nvmlShutdown")]
|
||||||
public static extern int NvmlShutdown();
|
public static extern int NvmlShutdown();
|
||||||
|
|
||||||
|
// Get device count
|
||||||
|
/* [DllImport("nvml.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern int nvmlDeviceGetCount_v2(ref uint deviceCount); */
|
||||||
|
|
||||||
|
/* public static int NvmlDeviceGetCount(ref uint deviceCount)
|
||||||
|
{
|
||||||
|
return nvmlDeviceGetCount_v2(ref deviceCount);
|
||||||
|
} */
|
||||||
|
|
||||||
[DllImport("nvml.dll", EntryPoint = "nvmlDeviceGetHandleByIndex_v2")]
|
[DllImport("nvml.dll", EntryPoint = "nvmlDeviceGetHandleByIndex_v2")]
|
||||||
public static extern int NvmlDeviceGetHandleByIndex(int index, out IntPtr device);
|
public static extern int NvmlDeviceGetHandleByIndex(int index, out IntPtr device);
|
||||||
|
|
||||||
|
|||||||
@@ -105,3 +105,15 @@ git add .
|
|||||||
git commit -m "Add steam running games"
|
git commit -m "Add steam running games"
|
||||||
git push origin master
|
git push origin master
|
||||||
dotnet publish -c Release -o ./publish
|
dotnet publish -c Release -o ./publish
|
||||||
|
|
||||||
|
# devtest
|
||||||
|
Invoke-WebRequest -Uri "http://localhost:5000/api/kill-process" -Method POST -Body "1234" -Headers @{ "X-API-KEY" = "b7f3e8a1-4c2d-4d9f-9a6e-2a1c5d7f8e9a" }
|
||||||
|
|
||||||
|
Invoke-WebRequest -Uri "http://192.168.50.52:5000/api/resource-usage" -Method GET -Headers @{ "X-API-KEY" = "b7f3e8a1-4c2d-4d9f-9a6e-2a1c5d7f8e9a" }
|
||||||
|
|
||||||
|
Use 'shutdown', 'restart', or 'cancel'.
|
||||||
|
Invoke-WebRequest -Uri "http://192.168.50.52:5000/api/force-shutdown" `
|
||||||
|
-Method POST `
|
||||||
|
-Headers @{ "X-API-KEY" = "b7f3e8a1-4c2d-4d9f-9a6e-2a1c5d7f8e9a" } `
|
||||||
|
-Body '{"Action": "shutdown", "DelaySeconds": 120}' `
|
||||||
|
-ContentType "application/json"
|
||||||
|
|||||||
@@ -25,12 +25,35 @@ namespace ResourceMonitorService
|
|||||||
builder.Services.AddCors(options =>
|
builder.Services.AddCors(options =>
|
||||||
{
|
{
|
||||||
options.AddPolicy("AllowAllOrigins",
|
options.AddPolicy("AllowAllOrigins",
|
||||||
builder => builder.AllowAnyOrigin()
|
builder => builder
|
||||||
|
.WithOrigins("http://localhost:4200","http://192.168.50.52:4200","http://vmwin11:4200")
|
||||||
.AllowAnyHeader()
|
.AllowAnyHeader()
|
||||||
.AllowAnyMethod());
|
.AllowAnyMethod());
|
||||||
});
|
});
|
||||||
builder.Services.AddControllers().AddNewtonsoftJson();
|
builder.Services.AddControllers().AddNewtonsoftJson();
|
||||||
|
|
||||||
|
// Read the API key from appsettings.json
|
||||||
|
var configuration = builder.Configuration;
|
||||||
|
var apiKey = configuration["ApiSettings:ApiKey"];
|
||||||
|
|
||||||
var app = builder.Build();
|
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
|
// Apply CORS policy to allow all origins
|
||||||
app.UseCors("AllowAllOrigins");
|
app.UseCors("AllowAllOrigins");
|
||||||
|
|
||||||
@@ -94,6 +117,88 @@ namespace ResourceMonitorService
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* 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<dynamic>(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);
|
_ = app.RunAsync(stoppingToken);
|
||||||
|
|
||||||
await Task.Delay(Timeout.Infinite, stoppingToken);
|
await Task.Delay(Timeout.Infinite, stoppingToken);
|
||||||
@@ -126,7 +231,26 @@ namespace ResourceMonitorService
|
|||||||
if (usage > 80)
|
if (usage > 80)
|
||||||
{
|
{
|
||||||
// Get the current processes and sort them by CPU usage in descending order
|
// Get the current processes and sort them by CPU usage in descending order
|
||||||
var processes = Process.GetProcesses().OrderByDescending(p => p.TotalProcessorTime);
|
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
|
// Create a new anonymous type containing the CPU usage, RAM usage, and the top 3 highest CPU-using processes
|
||||||
return new
|
return new
|
||||||
@@ -190,6 +314,21 @@ namespace ResourceMonitorService
|
|||||||
|
|
||||||
private object GetGpuUsage()
|
private object GetGpuUsage()
|
||||||
{
|
{
|
||||||
|
/* if (!IsNvidiaGpuPresent())
|
||||||
|
{
|
||||||
|
return new
|
||||||
|
{
|
||||||
|
Usage = 0,
|
||||||
|
Temperature = 0,
|
||||||
|
FanSpeed = 0,
|
||||||
|
IsAvailable = false,
|
||||||
|
Message = "No NVIDIA GPU detected"
|
||||||
|
};
|
||||||
|
} */
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
NvmlWrapper.NvmlInit();
|
NvmlWrapper.NvmlInit();
|
||||||
IntPtr device;
|
IntPtr device;
|
||||||
NvmlWrapper.NvmlDeviceGetHandleByIndex(0, out device);
|
NvmlWrapper.NvmlDeviceGetHandleByIndex(0, out device);
|
||||||
@@ -208,9 +347,53 @@ namespace ResourceMonitorService
|
|||||||
{
|
{
|
||||||
Usage = utilization.Gpu,
|
Usage = utilization.Gpu,
|
||||||
Temperature = temperature,
|
Temperature = temperature,
|
||||||
FanSpeed = fanSpeed
|
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()
|
private object GetCurrentlyRunningGame()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,5 +12,8 @@
|
|||||||
"Url": "http://*:5000"
|
"Url": "http://*:5000"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ApiSettings": {
|
||||||
|
"ApiKey": "b7f3e8a1-4c2d-4d9f-9a6e-2a1c5d7f8e9a"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# PowerShell script to create a new inbound rule in Windows Firewall
|
# PowerShell script to create a new inbound rule in Windows Firewall
|
||||||
$port = 5000
|
$port = 5000
|
||||||
$ruleName = "ResourceMonitorService"
|
$ruleName = "ResourceMonitorServicePublish"
|
||||||
if (Get-NetFirewallRule -DisplayName $ruleName) {
|
if (Get-NetFirewallRule -DisplayName $ruleName) {
|
||||||
Write-Host "Rule already exists, not creating a new one"
|
Write-Host "Rule already exists, not creating a new one"
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
sc create ResourceMonitorServicerrr binPath= "%~dp0ResourceMonitorService.exe --windows-service" start= auto
|
sc create ResourceMonitorService binPath="%~dp0ResourceMonitorService.exe --windows-service" start= auto
|
||||||
sc description ResourceMonitorServicerrr "A service that monitors system resource usage and exposes it via a web API."
|
sc description ResourceMonitorService "A service that monitors system resource usage and exposes it via a web API."
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RunAsWindowsService": true,
|
||||||
|
"Kestrel": {
|
||||||
|
"Endpoints": {
|
||||||
|
"Http": {
|
||||||
|
"Url": "http://*:5000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ApiSettings": {
|
||||||
|
"ApiKey": "b7f3e8a1-4c2d-4d9f-9a6e-2a1c5d7f8e9a"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RunAsWindowsService": true,
|
||||||
|
"Kestrel": {
|
||||||
|
"Endpoints": {
|
||||||
|
"Http": {
|
||||||
|
"Url": "http://*:5000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ApiSettings": {
|
||||||
|
"ApiKey": "b7f3e8a1-4c2d-4d9f-9a6e-2a1c5d7f8e9a"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RunAsWindowsService": true,
|
||||||
|
"Kestrel": {
|
||||||
|
"Endpoints": {
|
||||||
|
"Http": {
|
||||||
|
"Url": "http://*:5000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ApiSettings": {
|
||||||
|
"ApiKey": "b7f3e8a1-4c2d-4d9f-9a6e-2a1c5d7f8e9a"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user