| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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 |
| | | { |
| | | /// <summary> |
| | | /// æä»¶æä¹
åæå¡å®ç° |
| | | /// å°å®ä¾é
ç½®åå
åæ°æ®ä¿åå°æ¬å°JSONæä»¶ |
| | | /// </summary> |
| | | public class FilePersistenceService : IPersistenceService |
| | | { |
| | | /// <summary> |
| | | /// æ°æ®ç®å½è·¯å¾ |
| | | /// </summary> |
| | | private readonly string _dataPath; |
| | | |
| | | /// <summary> |
| | | /// JSONåºååé项 |
| | | /// </summary> |
| | | private readonly JsonSerializerOptions _jsonOptions; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="dataPath">æ°æ®ç®å½è·¯å¾</param> |
| | | public FilePersistenceService(string dataPath = "Data") |
| | | { |
| | | _dataPath = dataPath; |
| | | _jsonOptions = new JsonSerializerOptions |
| | | { |
| | | WriteIndented = true, |
| | | PropertyNamingPolicy = JsonNamingPolicy.CamelCase |
| | | }; |
| | | |
| | | // ç¡®ä¿æ°æ®ç®å½åå¨ |
| | | if (!Directory.Exists(_dataPath)) |
| | | { |
| | | Directory.CreateDirectory(_dataPath); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ä¿åå®ä¾é
ç½® |
| | | /// </summary> |
| | | 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); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å è½½å®ä¾é
ç½® |
| | | /// </summary> |
| | | public async Task<InstanceConfig> 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<InstanceDataModel>(json, _jsonOptions); |
| | | |
| | | if (model == null) |
| | | throw new InvalidOperationException("æ æ³ååºååå®ä¾é
ç½®"); |
| | | |
| | | return ToEntity(model); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å è½½ææå®ä¾é
ç½® |
| | | /// </summary> |
| | | public async Task<List<InstanceConfig>> LoadAllInstanceConfigsAsync() |
| | | { |
| | | var configs = new List<InstanceConfig>(); |
| | | |
| | | 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<InstanceDataModel>(json, _jsonOptions); |
| | | if (model != null) |
| | | { |
| | | configs.Add(ToEntity(model)); |
| | | } |
| | | } |
| | | catch (Exception) |
| | | { |
| | | // è·³è¿æ æ³å è½½çé
ç½®æä»¶ |
| | | continue; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return configs; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å é¤å®ä¾é
ç½® |
| | | /// </summary> |
| | | 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; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ä¿åå
åæ°æ® |
| | | /// </summary> |
| | | 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); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å è½½å
åæ°æ® |
| | | /// </summary> |
| | | 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<MemoryDataModel>(json, _jsonOptions); |
| | | |
| | | if (memoryDataModel?.MemoryData == null) |
| | | return; |
| | | |
| | | // å°Base64å符串转æ¢ååèæ°ç» |
| | | var importedData = new Dictionary<string, byte[]>(); |
| | | foreach (var kvp in memoryDataModel.MemoryData) |
| | | { |
| | | try |
| | | { |
| | | importedData[kvp.Key] = Convert.FromBase64String(kvp.Value); |
| | | } |
| | | catch (FormatException) |
| | | { |
| | | // è·³è¿æ æçBase64æ°æ® |
| | | continue; |
| | | } |
| | | } |
| | | |
| | | memoryStore.Import(importedData); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åå®ä¾ç®å½è·¯å¾ |
| | | /// </summary> |
| | | private string GetInstanceDirectory(string instanceId) |
| | | { |
| | | return Path.Combine(_dataPath, $"instance-{instanceId}"); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å°å®ä½è½¬æ¢ä¸ºæ°æ®æ¨¡å |
| | | /// </summary> |
| | | 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 |
| | | } |
| | | }; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å°æ°æ®æ¨¡å转æ¢ä¸ºå®ä½ |
| | | /// </summary> |
| | | private InstanceConfig ToEntity(InstanceDataModel model) |
| | | { |
| | | return new InstanceConfig |
| | | { |
| | | Id = model.Id, |
| | | Name = model.Name, |
| | | PLCType = Enum.Parse<SiemensPLCType>(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 |
| | | } |
| | | }; |
| | | } |
| | | } |
| | | } |