feature: Site & Gateway Registry + Clinical Sync Contracts
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user