ThreatSourceLibaray/ThreatSource/src/Data/ThreatSourceDataManager.cs

486 lines
21 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Tomlyn;
using System.Diagnostics;
using System.Reflection;
namespace ThreatSource.Data
{
/// <summary>
/// 威胁源数据管理器,负责加载和管理所有设备的配置数据
/// </summary>
/// <remarks>
/// 该类提供以下功能:
/// - 加载配置数据
/// - 获取可用设备列表
/// - 获取设备配置数据
/// 用于统一管理威胁源库中的各类设备数据
/// </remarks>
public class ThreatSourceDataManager
{
/// <summary>
/// 默认数据目录名称
/// </summary>
private static readonly string DEFAULT_DATA_FOLDER = "data";
/// <summary>
/// 回退数据目录路径(向后兼容)
/// </summary>
private static readonly string FALLBACK_DATA_PATH = "data";
private static readonly TomlModelOptions _tomlOptions = new()
{
ConvertPropertyName = name => name
};
private readonly Dictionary<string, MissileData> _missiles = [];
private readonly Dictionary<string, IndicatorData> _indicators = [];
private readonly Dictionary<string, SensorData> _sensors = [];
private readonly Dictionary<string, EquipmentData> _equipments = [];
private readonly Dictionary<string, WeatherData> _weathers = [];
private readonly Dictionary<string, JammerData> _jammers = [];
/// <summary>
/// 获取数据目录路径
/// 优先使用DLL上级目录的data文件夹如果不存在则回退到相对路径
/// </summary>
/// <returns>数据目录的绝对路径</returns>
private static string GetDataPath()
{
try
{
// 获取当前程序集DLL的位置
var assemblyLocation = Assembly.GetExecutingAssembly().Location;
if (!string.IsNullOrEmpty(assemblyLocation))
{
// 获取DLL所在目录的父目录
var dllDirectory = Path.GetDirectoryName(assemblyLocation);
if (!string.IsNullOrEmpty(dllDirectory))
{
var parentDirectory = Directory.GetParent(dllDirectory)?.FullName;
if (!string.IsNullOrEmpty(parentDirectory))
{
var dataPath = Path.Combine(parentDirectory, DEFAULT_DATA_FOLDER);
Debug.WriteLine($"[ThreatSourceDataManager] DLL位置: {assemblyLocation}");
Debug.WriteLine($"[ThreatSourceDataManager] 解析的data目录: {dataPath}");
if (Directory.Exists(dataPath))
{
Debug.WriteLine($"[ThreatSourceDataManager] 使用自动解析的data目录: {dataPath}");
return dataPath;
}
else
{
Debug.WriteLine($"[ThreatSourceDataManager] 自动解析的data目录不存在: {dataPath}");
}
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"[ThreatSourceDataManager] 自动路径解析失败: {ex.Message}");
}
// 回退到原始的相对路径(向后兼容)
Debug.WriteLine($"[ThreatSourceDataManager] 回退使用相对路径: {FALLBACK_DATA_PATH}");
return FALLBACK_DATA_PATH;
}
/// <summary>
/// 初始化威胁源数据管理器
/// </summary>
/// <param name="dataPath">可选的数据目录路径如果为null则使用智能路径解析</param>
public ThreatSourceDataManager(string? dataPath = null)
{
if (dataPath != null)
{
Debug.WriteLine($"[ThreatSourceDataManager] 使用用户指定的data路径: {dataPath}");
LoadData(dataPath);
}
else
{
var resolvedPath = GetDataPath();
LoadData(resolvedPath);
}
}
/// <summary>
/// 加载数据
/// </summary>
/// <param name="path">数据目录路径</param>
private void LoadData(string path)
{
Debug.WriteLine($"[ThreatSourceDataManager] 开始从路径加载数据: {Path.GetFullPath(path)}");
LoadMissiles(Path.Combine(path, "missiles"));
LoadIndicators(Path.Combine(path, "indicators"));
LoadWarners(Path.Combine(path, "warners"));
LoadTargets(Path.Combine(path, "equipments"));
LoadWeathers(Path.Combine(path, "weathers"));
LoadJammers(Path.Combine(path, "jammers"));
}
/// <summary>
/// 加载导弹数据
/// </summary>
private void LoadMissiles(string path)
{
if (!Directory.Exists(path))
{
Trace.TraceError($"导弹数据目录不存在:{path}");
return;
}
foreach (var file in Directory.GetFiles(path, "*.toml", SearchOption.AllDirectories))
{
try
{
var tomlContent = File.ReadAllText(file);
var data = Toml.ToModel<MissileData>(tomlContent, options: _tomlOptions); // Pass options
if (data != null)
{
if (data.Properties?.GuidanceSuite != null && data.Properties.GuidanceSuite.Count > 0)
{
Debug.WriteLine($"[ThreatSourceDataManager] Post-processing GuidanceSuite for missile file: {Path.GetFileName(file)} with {data.Properties.GuidanceSuite.Count} component(s).");
foreach (var componentConfig in data.Properties.GuidanceSuite)
{
if (componentConfig == null)
{
Debug.WriteLine($"[ThreatSourceDataManager] Warning: Encountered a null componentConfig in GuidanceSuite for {Path.GetFileName(file)}.");
continue;
}
string? typeKey = componentConfig.GuidanceSystemType?.ToLowerInvariant();
object? assignedConfig = null; // Will hold the config object from MissileData
string? topLevelConfigName = "UnknownPropertyInMissileData"; // For logging
switch (typeKey)
{
case "millimeterwave": // Alias
case "millimeterwaveterminalguidance":
assignedConfig = data.MillimeterWaveGuidanceConfig;
componentConfig.SpecificConfig = data.MillimeterWaveGuidanceConfig;
topLevelConfigName = nameof(data.MillimeterWaveGuidanceConfig);
break;
case "infraredimagingterminalguidance":
assignedConfig = data.InfraredImagingGuidanceConfig;
componentConfig.SpecificConfig = data.InfraredImagingGuidanceConfig;
topLevelConfigName = nameof(data.InfraredImagingGuidanceConfig);
break;
case "lasersemiactiveguidance":
assignedConfig = data.LaserSemiActiveGuidanceConfig;
componentConfig.SpecificConfig = data.LaserSemiActiveGuidanceConfig;
topLevelConfigName = nameof(data.LaserSemiActiveGuidanceConfig);
break;
case "laserbeamriderguidance":
assignedConfig = data.LaserBeamRiderGuidanceConfig;
componentConfig.SpecificConfig = data.LaserBeamRiderGuidanceConfig;
topLevelConfigName = nameof(data.LaserBeamRiderGuidanceConfig);
break;
case "infraredcommandguidance":
assignedConfig = data.InfraredCommandGuidanceConfig;
componentConfig.SpecificConfig = data.InfraredCommandGuidanceConfig;
topLevelConfigName = nameof(data.InfraredCommandGuidanceConfig);
break;
default:
Debug.WriteLine($"[ThreatSourceDataManager] Info: Component '{componentConfig.ComponentName}' (GuidanceSystemType: '{componentConfig.GuidanceSystemType}') has no explicit top-level config association logic in the current switch statement.");
break;
}
if (componentConfig.SpecificConfig != null) // Check if SpecificConfig was successfully assigned
{
Debug.WriteLine($"[ThreatSourceDataManager] Successfully associated SpecificConfig for component '{componentConfig.ComponentName}' (Type: {componentConfig.GuidanceSystemType}) with data.{topLevelConfigName} (Actual Type: {componentConfig.SpecificConfig.GetType().FullName}).");
}
else // SpecificConfig is still null
{
if (assignedConfig == null &&
(typeKey == "millimeterwaveterminalguidance" || typeKey == "millimeterwave" ||
typeKey == "infraredimagingterminalguidance" || typeKey == "lasersemiactiveguidance" ||
typeKey == "laserbeamriderguidance" || typeKey == "infraredcommandguidance"))
{
Debug.WriteLine($"[ThreatSourceDataManager] Error: SpecificConfig for component '{componentConfig.ComponentName}' (Type: {componentConfig.GuidanceSystemType}) remains NULL. The corresponding top-level config 'data.{topLevelConfigName}' was likely missing or null in the TOML file '{Path.GetFileName(file)}'.");
}
else
{
Debug.WriteLine($"[ThreatSourceDataManager] Info: SpecificConfig for component '{componentConfig.ComponentName}' (Type: {componentConfig.GuidanceSystemType}) is still null after processing. This implies no matching top-level config was found/assigned or the type is unhandled by the switch for top-level association.");
}
}
}
}
else if (data.Properties?.GuidanceSuite != null && data.Properties.GuidanceSuite.Count == 0 && data.Type == ThreatSource.Missile.MissileType.CompositeGuidance)
{
Debug.WriteLine($"[ThreatSourceDataManager] Warning: Missile file {Path.GetFileName(file)} is of type CompositeGuidance but its GuidanceSuite is empty or null.");
}
string model = Path.GetFileNameWithoutExtension(file);
_missiles[model] = data;
}
}
catch (Exception ex)
{
Trace.TraceError($"加载导弹数据文件失败:{file},错误:{ex.Message}");
Trace.TraceError($"异常堆栈:{ex.StackTrace}");
}
}
}
/// <summary>
/// 加载指示器数据
/// </summary>
private void LoadIndicators(string path)
{
if (!Directory.Exists(path))
{
Trace.TraceError($"指示器数据目录不存在:{path}");
return;
}
foreach (var file in Directory.GetFiles(path, "*.toml", SearchOption.AllDirectories))
{
try
{
var tomlContent = File.ReadAllText(file);
var data = Toml.ToModel<IndicatorData>(tomlContent, options: _tomlOptions); // Pass options
if (data != null)
{
string model = Path.GetFileNameWithoutExtension(file);
_indicators[model] = data;
}
}
catch (Exception ex)
{
Trace.TraceError($"加载指示器数据文件失败:{file},错误:{ex.Message}");
Trace.TraceError($"异常堆栈:{ex.StackTrace}");
}
}
}
/// <summary>
/// 加载告警器数据
/// </summary>
private void LoadWarners(string path)
{
if (!Directory.Exists(path))
{
Trace.TraceError($"告警器数据目录不存在:{path}");
return;
}
foreach (var file in Directory.GetFiles(path, "*.toml", SearchOption.AllDirectories))
{
try
{
var tomlContent = File.ReadAllText(file);
var data = Toml.ToModel<SensorData>(tomlContent, options: _tomlOptions); // Pass options
if (data != null)
{
string model = Path.GetFileNameWithoutExtension(file);
_sensors[model] = data;
}
}
catch (Exception ex)
{
Trace.TraceError($"加载告警器数据文件失败:{file},错误:{ex.Message}");
Trace.TraceError($"异常堆栈:{ex.StackTrace}");
}
}
}
/// <summary>
/// 加载目标数据
/// </summary>
private void LoadTargets(string path)
{
if (!Directory.Exists(path))
{
Trace.TraceError($"目标数据目录不存在:{path}");
return;
}
foreach (var file in Directory.GetFiles(path, "*.toml", SearchOption.AllDirectories))
{
try
{
var tomlContent = File.ReadAllText(file);
var data = Toml.ToModel<EquipmentData>(tomlContent, options: _tomlOptions); // Pass options
if (data != null)
{
string model = Path.GetFileNameWithoutExtension(file);
_equipments[model] = data;
}
}
catch (Exception ex)
{
Trace.TraceError($"加载目标数据文件失败:{file},错误:{ex.Message}");
Trace.TraceError($"异常堆栈:{ex.StackTrace}");
}
}
}
/// <summary>
/// 加载天气数据
/// </summary>
/// <param name="path">天气数据目录路径</param>
private void LoadWeathers(string path)
{
if (!Directory.Exists(path))
{
Trace.TraceError($"天气数据目录不存在:{path}");
return;
}
foreach (var file in Directory.GetFiles(path, "*.toml", SearchOption.AllDirectories))
{
try
{
var tomlContent = File.ReadAllText(file);
var data = Toml.ToModel<WeatherData>(tomlContent, options: _tomlOptions); // Pass options
if (data != null)
{
string model = Path.GetFileNameWithoutExtension(file);
_weathers[model] = data;
}
}
catch (Exception ex)
{
Trace.TraceError($"加载天气数据文件失败:{file},错误:{ex.Message}");
Trace.TraceError($"异常堆栈:{ex.StackTrace}");
}
}
}
/// <summary>
/// 加载干扰机数据
/// </summary>
private void LoadJammers(string path)
{
if (!Directory.Exists(path))
{
Trace.TraceError($"干扰机数据目录不存在:{path}");
return;
}
foreach (var file in Directory.GetFiles(path, "*.toml", SearchOption.AllDirectories))
{
try
{
var tomlContent = File.ReadAllText(file);
var data = Toml.ToModel<JammerData>(tomlContent, options: _tomlOptions); // Pass options
if (data != null)
{
string model = Path.GetFileNameWithoutExtension(file);
_jammers[model] = data;
}
}
catch (Exception ex)
{
Trace.TraceError($"加载干扰机数据文件失败:{file},错误:{ex.Message}");
Trace.TraceError($"异常堆栈:{ex.StackTrace}");
}
}
}
/// <summary>
/// 获取导弹配置数据
/// </summary>
/// <param name="model">导弹型号</param>
/// <returns>导弹配置数据</returns>
public MissileData GetMissile(string model)
{
if (_missiles.TryGetValue(model, out var data))
return data;
throw new KeyNotFoundException($"导弹 {model} 不存在");
}
/// <summary>
/// 获取指示器配置数据
/// </summary>
/// <param name="model">指示器型号</param>
/// <returns>指示器配置数据</returns>
public IndicatorData GetIndicator(string model)
{
if (_indicators.TryGetValue(model, out var data))
return data;
throw new KeyNotFoundException($"指示器 {model} 不存在");
}
/// <summary>
/// 获取传感器配置数据
/// </summary>
/// <param name="model">传感器型号</param>
/// <returns>传感器配置数据</returns>
public SensorData GetSensor(string model)
{
if (_sensors.TryGetValue(model, out var data))
return data;
throw new KeyNotFoundException($"传感器 {model} 不存在");
}
/// <summary>
/// 获取目标配置数据
/// </summary>
/// <param name="model">目标型号</param>
/// <returns>目标配置数据</returns>
public EquipmentData GetEquipment(string model)
{
if (_equipments.TryGetValue(model, out var data))
return data;
throw new KeyNotFoundException($"目标 {model} 不存在");
}
/// <summary>
/// 获取天气配置数据
/// </summary>
/// <param name="weatherType">天气类型</param>
/// <returns>天气配置数据</returns>
public WeatherData GetWeather(string weatherType)
{
if (_weathers.TryGetValue(weatherType, out var data))
return data;
throw new KeyNotFoundException($"天气 {weatherType} 不存在");
}
/// <summary>
/// 获取干扰机配置数据
/// </summary>
/// <param name="model">干扰机型号</param>
/// <returns>干扰机配置数据</returns>
public JammerData GetJammer(string model)
{
if (_jammers.TryGetValue(model, out var data))
return data;
throw new KeyNotFoundException($"干扰机 {model} 不存在");
}
/// <summary>
/// 获取所有可用的导弹ID列表
/// </summary>
public IEnumerable<string> GetAvailableMissiles() => _missiles.Keys;
/// <summary>
/// 获取所有可用的指示器ID列表
/// </summary>
public IEnumerable<string> GetAvailableIndicators() => _indicators.Keys;
/// <summary>
/// 获取所有可用的传感器ID列表
/// </summary>
public IEnumerable<string> GetAvailableSensors() => _sensors.Keys;
/// <summary>
/// 获取所有可用的目标ID列表
/// </summary>
public IEnumerable<string> GetAvailableTargets() => _equipments.Keys;
/// <summary>
/// 获取所有可用的天气ID列表
/// </summary>
public IEnumerable<string> GetAvailableWeathers() => _weathers.Keys;
/// <summary>
/// 获取所有可用的干扰机ID列表
/// </summary>
public IEnumerable<string> GetAvailableJammers() => _jammers.Keys;
}
}