A:增加消息记录功能

This commit is contained in:
jimmy committed 2025-08-01 16:57:59 +08:00
1 parent 2f6e912c58
commit 2f54037836
14 files changed
+1975 -121

No files matched your search

@@ -0,0 +1,83 @@
using Data.Core;
using Data.Models;
using Data.Repositories;
namespace Data.Services;
public interface IDataService
{
Task InitializeAsync();
Task<AppSetting> GetOrCreateDefaultSettingAsync();
IAppSettingRepository AppSettings { get; }
IAppInfoRepository AppInfos { get; }
INetworkRepository Networks { get; }
DatabaseWriteManager WriteManager { get; }
NetworkDataCollectionService CollectionService { get; }
Task<bool> IsHealthyAsync();
}
public class DataService : IDataService, IDisposable
{
private readonly NetVizorDbContext _context;
private readonly Lazy<IAppSettingRepository> _appSettingRepository;
private readonly Lazy<IAppInfoRepository> _appInfoRepository;
private readonly Lazy<INetworkRepository> _networkRepository;
private readonly DatabaseWriteManager _writeManager;
private readonly NetworkDataCollectionService _collectionService;
public DataService(string databasePath)
{
_context = new NetVizorDbContext(databasePath);
_appSettingRepository = new Lazy<IAppSettingRepository>(() => new AppSettingRepository(_context));
_appInfoRepository = new Lazy<IAppInfoRepository>(() => new AppInfoRepository(_context));
_networkRepository = new Lazy<INetworkRepository>(() => new NetworkRepository(_context));
// 创建写入管理器和数据收集服务
_writeManager = new DatabaseWriteManager(this);
_collectionService = new NetworkDataCollectionService(_writeManager);
}
public IAppSettingRepository AppSettings => _appSettingRepository.Value;
public IAppInfoRepository AppInfos => _appInfoRepository.Value;
public INetworkRepository Networks => _networkRepository.Value;
public DatabaseWriteManager WriteManager => _writeManager;
public NetworkDataCollectionService CollectionService => _collectionService;
public async Task InitializeAsync()
{
await _context.InitializeDatabaseAsync();
}
public async Task<AppSetting> GetOrCreateDefaultSettingAsync()
{
var setting = await AppSettings.GetCurrentSettingAsync();
if (setting == null)
{
// 创建默认设置
setting = new AppSetting
{
WindowX = 100,
WindowY = 100,
AutoStart = false,
UpdateTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
};
setting.Id = await AppSettings.SaveSettingAsync(setting);
}
return setting;
}
public async Task<bool> IsHealthyAsync()
{
return await _context.IsHealthyAsync();
}
public void Dispose()
{
_collectionService?.Dispose();
_writeManager?.Dispose();
_context?.Dispose();
}
}
@@ -0,0 +1,333 @@
using System.Collections.Concurrent;
using Application.Utils;
using Common.Logger;
using Common.Utils;
using Data.Core;
using Data.Models;
using Infrastructure.utils;
using Utils.ETW.Etw;
namespace Data.Services;
/// <summary>
/// 网络数据收集服务
/// 负责全局网速监控和ETW网络数据收集
/// </summary>
public class NetworkDataCollectionService : IDisposable
{
private readonly DatabaseWriteManager _writeManager;
private readonly Timer _globalNetworkTimer;
private readonly Timer _etwNetworkTimer;
private readonly Timer _networkInterfaceUpdateTimer;
private readonly Timer _batchFlushTimer;
// 网卡信息缓存
private readonly ConcurrentDictionary<string, BasicNetworkMonitor.BasicNetworkInterface> _networkInterfaces = new();
private DateTime _lastNetworkInterfaceUpdate = DateTime.MinValue;
// ETW数据缓存(只保留最活跃的前100条)
private readonly ConcurrentDictionary<string, AppNetworkData> _activeConnections = new();
// AppId生成工具
private readonly ConcurrentDictionary<int, string> _processAppIdCache = new();
public NetworkDataCollectionService(DatabaseWriteManager writeManager)
{
_writeManager = writeManager;
// 每5秒收集一次全局网络数据
_globalNetworkTimer = new Timer(CollectGlobalNetworkData, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
// 每分钟收集一次ETW网络数据(需要管理员权限)
_etwNetworkTimer = new Timer(CollectEtwNetworkData, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
// 每分钟更新一次网卡列表
_networkInterfaceUpdateTimer = new Timer(UpdateNetworkInterfaces, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
// 每30秒强制刷新一次批处理缓存
_batchFlushTimer = new Timer(async _ => await _writeManager.FlushAllBatchesAsync(), null,
TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30));
Log.Information("网络数据收集服务已启动");
}
/// <summary>
/// 收集全局网络数据
/// </summary>
private async void CollectGlobalNetworkData(object state)
{
try
{
var connectedInterfaces = _networkInterfaces.Values
.Where(i => i.IsConnected)
.ToList();
if (connectedInterfaces.Count == 0)
{
Log.Debug("没有找到活跃的网络接口");
return;
}
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
foreach (var networkInterface in connectedInterfaces)
{
try
{
var speed = BasicNetworkMonitor.CalculateSpeedById(networkInterface.Id);
if (speed.DownloadSpeed > 0 || speed.UploadSpeed > 0)
{
var globalNetwork = new GlobalNetwork
{
Timestep = timestamp,
Upload = (long)speed.UploadSpeed,
Download = (long)speed.DownloadSpeed,
NetworkCardGuid = networkInterface.Id
};
await _writeManager.SaveGlobalNetworkAsync(globalNetwork);
Log.Debug(
$"记录网卡 {networkInterface.Name} 速度: 上传={speed.UploadSpeedText}, 下载={speed.DownloadSpeedText}");
}
}
catch (Exception ex)
{
Log.Warning($"收集网卡 {networkInterface.Name} 数据时出错");
}
}
}
catch (Exception ex)
{
Log.Error(ex, "收集全局网络数据时发生错误");
}
}
/// <summary>
/// 收集ETW网络数据(需要管理员权限)
/// </summary>
private async void CollectEtwNetworkData(object state)
{
try
{
// 检查是否有管理员权限
if (!SysHelper.IsAdministrator())
{
Log.Warning("ETW网络监控需要管理员权限,跳过收集");
return;
}
var snapshot = GlobalNetworkMonitor.Instance.GetSnapshot();
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
Log.Information($"开始收集ETW网络数据,共找到 {snapshot.Applications.Count} 个应用程序");
foreach (var app in snapshot.Applications)
{
try
{
// 生成或获取AppId
var appId = await GetOrGenerateAppIdAsync(app.ProcessId, app.ProgramInfo);
if (string.IsNullOrEmpty(appId))
{
continue;
}
// 保存应用信息到数据库(如果不存在)
if (app.ProgramInfo != null)
{
// 检查应用信息是否已存在
var appExists = await _writeManager.AppExistsAsync(appId);
if (!appExists)
{
var appInfo = new AppInfo
{
AppId = appId,
Name = app.ProgramInfo.ProcessName ?? "Unknown",
Path = app.ProgramInfo.MainModulePath ?? "",
Version = app.ProgramInfo.Version ?? "",
Company = app.ProgramInfo.CompanyName ?? "",
Base64Icon = app.ProgramInfo.IconBase64 ?? "",
Hash = app.ProgramInfo.FileDescription ?? ""
};
await _writeManager.SaveAppInfoAsync(appInfo);
}
}
// 只保留最活跃的前100个连接
var activeConnections = app.Connections
.Where(c => c.IsActive && (c.BytesSent > 0 || c.BytesReceived > 0))
.OrderByDescending(c => c.BytesSent + c.BytesReceived)
.Take(100)
.ToList();
foreach (var connection in activeConnections)
{
var appNetwork = new AppNetwork
{
Timestamp = timestamp,
LocalIP = connection.LocalIp,
LocalPort = connection.LocalPort,
RemoteIP = connection.RemoteIp,
RemotePort = connection.RemotePort,
Protocol = connection.Protocol,
UploadBytes = connection.BytesSent,
DownloadBytes = connection.BytesReceived,
AppId = appId
};
await _writeManager.SaveAppNetworkAsync(appNetwork);
}
if (activeConnections.Count > 0)
{
Log.Debug($"记录应用 {app.ProgramInfo?.ProcessName} 的 {activeConnections.Count} 个网络连接");
}
}
catch (Exception ex)
{
Log.Warning($"处理应用 {app.ProcessId} 的网络数据时出错", ex);
}
}
Log.Information($"ETW网络数据收集完成,处理了 {snapshot.Applications.Count} 个应用程序");
}
catch (Exception ex)
{
Log.Error(ex, "收集ETW网络数据时发生错误");
}
}
/// <summary>
/// 更新网络接口列表
/// </summary>
private void UpdateNetworkInterfaces(object state)
{
try
{
var interfaces = BasicNetworkMonitor.GetConnectedNetworkInterfaces();
_networkInterfaces.Clear();
foreach (var networkInterface in interfaces)
{
_networkInterfaces.TryAdd(networkInterface.Id, networkInterface);
}
_lastNetworkInterfaceUpdate = DateTime.UtcNow;
Log.Information($"更新网络接口列表,共找到 {interfaces.Count} 个活跃接口");
}
catch (Exception ex)
{
Log.Error(ex, "更新网络接口列表时发生错误");
}
}
/// <summary>
/// 获取或生成应用程序ID
/// </summary>
private async Task<string> GetOrGenerateAppIdAsync(int processId, Infrastructure.Models.ProgramInfo programInfo)
{
// 先检查缓存
if (_processAppIdCache.TryGetValue(processId, out var cachedAppId))
{
return cachedAppId;
}
try
{
// 如果没有程序信息,尝试从系统获取
if (programInfo == null)
{
programInfo = SysInfoUtils.InspectProcess(processId);
}
if (programInfo == null)
{
Log.Warning($"无法获取进程 {processId} 的信息");
return null;
}
// 生成AppId: 路径 + 文件签名发布者 + 进程名
var path = programInfo.MainModulePath ?? "";
var publisher = programInfo.CompanyName ?? "";
var processName = programInfo.ProcessName ?? "Unknown";
var appId = $"{path}|{publisher}|{processName}";
// 缓存AppId
_processAppIdCache.TryAdd(processId, appId);
return appId;
}
catch (Exception ex)
{
Log.Warning($"生成进程 {processId} 的AppId时出错", ex);
return null;
}
}
/// <summary>
/// 获取收集统计信息
/// </summary>
public NetworkCollectionStats GetStats()
{
return new NetworkCollectionStats
{
ActiveNetworkInterfaces = _networkInterfaces.Count,
LastNetworkInterfaceUpdate = _lastNetworkInterfaceUpdate,
CachedProcessCount = _processAppIdCache.Count,
ActiveConnectionsCount = _activeConnections.Count
};
}
public void Dispose()
{
Log.Information("正在关闭网络数据收集服务...");
_globalNetworkTimer?.Dispose();
_etwNetworkTimer?.Dispose();
_networkInterfaceUpdateTimer?.Dispose();
_batchFlushTimer?.Dispose();
// 强制刷新所有批处理数据
try
{
_writeManager.FlushAllBatchesAsync().Wait(TimeSpan.FromSeconds(10));
}
catch (Exception ex)
{
Log.Warning("关闭时刷新批处理数据失败", ex);
}
Log.Information("网络数据收集服务已关闭");
}
}
/// <summary>
/// 应用网络数据(用于缓存)
/// </summary>
public class AppNetworkData
{
public string AppId { get; set; }
public long TotalUpload { get; set; }
public long TotalDownload { get; set; }
public DateTime LastUpdate { get; set; }
public int ConnectionCount { get; set; }
}
/// <summary>
/// 网络收集统计信息
/// </summary>
public class NetworkCollectionStats
{
public int ActiveNetworkInterfaces { get; set; }
public DateTime LastNetworkInterfaceUpdate { get; set; }
public int CachedProcessCount { get; set; }
public int ActiveConnectionsCount { get; set; }
}