#33 Remove single-use interfaces #36

Merged
henry merged 1 commits from remove-interfaces into main 2025-07-15 22:36:24 +00:00
13 changed files with 24 additions and 67 deletions
Showing only changes of commit ec3be2d6f6 - Show all commits

View File

@ -1,5 +1,5 @@
@page "/config" @page "/config"
@inject AccessQueuePlayground.Services.IAccessQueueManager QueueManager @inject AccessQueuePlayground.Services.AccessQueueManager QueueManager
@using BlazorBootstrap @using BlazorBootstrap
<h3>Access Queue Configuration</h3> <h3>Access Queue Configuration</h3>

View File

@ -4,7 +4,7 @@
@using AccessQueueService.Models; @using AccessQueueService.Models;
@using BlazorBootstrap @using BlazorBootstrap
@inject IAccessQueueManager Manager @inject AccessQueueManager Manager
<PageTitle>AccessQueue Playground</PageTitle> <PageTitle>AccessQueue Playground</PageTitle>
@if (Config != null) @if (Config != null)

View File

@ -28,8 +28,8 @@ else
builder.Services.AddHttpClient(); builder.Services.AddHttpClient();
builder.Services.AddSingleton<IAccessService, AccessQueueApiService>(); builder.Services.AddSingleton<IAccessService, AccessQueueApiService>();
} }
builder.Services.AddSingleton<IAccessQueueRepo, TakeANumberAccessQueueRepo>(); builder.Services.AddSingleton<AccessQueueRepository>();
builder.Services.AddSingleton<IAccessQueueManager, AccessQueueManager>(); builder.Services.AddSingleton<AccessQueueManager>();
builder.Services.AddHostedService<AccessQueueBackgroundService>(); builder.Services.AddHostedService<AccessQueueBackgroundService>();
var app = builder.Build(); var app = builder.Build();

View File

