Files
AX-Copilot-Codex/src/AxCopilot/Handlers/MonitorHandler.cs

164 lines
6.3 KiB
C#

using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
using AxCopilot.SDK;
using AxCopilot.Themes;
namespace AxCopilot.Handlers;
/// <summary>
/// 시스템 리소스 모니터 핸들러. "monitor" 프리픽스로 사용합니다.
/// CPU, 메모리, 디스크, 프로세스 수 등 실시간 시스템 리소스 정보를 표시합니다.
/// 예: monitor → 전체 리소스 현황
/// monitor cpu → CPU 관련 정보만
/// monitor mem → 메모리 관련 정보만
/// monitor disk → 디스크 사용량
/// Enter → 결과를 클립보드에 복사.
/// </summary>
public class MonitorHandler : IActionHandler
{
public string? Prefix => "monitor";
public PluginMetadata Metadata => new(
"Monitor",
"시스템 리소스 모니터 — monitor",
"1.0",
"AX");
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);
[StructLayout(LayoutKind.Sequential)]
private 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;
}
public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
{
var q = query.Trim().ToLowerInvariant();
var items = new List<LauncherItem>();
var showAll = string.IsNullOrWhiteSpace(q);
// CPU
if (showAll || q.Contains("cpu") || q.Contains("프로세서"))
{
var cpuCount = Environment.ProcessorCount;
var processes = Process.GetProcesses().Length;
var threads = 0;
try { threads = Process.GetProcesses().Sum(p => { try { return p.Threads.Count; } catch { return 0; } }); }
catch { }
items.Add(new LauncherItem(
$"CPU: {cpuCount}코어 · 프로세스 {processes}개 · 스레드 {threads:N0}개",
"Enter로 클립보드 복사",
null, $"CPU: {cpuCount}코어, 프로세스 {processes}개, 스레드 {threads:N0}개",
Symbol: Symbols.Processor));
}
// Memory
if (showAll || q.Contains("mem") || q.Contains("ram") || q.Contains("메모리"))
{
var mem = new MEMORYSTATUSEX { dwLength = (uint)Marshal.SizeOf<MEMORYSTATUSEX>() };
GlobalMemoryStatusEx(ref mem);
var totalGB = mem.ullTotalPhys / (1024.0 * 1024 * 1024);
var usedGB = (mem.ullTotalPhys - mem.ullAvailPhys) / (1024.0 * 1024 * 1024);
var pct = mem.dwMemoryLoad;
items.Add(new LauncherItem(
$"메모리: {usedGB:F1}GB / {totalGB:F1}GB ({pct}% 사용)",
$"사용 가능: {mem.ullAvailPhys / (1024.0 * 1024 * 1024):F1}GB · Enter로 복사",
null, $"메모리: {usedGB:F1}GB / {totalGB:F1}GB ({pct}% 사용)",
Symbol: Symbols.Memory));
}
// Disk
if (showAll || q.Contains("disk") || q.Contains("디스크") || q.Contains("저장"))
{
foreach (var drive in System.IO.DriveInfo.GetDrives())
{
if (!drive.IsReady || drive.DriveType != System.IO.DriveType.Fixed) continue;
var totalGB = drive.TotalSize / (1024.0 * 1024 * 1024);
var freeGB = drive.AvailableFreeSpace / (1024.0 * 1024 * 1024);
var usedGB = totalGB - freeGB;
var pct = (int)(usedGB / totalGB * 100);
items.Add(new LauncherItem(
$"디스크 {drive.Name.TrimEnd('\\')} {usedGB:F0}GB / {totalGB:F0}GB ({pct}%)",
$"여유: {freeGB:F1}GB · {drive.DriveFormat} · Enter로 복사",
null, $"디스크 {drive.Name}: {usedGB:F0}GB / {totalGB:F0}GB ({pct}%), 여유 {freeGB:F1}GB",
Symbol: Symbols.Storage));
}
}
// Uptime
if (showAll || q.Contains("uptime") || q.Contains("가동"))
{
var uptime = TimeSpan.FromMilliseconds(Environment.TickCount64);
var uptimeStr = uptime.Days > 0
? $"{uptime.Days}일 {uptime.Hours}시간 {uptime.Minutes}분"
: $"{uptime.Hours}시간 {uptime.Minutes}분";
items.Add(new LauncherItem(
$"가동 시간: {uptimeStr}",
"마지막 재시작 이후 경과 · Enter로 복사",
null, $"가동 시간: {uptimeStr}",
Symbol: Symbols.Clock));
}
// Top processes by memory
if (showAll || q.Contains("top") || q.Contains("프로세스"))
{
try
{
var topProcs = Process.GetProcesses()
.Where(p => { try { return p.WorkingSet64 > 0; } catch { return false; } })
.OrderByDescending(p => { try { return p.WorkingSet64; } catch { return 0L; } })
.Take(5)
.Select(p =>
{
try { return $"{p.ProcessName} ({p.WorkingSet64 / (1024 * 1024)}MB)"; }
catch { return p.ProcessName; }
});
items.Add(new LauncherItem(
"메모리 상위 프로세스",
string.Join(", ", topProcs),
null, $"메모리 상위: {string.Join(", ", topProcs)}",
Symbol: Symbols.Computer));
}
catch { }
}
if (items.Count == 0)
{
items.Add(new LauncherItem(
$"'{q}'에 해당하는 리소스 항목 없음",
"cpu / mem / disk / uptime / top",
null, null, Symbol: Symbols.Warning));
}
return Task.FromResult<IEnumerable<LauncherItem>>(items);
}
public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
{
if (item.Data is string text && !string.IsNullOrWhiteSpace(text))
{
try { Application.Current?.Dispatcher.Invoke(() => Clipboard.SetText(text)); }
catch { }
}
return Task.CompletedTask;
}
}