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<IReadOnlyList<ProtocolTemplate>> GetAllAsync()
|
{
|
await _lock.WaitAsync();
|
try
|
{
|
var templates = await LoadUnsafeAsync();
|
return templates.AsReadOnly();
|
}
|
finally
|
{
|
_lock.Release();
|
}
|
}
|
|
public async Task<ProtocolTemplate?> 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<ProtocolTemplate> 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<bool> 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<bool> ExistsAsync(string id)
|
{
|
return (await GetByIdAsync(id)) != null;
|
}
|
|
private async Task<List<ProtocolTemplate>> 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<ProtocolTemplate>();
|
}
|
|
return JsonSerializer.Deserialize<List<ProtocolTemplate>>(content, _jsonOptions) ?? new List<ProtocolTemplate>();
|
}
|
|
private async Task SaveUnsafeAsync(List<ProtocolTemplate> templates)
|
{
|
var content = JsonSerializer.Serialize(templates, _jsonOptions);
|
await File.WriteAllTextAsync(_filePath, content);
|
}
|
|
private static List<ProtocolTemplate> CreateDefaultTemplates()
|
{
|
return new List<ProtocolTemplate>
|
{
|
new()
|
{
|
Id = "wcs-line-v260202",
|
Name = "WCS-输送线对接协议 V260202",
|
Version = "V260202",
|
Fields = new List<ProtocolFieldMapping>
|
{
|
// 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 }
|
}
|
}
|
};
|
}
|
}
|