@ -6,10 +6,10 @@ namespace AccessQueuePlayground.Services
{ {
public class AccessQueueBackgroundService : BackgroundService public class AccessQueueBackgroundService : BackgroundService
{ {
private readonly IAccessQueueManager _accessQueueManager; private readonly AccessQueueManager _accessQueueManager;
private readonly IConfiguration _config; private readonly IConfiguration _config;
public AccessQueueBackgroundService(IAccessQueueManager accessQueueManager, IConfiguration config) public AccessQueueBackgroundService(AccessQueueManager accessQueueManager, IConfiguration config)
{ {
_accessQueueManager = accessQueueManager; _accessQueueManager = accessQueueManager;
_config = config; _config = config;

View File

@ -6,7 +6,7 @@ using Microsoft.Extensions.Configuration;
namespace AccessQueuePlayground.Services namespace AccessQueuePlayground.Services
{ {
public class AccessQueueManager : IAccessQueueManager public class AccessQueueManager
{ {
private readonly IAccessService _accessService; private readonly IAccessService _accessService;
private readonly IConfiguration _config; private readonly IConfiguration _config;

View File

@ -1,20 +0,0 @@
using AccessQueuePlayground.Models;
using AccessQueueService.Models;
namespace AccessQueuePlayground.Services
{
public interface IAccessQueueManager
{
public event Action? StatusUpdated;
public AccessQueueConfig GetConfig();
public void UpdateConfig(AccessQueueConfig config);
public Task RecalculateStatus();
public AccessQueueManagerStatus GetStatus();
public Guid AddUser(bool isActive);
public void SetUserActive(Guid userId, bool isActive);
public void RevokeAccess(Guid userId);
public void RevokeAllAccess();
public void Reset();
}
}

View File

@ -6,7 +6,7 @@ using Microsoft.Extensions.Configuration;
namespace AccessQueueService.Data namespace AccessQueueService.Data
{ {
public class TakeANumberAccessQueueRepo : IAccessQueueRepo public class AccessQueueRepository
{ {
private ConcurrentDictionary<string, AccessTicket> _accessTickets = new(); private ConcurrentDictionary<string, AccessTicket> _accessTickets = new();
private ConcurrentDictionary<string, ulong> _queueNumbers = new(); private ConcurrentDictionary<string, ulong> _queueNumbers = new();
@ -189,7 +189,7 @@ namespace AccessQueueService.Data
return JsonSerializer.Serialize(state); return JsonSerializer.Serialize(state);
} }
public static TakeANumberAccessQueueRepo FromState(string stateJson) public static AccessQueueRepository FromState(string stateJson)
{ {
var state = JsonSerializer.Deserialize<TakeANumberAccessQueueRepoState?>(stateJson); var state = JsonSerializer.Deserialize<TakeANumberAccessQueueRepoState?>(stateJson);
if (state?.AccessTickets == null || state?.AccessQueue == null) if (state?.AccessTickets == null || state?.AccessQueue == null)

View File

@ -1,21 +0,0 @@
using System.Runtime.Serialization;
using AccessQueueService.Models;
using Microsoft.Extensions.Configuration;
namespace AccessQueueService.Data
{
public interface IAccessQueueRepo
{
public string ToState();
public int GetUnexpiredTicketsCount();
public int GetActiveTicketsCount(DateTime activeCutoff);
public int GetQueueCount();
public AccessTicket? GetTicket(string userId);
public void UpsertTicket(AccessTicket ticket);
public int GetRequestsAhead(string userId);
public void Enqueue(AccessTicket ticket);
public int DeleteExpiredTickets();
public bool RemoveUser(string userId);
public bool DidDequeueUntilFull(AccessQueueConfig config);
}
}

View File

@ -17,7 +17,7 @@ builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(); builder.Services.AddSwaggerGen();
builder.Services.AddSingleton<IAccessService, AccessService>(); builder.Services.AddSingleton<IAccessService, AccessService>();
builder.Services.AddSingleton<IAccessQueueRepo>(sp => builder.Services.AddSingleton<AccessQueueRepository>(sp =>
{ {
string? filePath = builder.Configuration.GetValue<string>("AccessQueue:BackupFilePath"); string? filePath = builder.Configuration.GetValue<string>("AccessQueue:BackupFilePath");
if (!string.IsNullOrWhiteSpace(filePath) && File.Exists(filePath)) if (!string.IsNullOrWhiteSpace(filePath) && File.Exists(filePath))
@ -25,14 +25,14 @@ builder.Services.AddSingleton<IAccessQueueRepo>(sp =>
try try
{ {
var json = File.ReadAllText(filePath); var json = File.ReadAllText(filePath);
return TakeANumberAccessQueueRepo.FromState(json); return AccessQueueRepository.FromState(json);
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"Failed to load state from {filePath}. Error message: {ex.Message}"); Console.WriteLine($"Failed to load state from {filePath}. Error message: {ex.Message}");
} }
} }
return new TakeANumberAccessQueueRepo(); return new AccessQueueRepository();
}); });
builder.Services.AddHostedService<AccessCleanupBackgroundService>(); builder.Services.AddHostedService<AccessCleanupBackgroundService>();
builder.Services.AddHostedService<AccessQueueSerializerService>(); builder.Services.AddHostedService<AccessQueueSerializerService>();

View File

@ -5,11 +5,11 @@ namespace AccessQueueService.Services
{ {
public class AccessQueueSerializerService : BackgroundService public class AccessQueueSerializerService : BackgroundService
{ {
private readonly IAccessQueueRepo _accessRepo; private readonly AccessQueueRepository _accessRepo;
private readonly IConfiguration _config; private readonly IConfiguration _config;
private readonly ILogger<AccessQueueSerializerService> _logger; private readonly ILogger<AccessQueueSerializerService> _logger;
public AccessQueueSerializerService(IAccessQueueRepo accessRepo, IConfiguration config, ILogger<AccessQueueSerializerService> logger) public AccessQueueSerializerService(AccessQueueRepository accessRepo, IConfiguration config, ILogger<AccessQueueSerializerService> logger)
{ {
_accessRepo = accessRepo; _accessRepo = accessRepo;
_config = config; _config = config;

View File

@ -8,12 +8,12 @@ namespace AccessQueueService.Services
public class AccessService : IAccessService public class AccessService : IAccessService
{ {
private readonly IConfiguration _configuration; private readonly IConfiguration _configuration;
private readonly IAccessQueueRepo _accessQueueRepo; private readonly AccessQueueRepository _accessQueueRepo;
private readonly ILogger<AccessService> _logger; private readonly ILogger<AccessService> _logger;
private readonly SemaphoreSlim _queueLock = new(1, 1); private readonly SemaphoreSlim _queueLock = new(1, 1);
private AccessQueueConfig _config; private AccessQueueConfig _config;
public AccessService(IConfiguration configuration, IAccessQueueRepo accessQueueRepo, ILogger<AccessService> logger) public AccessService(IConfiguration configuration, AccessQueueRepository accessQueueRepo, ILogger<AccessService> logger)
{ {
_configuration = configuration; _configuration = configuration;
_accessQueueRepo = accessQueueRepo; _accessQueueRepo = accessQueueRepo;

View File

@ -14,7 +14,7 @@ namespace AccessQueueServiceTests
{ {
public class AccessQueueRepoTests public class AccessQueueRepoTests
{ {
private readonly TakeANumberAccessQueueRepo _repo; private readonly AccessQueueRepository _repo;
private readonly AccessQueueConfig _simpleConfig = new() private readonly AccessQueueConfig _simpleConfig = new()
{ {
ExpirationSeconds = 60, ExpirationSeconds = 60,
@ -42,7 +42,7 @@ namespace AccessQueueServiceTests
public AccessQueueRepoTests() public AccessQueueRepoTests()
{ {
_repo = new TakeANumberAccessQueueRepo(); _repo = new AccessQueueRepository();
} }
private List<AccessTicket> GetSimpleTicketList() => new() private List<AccessTicket> GetSimpleTicketList() => new()
@ -313,7 +313,7 @@ namespace AccessQueueServiceTests
_repo.Enqueue(ticketWithoutAccess); _repo.Enqueue(ticketWithoutAccess);
string stateJson = _repo.ToState(); string stateJson = _repo.ToState();
var deserializedRepo = TakeANumberAccessQueueRepo.FromState(stateJson); var deserializedRepo = AccessQueueRepository.FromState(stateJson);
Assert.Equal(1, deserializedRepo.GetUnexpiredTicketsCount()); Assert.Equal(1, deserializedRepo.GetUnexpiredTicketsCount());
Assert.Equal(1, deserializedRepo.GetQueueCount()); Assert.Equal(1, deserializedRepo.GetQueueCount());

View File

@ -16,7 +16,6 @@ namespace AccessQueueServiceTests
const int ACT_MILLIS = 1000 * ACT_SECONDS; const int ACT_MILLIS = 1000 * ACT_SECONDS;
const int CAP_LIMIT = 5; const int CAP_LIMIT = 5;
const int BULK_COUNT = 10000; const int BULK_COUNT = 10000;
const int CACHE_MILLIS = 1000;
private readonly AccessService _accessService; private readonly AccessService _accessService;
public AccessServiceTests() public AccessServiceTests()
@ -26,14 +25,13 @@ namespace AccessQueueServiceTests
{ "AccessQueue:ExpirationSeconds", $"{EXP_SECONDS}" }, { "AccessQueue:ExpirationSeconds", $"{EXP_SECONDS}" },
{ "AccessQueue:ActivitySeconds", $"{ACT_SECONDS}" }, { "AccessQueue:ActivitySeconds", $"{ACT_SECONDS}" },
{ "AccessQueue:CapacityLimit", $"{CAP_LIMIT}" }, { "AccessQueue:CapacityLimit", $"{CAP_LIMIT}" },
{ "AccessQueue:RollingExpiration", "true" }, { "AccessQueue:RollingExpiration", "true" }
{ "AccessQueue:CacheMilliseconds", $"{CACHE_MILLIS}" }
}; };
var configuration = new ConfigurationBuilder() var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(inMemorySettings) .AddInMemoryCollection(inMemorySettings)
.Build(); .Build();
var accessQueueRepo = new TakeANumberAccessQueueRepo(); var accessQueueRepo = new AccessQueueRepository();
var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole()); var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
var logger = loggerFactory.CreateLogger<AccessService>(); var logger = loggerFactory.CreateLogger<AccessService>();
_accessService = new AccessService(configuration, accessQueueRepo, logger); _accessService = new AccessService(configuration, accessQueueRepo, logger);
@ -89,9 +87,9 @@ namespace AccessQueueServiceTests
Assert.NotNull(response); Assert.NotNull(response);
Assert.Null(response.ExpiresOn); Assert.Null(response.ExpiresOn);
Assert.True(response.RequestsAhead == CAP_LIMIT); Assert.True(response.RequestsAhead == CAP_LIMIT);
Assert.Equal(CAP_LIMIT, _accessService.UnexpiredTicketsCount); Assert.Equal(5, _accessService.UnexpiredTicketsCount);
Assert.Equal(CAP_LIMIT, _accessService.ActiveTicketsCount); Assert.Equal(5, _accessService.ActiveTicketsCount);
Assert.Equal(CAP_LIMIT + 1, _accessService.QueueCount); Assert.Equal(6, _accessService.QueueCount);
} }