Initial commit to new repository
This commit is contained in:
163
src/AxCopilot/Handlers/MonitorHandler.cs
Normal file
163
src/AxCopilot/Handlers/MonitorHandler.cs
Normal file
@@ -0,0 +1,163 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user