164 lines
6.3 KiB
C#
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;
|
|
}
|
|
}
|