using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.Json; using System.Threading.Tasks; using WIDESEAWCS_S7Simulator.Core.Entities; using WIDESEAWCS_S7Simulator.Core.Enums; using WIDESEAWCS_S7Simulator.Core.Interfaces; using WIDESEAWCS_S7Simulator.Core.Persistence.Models; namespace WIDESEAWCS_S7Simulator.Core.Persistence { /// /// 文件持久化服务实现 /// 将实例配置和内存数据保存到本地JSON文件 /// public class FilePersistenceService : IPersistenceService { /// /// 数据目录路径 /// private readonly string _dataPath; /// /// JSON序列化选项 /// private readonly JsonSerializerOptions _jsonOptions; /// /// 构造函数 /// /// 数据目录路径 public FilePersistenceService(string dataPath = "Data") { _dataPath = dataPath; _jsonOptions = new JsonSerializerOptions { WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; // 确保数据目录存在 if (!Directory.Exists(_dataPath)) { Directory.CreateDirectory(_dataPath); } } /// /// 保存实例配置 /// public async Task SaveInstanceConfigAsync(InstanceConfig config) { if (config == null) throw new ArgumentNullException(nameof(config)); var instanceDir = GetInstanceDirectory(config.Id); if (!Directory.Exists(instanceDir)) { Directory.CreateDirectory(instanceDir); } var configPath = Path.Combine(instanceDir, "config.json"); var model = ToDataModel(config); var json = JsonSerializer.Serialize(model, _jsonOptions); await File.WriteAllTextAsync(configPath, json); } /// /// 加载实例配置 /// public async Task LoadInstanceConfigAsync(string instanceId) { if (string.IsNullOrWhiteSpace(instanceId)) throw new ArgumentException("实例ID不能为空", nameof(instanceId)); var configPath = Path.Combine(GetInstanceDirectory(instanceId), "config.json"); if (!File.Exists(configPath)) throw new FileNotFoundException($"实例配置文件不存在: {configPath}"); var json = await File.ReadAllTextAsync(configPath); var model = JsonSerializer.Deserialize(json, _jsonOptions); if (model == null) throw new InvalidOperationException("无法反序列化实例配置"); return ToEntity(model); } /// /// 加载所有实例配置 /// public async Task> LoadAllInstanceConfigsAsync() { var configs = new List(); if (!Directory.Exists(_dataPath)) return configs; var instanceDirs = Directory.GetDirectories(_dataPath) .Where(d => Path.GetFileName(d).StartsWith("instance-")) .ToList(); foreach (var dir in instanceDirs) { var configPath = Path.Combine(dir, "config.json"); if (File.Exists(configPath)) { try { var json = await File.ReadAllTextAsync(configPath); var model = JsonSerializer.Deserialize(json, _jsonOptions); if (model != null) { configs.Add(ToEntity(model)); } } catch (Exception) { // 跳过无法加载的配置文件 continue; } } } return configs; } /// /// 删除实例配置 /// public Task DeleteInstanceConfigAsync(string instanceId) { if (string.IsNullOrWhiteSpace(instanceId)) throw new ArgumentException("实例ID不能为空", nameof(instanceId)); var instanceDir = GetInstanceDirectory(instanceId); if (Directory.Exists(instanceDir)) { Directory.Delete(instanceDir, recursive: true); } return Task.CompletedTask; } /// /// 保存内存数据 /// public async Task SaveMemoryDataAsync(string instanceId, IMemoryStore memoryStore) { if (string.IsNullOrWhiteSpace(instanceId)) throw new ArgumentException("实例ID不能为空", nameof(instanceId)); if (memoryStore == null) throw new ArgumentNullException(nameof(memoryStore)); var instanceDir = GetInstanceDirectory(instanceId); if (!Directory.Exists(instanceDir)) { Directory.CreateDirectory(instanceDir); } var memoryPath = Path.Combine(instanceDir, "memory.json"); var exportedData = memoryStore.Export(); // 将字节数组转换为Base64字符串以便JSON序列化 var memoryDataModel = new MemoryDataModel { MemoryData = exportedData.ToDictionary( kvp => kvp.Key, kvp => Convert.ToBase64String(kvp.Value) ) }; var json = JsonSerializer.Serialize(memoryDataModel, _jsonOptions); await File.WriteAllTextAsync(memoryPath, json); } /// /// 加载内存数据 /// public async Task LoadMemoryDataAsync(string instanceId, IMemoryStore memoryStore) { if (string.IsNullOrWhiteSpace(instanceId)) throw new ArgumentException("实例ID不能为空", nameof(instanceId)); if (memoryStore == null) throw new ArgumentNullException(nameof(memoryStore)); var memoryPath = Path.Combine(GetInstanceDirectory(instanceId), "memory.json"); if (!File.Exists(memoryPath)) return; // 内存文件不存在,跳过加载 var json = await File.ReadAllTextAsync(memoryPath); var memoryDataModel = JsonSerializer.Deserialize(json, _jsonOptions); if (memoryDataModel?.MemoryData == null) return; // 将Base64字符串转换回字节数组 var importedData = new Dictionary(); foreach (var kvp in memoryDataModel.MemoryData) { try { importedData[kvp.Key] = Convert.FromBase64String(kvp.Value); } catch (FormatException) { // 跳过无效的Base64数据 continue; } } memoryStore.Import(importedData); } /// /// 获取实例目录路径 /// private string GetInstanceDirectory(string instanceId) { return Path.Combine(_dataPath, $"instance-{instanceId}"); } /// /// 将实体转换为数据模型 /// private InstanceDataModel ToDataModel(InstanceConfig config) { return new InstanceDataModel { Id = config.Id, Name = config.Name, PlcType = config.PLCType.ToString(), Port = config.Port, ActivationKey = config.ActivationKey, AutoStart = config.AutoStart, MemoryConfig = new MemoryRegionConfigModel { MRegionSize = config.MemoryConfig.MRegionSize, DBBlockCount = config.MemoryConfig.DBBlockCount, DBBlockSize = config.MemoryConfig.DBBlockSize, IRegionSize = config.MemoryConfig.IRegionSize, QRegionSize = config.MemoryConfig.QRegionSize, TRegionCount = config.MemoryConfig.TRegionCount, CRegionCount = config.MemoryConfig.CRegionCount } }; } /// /// 将数据模型转换为实体 /// private InstanceConfig ToEntity(InstanceDataModel model) { return new InstanceConfig { Id = model.Id, Name = model.Name, PLCType = Enum.Parse(model.PlcType), Port = model.Port, ActivationKey = model.ActivationKey, AutoStart = model.AutoStart, MemoryConfig = new MemoryRegionConfig { MRegionSize = model.MemoryConfig.MRegionSize, DBBlockCount = model.MemoryConfig.DBBlockCount, DBBlockSize = model.MemoryConfig.DBBlockSize, IRegionSize = model.MemoryConfig.IRegionSize, QRegionSize = model.MemoryConfig.QRegionSize, TRegionCount = model.MemoryConfig.TRegionCount, CRegionCount = model.MemoryConfig.CRegionCount } }; } } }