152 lines
5.4 KiB
C#
152 lines
5.4 KiB
C#
using System.IO;
|
|
|
|
namespace AxCopilot.Services;
|
|
|
|
/// <summary>
|
|
/// 앱의 저장 공간 사용량을 분석하고 정리 기능을 제공합니다.
|
|
/// </summary>
|
|
public static class StorageAnalyzer
|
|
{
|
|
private static readonly string AppDataDir = Path.Combine(
|
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "AxCopilot");
|
|
|
|
/// <summary>저장 공간 분석 결과를 반환합니다.</summary>
|
|
public static StorageReport Analyze()
|
|
{
|
|
var report = new StorageReport();
|
|
|
|
// 앱 데이터 폴더별 크기 계산
|
|
report.Conversations = GetFolderSize(Path.Combine(AppDataDir, "conversations"));
|
|
report.AuditLogs = GetFolderSize(Path.Combine(AppDataDir, "audit"));
|
|
report.Logs = GetFolderSize(Path.Combine(AppDataDir, "logs"));
|
|
report.CodeIndex = GetFolderSize(Path.Combine(AppDataDir, "code_index"));
|
|
report.EmbeddingDb = GetFolderSize(Path.Combine(AppDataDir, "embeddings"));
|
|
report.ClipboardHistory = GetFileSize(Path.Combine(AppDataDir, "clipboard_history.dat"));
|
|
report.Plugins = GetFolderSize(Path.Combine(AppDataDir, "plugins"));
|
|
report.Skills = GetFolderSize(Path.Combine(AppDataDir, "skills"));
|
|
report.Settings = GetFileSize(Path.Combine(AppDataDir, "settings.json"));
|
|
|
|
// 앱 실행 파일 위치의 드라이브 여유 공간
|
|
var exeDir = Path.GetDirectoryName(Environment.ProcessPath) ?? AppDataDir;
|
|
try
|
|
{
|
|
var drive = new DriveInfo(Path.GetPathRoot(exeDir) ?? "C:");
|
|
report.DriveLabel = drive.Name;
|
|
report.DriveFreeSpace = drive.AvailableFreeSpace;
|
|
report.DriveTotalSpace = drive.TotalSize;
|
|
}
|
|
catch { }
|
|
|
|
return report;
|
|
}
|
|
|
|
/// <summary>지정된 기간보다 오래된 데이터를 삭제합니다.</summary>
|
|
/// <param name="retainDays">보관 일수 (7/14/30). 0이면 전체 삭제.</param>
|
|
/// <returns>삭제된 바이트 수</returns>
|
|
public static long Cleanup(int retainDays, bool cleanConversations, bool cleanAuditLogs,
|
|
bool cleanLogs, bool cleanCodeIndex, bool cleanClipboard)
|
|
{
|
|
long freed = 0;
|
|
var cutoff = DateTime.Now.AddDays(-retainDays);
|
|
|
|
if (cleanConversations)
|
|
freed += CleanFolder(Path.Combine(AppDataDir, "conversations"), cutoff, retainDays == 0);
|
|
|
|
if (cleanAuditLogs)
|
|
freed += CleanFolder(Path.Combine(AppDataDir, "audit"), cutoff, retainDays == 0);
|
|
|
|
if (cleanLogs)
|
|
freed += CleanFolder(Path.Combine(AppDataDir, "logs"), cutoff, retainDays == 0);
|
|
|
|
if (cleanCodeIndex)
|
|
freed += CleanFolder(Path.Combine(AppDataDir, "code_index"), cutoff, true); // 인덱스는 전체 삭제
|
|
|
|
if (cleanClipboard)
|
|
{
|
|
var clipFile = Path.Combine(AppDataDir, "clipboard_history.dat");
|
|
if (File.Exists(clipFile))
|
|
{
|
|
freed += new FileInfo(clipFile).Length;
|
|
File.Delete(clipFile);
|
|
}
|
|
}
|
|
|
|
return freed;
|
|
}
|
|
|
|
private static long GetFolderSize(string path)
|
|
{
|
|
if (!Directory.Exists(path)) return 0;
|
|
try
|
|
{
|
|
return Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)
|
|
.Sum(f => { try { return new FileInfo(f).Length; } catch { return 0; } });
|
|
}
|
|
catch { return 0; }
|
|
}
|
|
|
|
private static long GetFileSize(string path)
|
|
{
|
|
try { return File.Exists(path) ? new FileInfo(path).Length : 0; }
|
|
catch { return 0; }
|
|
}
|
|
|
|
private static long CleanFolder(string path, DateTime cutoff, bool deleteAll)
|
|
{
|
|
if (!Directory.Exists(path)) return 0;
|
|
long freed = 0;
|
|
|
|
foreach (var file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories))
|
|
{
|
|
try
|
|
{
|
|
var fi = new FileInfo(file);
|
|
if (deleteAll || fi.LastWriteTime < cutoff)
|
|
{
|
|
freed += fi.Length;
|
|
fi.Delete();
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
// 빈 디렉토리 정리
|
|
if (deleteAll)
|
|
{
|
|
try { Directory.Delete(path, true); Directory.CreateDirectory(path); } catch { }
|
|
}
|
|
|
|
return freed;
|
|
}
|
|
|
|
/// <summary>바이트를 읽기 좋은 형태로 변환합니다.</summary>
|
|
public static string FormatSize(long bytes)
|
|
{
|
|
if (bytes < 1024) return $"{bytes} B";
|
|
if (bytes < 1024 * 1024) return $"{bytes / 1024.0:F1} KB";
|
|
if (bytes < 1024L * 1024 * 1024) return $"{bytes / (1024.0 * 1024):F1} MB";
|
|
return $"{bytes / (1024.0 * 1024 * 1024):F2} GB";
|
|
}
|
|
}
|
|
|
|
/// <summary>저장 공간 분석 결과.</summary>
|
|
public class StorageReport
|
|
{
|
|
public long Conversations { get; set; }
|
|
public long AuditLogs { get; set; }
|
|
public long Logs { get; set; }
|
|
public long CodeIndex { get; set; }
|
|
public long EmbeddingDb { get; set; }
|
|
public long ClipboardHistory { get; set; }
|
|
public long Plugins { get; set; }
|
|
public long Skills { get; set; }
|
|
public long Settings { get; set; }
|
|
|
|
public string DriveLabel { get; set; } = "";
|
|
public long DriveFreeSpace { get; set; }
|
|
public long DriveTotalSpace { get; set; }
|
|
|
|
/// <summary>앱 전체 사용량.</summary>
|
|
public long TotalAppUsage => Conversations + AuditLogs + Logs + CodeIndex + EmbeddingDb + ClipboardHistory + Plugins + Skills + Settings;
|
|
}
|