using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Extensions.Logging;
using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace JiShe.CollectBus.PluginFileWatcher
{
///
/// 数据库操作工具类,用于命令行测试数据库功能
///
public class DbUtility
{
private readonly EventDatabaseManager _dbManager;
private readonly ILogger _logger;
private readonly FileMonitorConfig _config;
///
/// 初始化数据库工具类
///
/// 配置文件路径
public DbUtility(string configPath = "appsettings.json")
{
// 从配置文件加载配置
var configuration = new ConfigurationBuilder()
.AddJsonFile(configPath, optional: false, reloadOnChange: true)
.Build();
// 初始化日志
var serilogLogger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
// 将Serilog适配为Microsoft.Extensions.Logging.ILogger
_logger = new SerilogLoggerFactory(serilogLogger).CreateLogger("DbUtility");
// 创建配置对象
_config = new FileMonitorConfig();
configuration.GetSection("FileMonitor").Bind(_config);
// 确保SQLite存储已启用
_config.EventStorage.EnableEventStorage = true;
_config.EventStorage.StorageType = "SQLite";
// 创建数据库管理器
_dbManager = new EventDatabaseManager(_config, _logger);
}
///
/// 执行数据库维护操作
///
/// 命令行参数
public async Task ExecuteAsync(string[] args)
{
if (args.Length == 0)
{
PrintUsage();
return;
}
string command = args[0].ToLower();
switch (command)
{
case "stats":
await ShowStatisticsAsync();
break;
case "cleanup":
int days = args.Length > 1 && int.TryParse(args[1], out int d) ? d : _config.EventStorage.DataRetentionDays;
await _dbManager.CleanupOldDataAsync(days);
Console.WriteLine($"已清理 {days} 天前的旧数据");
break;
case "query":
await QueryEventsAsync(args);
break;
case "test":
await GenerateTestDataAsync(args);
break;
default:
Console.WriteLine($"未知命令: {command}");
PrintUsage();
break;
}
}
///
/// 显示帮助信息
///
private void PrintUsage()
{
Console.WriteLine("数据库工具使用方法:");
Console.WriteLine(" stats - 显示数据库统计信息");
Console.WriteLine(" cleanup [days] - 清理指定天数之前的数据(默认使用配置值)");
Console.WriteLine(" query [limit] - 查询最近的事件(默认10条)");
Console.WriteLine(" query type:X ext:Y - 按类型和扩展名查询事件");
Console.WriteLine(" test [count] - 生成测试数据(默认100条)");
}
///
/// 显示数据库统计信息
///
private async Task ShowStatisticsAsync()
{
try
{
var stats = await _dbManager.GetDatabaseStatsAsync();
Console.WriteLine("数据库统计信息:");
Console.WriteLine($"事件总数: {stats.TotalEvents}");
Console.WriteLine($"最早事件时间: {stats.OldestEventTime?.ToLocalTime()}");
Console.WriteLine($"最新事件时间: {stats.NewestEventTime?.ToLocalTime()}");
Console.WriteLine("\n事件类型分布:");
if (stats.EventTypeCounts != null)
{
foreach (var item in stats.EventTypeCounts)
{
Console.WriteLine($" {item.Key}: {item.Value}");
}
}
Console.WriteLine("\n扩展名分布 (Top 10):");
if (stats.TopExtensions != null)
{
foreach (var item in stats.TopExtensions)
{
Console.WriteLine($" {item.Key}: {item.Value}");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"获取统计信息出错: {ex.Message}");
_logger.LogError(ex, "获取数据库统计信息时发生错误");
}
}
///
/// 查询事件
///
private async Task QueryEventsAsync(string[] args)
{
try
{
var queryParams = new EventQueryParams
{
PageSize = 10,
PageIndex = 0
};
// 解析查询参数
if (args.Length > 1)
{
foreach (var arg in args.Skip(1))
{
if (int.TryParse(arg, out int limit))
{
queryParams.PageSize = limit;
}
else if (arg.StartsWith("type:", StringComparison.OrdinalIgnoreCase))
{
string typeValue = arg.Substring(5);
if (Enum.TryParse(typeValue, true, out var eventType))
{
queryParams.EventType = eventType;
}
}
else if (arg.StartsWith("ext:", StringComparison.OrdinalIgnoreCase))
{
queryParams.ExtensionFilter = arg.Substring(4);
if (!queryParams.ExtensionFilter.StartsWith("."))
{
queryParams.ExtensionFilter = "." + queryParams.ExtensionFilter;
}
}
else if (arg.StartsWith("path:", StringComparison.OrdinalIgnoreCase))
{
queryParams.PathFilter = arg.Substring(5);
}
}
}
// 执行查询
var result = await _dbManager.QueryEventsAsync(queryParams);
Console.WriteLine($"查询结果 (总数: {result.TotalCount}):");
foreach (var evt in result.Events)
{
string typeStr = evt.EventType.ToString();
string timestamp = evt.Timestamp.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss");
Console.WriteLine($"[{timestamp}] {typeStr,-10} {evt.FileName} ({evt.Extension})");
}
if (result.HasMore)
{
Console.WriteLine($"... 还有更多结果,共 {result.TotalCount} 条");
}
}
catch (Exception ex)
{
Console.WriteLine($"查询事件出错: {ex.Message}");
_logger.LogError(ex, "查询事件时发生错误");
}
}
///
/// 生成测试数据
///
private async Task GenerateTestDataAsync(string[] args)
{
try
{
int count = args.Length > 1 && int.TryParse(args[1], out int c) ? c : 100;
var events = new List();
var rnd = new Random();
string[] extensions = { ".dll", ".exe", ".txt", ".cs", ".xml", ".json", ".png", ".jpg" };
string[] directories = { "C:\\Temp", "D:\\Work", "C:\\Program Files", "D:\\Projects", "E:\\Data" };
DateTime startTime = DateTime.Now.AddHours(-24);
for (int i = 0; i < count; i++)
{
var eventType = (FileEventType)rnd.Next(0, 5);
var ext = extensions[rnd.Next(extensions.Length)];
var dir = directories[rnd.Next(directories.Length)];
var fileName = $"TestFile_{i:D5}{ext}";
var timestamp = startTime.AddMinutes(i);
var fileEvent = new FileEvent
{
Id = Guid.NewGuid(),
Timestamp = timestamp,
EventType = eventType,
FullPath = $"{dir}\\{fileName}",
FileName = fileName,
Directory = dir,
Extension = ext,
FileSize = rnd.Next(1024, 1024 * 1024)
};
// 如果是重命名事件,添加旧文件名
if (eventType == FileEventType.Renamed)
{
fileEvent.OldFileName = $"OldFile_{i:D5}{ext}";
fileEvent.OldFullPath = $"{dir}\\{fileEvent.OldFileName}";
}
// 添加一些元数据
fileEvent.Metadata["CreationTime"] = timestamp.AddMinutes(-rnd.Next(1, 60)).ToString("o");
fileEvent.Metadata["LastWriteTime"] = timestamp.ToString("o");
fileEvent.Metadata["IsReadOnly"] = (rnd.Next(10) < 2).ToString();
fileEvent.Metadata["TestData"] = $"测试数据 {i}";
events.Add(fileEvent);
}
Console.WriteLine($"正在生成 {count} 条测试数据...");
await _dbManager.SaveEventsAsync(events);
Console.WriteLine("测试数据生成完成!");
}
catch (Exception ex)
{
Console.WriteLine($"生成测试数据出错: {ex.Message}");
_logger.LogError(ex, "生成测试数据时发生错误");
}
}
}
}