80 lines
3.1 KiB
C#
80 lines
3.1 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
|
|
public class GatewayRegistryService : IGatewayRegistryService
|
|
{
|
|
private readonly AppDbContext _db;
|
|
|
|
public GatewayRegistryService(AppDbContext db) => _db = db;
|
|
|
|
public async Task<WardGateway> RegisterAsync(Guid siteId, RegisterGatewayRequest req)
|
|
{
|
|
var siteExists = await _db.ClinicalSites.AnyAsync(s => s.Id == siteId);
|
|
if (!siteExists)
|
|
throw new NotFoundException("Clinical site not found.", "SITE_NOT_FOUND");
|
|
|
|
var duplicate = await _db.WardGateways.AnyAsync(g =>
|
|
g.SiteId == siteId && g.GatewayCode == req.GatewayCode);
|
|
if (duplicate)
|
|
throw new ConflictException(
|
|
$"Gateway code '{req.GatewayCode}' already exists for this site.",
|
|
"GATEWAY_CODE_CONFLICT");
|
|
|
|
var gateway = new WardGateway(siteId, req.GatewayCode, req.Department);
|
|
_db.WardGateways.Add(gateway);
|
|
await _db.SaveChangesAsync();
|
|
return gateway;
|
|
}
|
|
|
|
public async Task<WardGateway> GetByIdAsync(Guid id)
|
|
{
|
|
var gateway = await _db.WardGateways
|
|
.AsNoTracking()
|
|
.Include(g => g.Site)
|
|
.FirstOrDefaultAsync(g => g.Id == id);
|
|
if (gateway is null)
|
|
throw new NotFoundException("Ward gateway not found.", "GATEWAY_NOT_FOUND");
|
|
return gateway;
|
|
}
|
|
|
|
public async Task<List<WardGateway>> ListBySiteAsync(Guid siteId, string? department)
|
|
{
|
|
var siteExists = await _db.ClinicalSites.AnyAsync(s => s.Id == siteId);
|
|
if (!siteExists)
|
|
throw new NotFoundException("Clinical site not found.", "SITE_NOT_FOUND");
|
|
|
|
var query = _db.WardGateways.AsNoTracking().Where(g => g.SiteId == siteId);
|
|
if (!string.IsNullOrWhiteSpace(department))
|
|
query = query.Where(g => g.Department == department);
|
|
|
|
return await query.OrderBy(g => g.GatewayCode).ToListAsync();
|
|
}
|
|
|
|
public async Task<WardGateway> RecordHeartbeatAsync(
|
|
Guid gatewayId, GatewayHeartbeatRequest req, string? authenticatedGatewayId)
|
|
{
|
|
if (authenticatedGatewayId is not null
|
|
&& Guid.TryParse(authenticatedGatewayId, out var authId)
|
|
&& authId != gatewayId)
|
|
throw new ValidationException(
|
|
"Gateway id in URL does not match X-Gateway-Id header.",
|
|
"GATEWAY_ID_MISMATCH");
|
|
|
|
var gateway = await _db.WardGateways.FindAsync(gatewayId);
|
|
if (gateway is null)
|
|
throw new NotFoundException("Ward gateway not found.", "GATEWAY_NOT_FOUND");
|
|
|
|
var status = GatewayStatusExtensions.FromDbString(req.Status.ToUpperInvariant());
|
|
gateway.RecordHeartbeat(status, req.BufferDepth, req.ReportedAtUtc);
|
|
await _db.SaveChangesAsync();
|
|
return gateway;
|
|
}
|
|
|
|
public async Task MarkOfflineAsync(Guid gatewayId)
|
|
{
|
|
var gateway = await _db.WardGateways.FindAsync(gatewayId);
|
|
if (gateway is null)
|
|
throw new NotFoundException("Ward gateway not found.", "GATEWAY_NOT_FOUND");
|
|
gateway.MarkOffline();
|
|
await _db.SaveChangesAsync();
|
|
}
|
|
} |