A:增加消息记录功能
This commit is contained in:
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; }
|
||||
}
|
||||
Reference in new issue
Block a user