using System.Text.Json; using WIDESEAWCS_S7Simulator.Application.Protocol; using WIDESEAWCS_S7Simulator.Core.Protocol; namespace WIDESEAWCS_S7Simulator.Server.Services; public class FileProtocolTemplateService : IProtocolTemplateService { private readonly string _filePath; private readonly SemaphoreSlim _lock = new(1, 1); private readonly JsonSerializerOptions _jsonOptions = new() { WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; public FileProtocolTemplateService(string dataPath) { Directory.CreateDirectory(dataPath); _filePath = Path.Combine(dataPath, "protocol-templates.json"); } public async Task> GetAllAsync() { await _lock.WaitAsync(); try { var templates = await LoadUnsafeAsync(); return templates.AsReadOnly(); } finally { _lock.Release(); } } public async Task GetByIdAsync(string id) { if (string.IsNullOrWhiteSpace(id)) { return null; } await _lock.WaitAsync(); try { var templates = await LoadUnsafeAsync(); return templates.FirstOrDefault(t => string.Equals(t.Id, id, StringComparison.OrdinalIgnoreCase)); } finally { _lock.Release(); } } public async Task UpsertAsync(ProtocolTemplate template) { if (template == null) throw new ArgumentNullException(nameof(template)); if (string.IsNullOrWhiteSpace(template.Id)) throw new ArgumentException("Template id is required.", nameof(template)); await _lock.WaitAsync(); try { var templates = await LoadUnsafeAsync(); var idx = templates.FindIndex(t => string.Equals(t.Id, template.Id, StringComparison.OrdinalIgnoreCase)); if (idx >= 0) { templates[idx] = template; } else { templates.Add(template); } await SaveUnsafeAsync(templates); return template; } finally { _lock.Release(); } } public async Task DeleteAsync(string id) { if (string.IsNullOrWhiteSpace(id)) { return false; } await _lock.WaitAsync(); try { var templates = await LoadUnsafeAsync(); var removed = templates.RemoveAll(t => string.Equals(t.Id, id, StringComparison.OrdinalIgnoreCase)) > 0; if (removed) { await SaveUnsafeAsync(templates); } return removed; } finally { _lock.Release(); } } public async Task ExistsAsync(string id) { return (await GetByIdAsync(id)) != null; } private async Task> LoadUnsafeAsync() { if (!File.Exists(_filePath)) { var defaults = CreateDefaultTemplates(); await SaveUnsafeAsync(defaults); return defaults; } var content = await File.ReadAllTextAsync(_filePath); if (string.IsNullOrWhiteSpace(content)) { return new List(); } return JsonSerializer.Deserialize>(content, _jsonOptions) ?? new List(); } private async Task SaveUnsafeAsync(List templates) { var content = JsonSerializer.Serialize(templates, _jsonOptions); await File.WriteAllTextAsync(_filePath, content); } private static List CreateDefaultTemplates() { return new List { new() { Id = "wcs-line-v260202", Name = "WCS-输送线对接协议 V260202", Version = "V260202", Fields = new List { // SEG01 new() { FieldKey = "SEG01_WCS_ACK", DbNumber = 1, Offset = 0, DataType = ProtocolDataType.Byte, Direction = ProtocolFieldDirection.WcsToPlc }, new() { FieldKey = "SEG01_WCS_TASK_ID", DbNumber = 1, Offset = 2, DataType = ProtocolDataType.DInt, Direction = ProtocolFieldDirection.WcsToPlc }, new() { FieldKey = "SEG01_WCS_TARGET_ID", DbNumber = 1, Offset = 6, DataType = ProtocolDataType.Int, Direction = ProtocolFieldDirection.WcsToPlc }, new() { FieldKey = "SEG01_PLC_STB", DbNumber = 1, Offset = 10, DataType = ProtocolDataType.Byte, Direction = ProtocolFieldDirection.PlcToWcs }, new() { FieldKey = "SEG01_PLC_TASK_ID", DbNumber = 1, Offset = 20, DataType = ProtocolDataType.DInt, Direction = ProtocolFieldDirection.PlcToWcs }, new() { FieldKey = "SEG01_PLC_TARGET_ID", DbNumber = 1, Offset = 24, DataType = ProtocolDataType.Int, Direction = ProtocolFieldDirection.PlcToWcs }, new() { FieldKey = "SEG01_PALLET_CODE", DbNumber = 1, Offset = 30, DataType = ProtocolDataType.String, Length = 32, Direction = ProtocolFieldDirection.Bidirectional }, // SEG02 new() { FieldKey = "SEG02_WCS_ACK", DbNumber = 2, Offset = 0, DataType = ProtocolDataType.Byte, Direction = ProtocolFieldDirection.WcsToPlc }, new() { FieldKey = "SEG02_WCS_TASK_ID", DbNumber = 2, Offset = 2, DataType = ProtocolDataType.DInt, Direction = ProtocolFieldDirection.WcsToPlc }, new() { FieldKey = "SEG02_WCS_TARGET_ID", DbNumber = 2, Offset = 6, DataType = ProtocolDataType.Int, Direction = ProtocolFieldDirection.WcsToPlc }, new() { FieldKey = "SEG02_PLC_STB", DbNumber = 2, Offset = 10, DataType = ProtocolDataType.Byte, Direction = ProtocolFieldDirection.PlcToWcs }, new() { FieldKey = "SEG02_PLC_TASK_ID", DbNumber = 2, Offset = 20, DataType = ProtocolDataType.DInt, Direction = ProtocolFieldDirection.PlcToWcs }, new() { FieldKey = "SEG02_PLC_TARGET_ID", DbNumber = 2, Offset = 24, DataType = ProtocolDataType.Int, Direction = ProtocolFieldDirection.PlcToWcs }, new() { FieldKey = "SEG02_PALLET_CODE", DbNumber = 2, Offset = 30, DataType = ProtocolDataType.String, Length = 32, Direction = ProtocolFieldDirection.Bidirectional } } } }; } }