#17 Make configuration eidtable at runtime #18
|
@ -1,6 +1,7 @@
|
||||||
@page "/"
|
@page "/"
|
||||||
@using AccessQueuePlayground.Models
|
@using AccessQueuePlayground.Models
|
||||||
@using AccessQueuePlayground.Services
|
@using AccessQueuePlayground.Services
|
||||||
|
@using AccessQueueService.Models;
|
||||||
@using BlazorBootstrap
|
@using BlazorBootstrap
|
||||||
|
|
||||||
@inject IAccessQueueManager Manager
|
@inject IAccessQueueManager Manager
|
||||||
|
@ -12,7 +13,8 @@
|
||||||
<p>
|
<p>
|
||||||
<b>Expiration Seconds:</b> @Config.ExpirationSeconds,
|
<b>Expiration Seconds:</b> @Config.ExpirationSeconds,
|
||||||
<b>Activity Seconds:</b> @Config.ActivitySeconds,
|
<b>Activity Seconds:</b> @Config.ActivitySeconds,
|
||||||
<b>Capacity Limit:</b> @Config.CapacityLimit
|
<b>Capacity Limit:</b> @Config.CapacityLimit,
|
||||||
|
<b>Rolling Expiration:</b> @Config.RollingExpiration
|
||||||
</p>
|
</p>
|
||||||
}
|
}
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
namespace AccessQueuePlayground.Models
|
|
||||||
{
|
|
||||||
public class AccessQueueConfig
|
|
||||||
{
|
|
||||||
public int ActivitySeconds { get; set; }
|
|
||||||
public int ExpirationSeconds { get; set; }
|
|
||||||
public int CapacityLimit { get; set; }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -29,12 +29,12 @@ namespace AccessQueuePlayground.Services
|
||||||
|
|
||||||
public AccessQueueStatus GetStatus() => _status;
|
public AccessQueueStatus GetStatus() => _status;
|
||||||
|
|
||||||
public AccessQueueConfig GetConfig() => new AccessQueueConfig
|
public AccessQueueConfig GetConfig() => _accessService.GetConfiguration();
|
||||||
|
|
||||||
|
public void UpdateConfig(AccessQueueConfig config)
|
||||||
{
|
{
|
||||||
ActivitySeconds = _config.GetValue<int>("AccessQueue:ActivitySeconds"),
|
_accessService.UpdateConfiguration(config);
|
||||||
ExpirationSeconds = _config.GetValue<int>("AccessQueue:ExpirationSeconds"),
|
}
|
||||||
CapacityLimit = _config.GetValue<int>("AccessQueue:CapacityLimit")
|
|
||||||
};
|
|
||||||
|
|
||||||
public Guid AddUser()
|
public Guid AddUser()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using AccessQueuePlayground.Models;
|
using AccessQueuePlayground.Models;
|
||||||
|
using AccessQueueService.Models;
|
||||||
|
|
||||||
namespace AccessQueuePlayground.Services
|
namespace AccessQueuePlayground.Services
|
||||||
{
|
{
|
||||||
|
@ -6,6 +7,7 @@ namespace AccessQueuePlayground.Services
|
||||||
{
|
{
|
||||||
public event Action? StatusUpdated;
|
public event Action? StatusUpdated;
|
||||||
public AccessQueueConfig GetConfig();
|
public AccessQueueConfig GetConfig();
|
||||||
|
public void UpdateConfig(AccessQueueConfig config);
|
||||||
public Task RecalculateStatus();
|
public Task RecalculateStatus();
|
||||||
public AccessQueueStatus GetStatus();
|
public AccessQueueStatus GetStatus();
|
||||||
public Guid AddUser();
|
public Guid AddUser();
|
||||||
|
|
|
@ -28,5 +28,18 @@ namespace AccessQueueService.Controllers
|
||||||
{
|
{
|
||||||
return await _accessService.RevokeAccess(id);
|
return await _accessService.RevokeAccess(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("configuration")]
|
||||||
|
public ActionResult<AccessQueueConfig> GetConfiguration()
|
||||||
|
{
|
||||||
|
return Ok(_accessService.GetConfiguration());
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("configuration")]
|
||||||
|
public IActionResult UpdateConfiguration([FromBody] AccessQueueConfig config)
|
||||||
|
{
|
||||||
|
_accessService.PatchConfiguration(config);
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
namespace AccessQueueService.Models
|
||||||
|
{
|
||||||
|
public class AccessQueueConfig
|
||||||
|
{
|
||||||
|
public int? CapacityLimit { get; set; }
|
||||||
|
public int? ActivitySeconds { get; set; }
|
||||||
|
public int? ExpirationSeconds { get; set; }
|
||||||
|
public bool? RollingExpiration { get; set; }
|
||||||
|
|
||||||
|
public AccessQueueConfig Clone()
|
||||||
|
{
|
||||||
|
return (AccessQueueConfig)this.MemberwiseClone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,37 +12,52 @@ namespace AccessQueueService.Services
|
||||||
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 readonly int EXP_SECONDS;
|
private AccessQueueConfig _config;
|
||||||
private readonly int ACT_SECONDS;
|
|
||||||
private readonly int CAPACITY_LIMIT;
|
|
||||||
private readonly bool ROLLING_EXPIRATION;
|
|
||||||
public AccessService(IConfiguration configuration, IAccessQueueRepo accessQueueRepo, ILogger<AccessService> logger)
|
public AccessService(IConfiguration configuration, IAccessQueueRepo accessQueueRepo, ILogger<AccessService> logger)
|
||||||
{
|
{
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_accessQueueRepo = accessQueueRepo;
|
_accessQueueRepo = accessQueueRepo;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
EXP_SECONDS = _configuration.GetValue<int>("AccessQueue:ExpirationSeconds");
|
_config = new AccessQueueConfig
|
||||||
ACT_SECONDS = _configuration.GetValue<int>("AccessQueue:ActivitySeconds");
|
{
|
||||||
CAPACITY_LIMIT = _configuration.GetValue<int>("AccessQueue:CapacityLimit");
|
ExpirationSeconds = _configuration.GetValue<int>("AccessQueue:ExpirationSeconds"),
|
||||||
ROLLING_EXPIRATION = _configuration.GetValue<bool>("AccessQueue:RollingExpiration");
|
ActivitySeconds = _configuration.GetValue<int>("AccessQueue:ActivitySeconds"),
|
||||||
|
CapacityLimit = _configuration.GetValue<int>("AccessQueue:CapacityLimit"),
|
||||||
|
RollingExpiration = _configuration.GetValue<bool>("AccessQueue:RollingExpiration")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public AccessQueueConfig GetConfiguration() => _config.Clone();
|
||||||
|
public void UpdateConfiguration(AccessQueueConfig config)
|
||||||
|
{
|
||||||
|
_config = config.Clone();
|
||||||
|
}
|
||||||
|
public void PatchConfiguration(AccessQueueConfig partialConfig)
|
||||||
|
{
|
||||||
|
if (partialConfig.CapacityLimit.HasValue) _config.CapacityLimit = partialConfig.CapacityLimit.Value;
|
||||||
|
if (partialConfig.ActivitySeconds.HasValue) _config.ActivitySeconds = partialConfig.ActivitySeconds.Value;
|
||||||
|
if (partialConfig.ExpirationSeconds.HasValue) _config.ExpirationSeconds = partialConfig.ExpirationSeconds.Value;
|
||||||
|
if (partialConfig.RollingExpiration.HasValue) _config.RollingExpiration = partialConfig.RollingExpiration.Value;
|
||||||
}
|
}
|
||||||
public int UnexpiredTicketsCount => _accessQueueRepo.GetUnexpiredTicketsCount();
|
public int UnexpiredTicketsCount => _accessQueueRepo.GetUnexpiredTicketsCount();
|
||||||
public int ActiveTicketsCount => _accessQueueRepo.GetActiveTicketsCount(DateTime.UtcNow.AddSeconds(-_configuration.GetValue<int>("AccessQueue:ActivitySeconds")));
|
public int ActiveTicketsCount => _accessQueueRepo.GetActiveTicketsCount(DateTime.UtcNow.AddSeconds(-_config.ActivitySeconds.Value));
|
||||||
public int QueueCount => _accessQueueRepo.GetQueueCount();
|
public int QueueCount => _accessQueueRepo.GetQueueCount();
|
||||||
public async Task<AccessResponse> RequestAccess(string userId)
|
public async Task<AccessResponse> RequestAccess(string userId)
|
||||||
{
|
{
|
||||||
await _queueLock.WaitAsync();
|
await _queueLock.WaitAsync();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var hasCapacity = !_accessQueueRepo.DidDequeueUntilFull(ACT_SECONDS, EXP_SECONDS, CAPACITY_LIMIT);
|
var hasCapacity = !_accessQueueRepo.DidDequeueUntilFull(
|
||||||
|
_config.ActivitySeconds.Value,
|
||||||
|
_config.ExpirationSeconds.Value,
|
||||||
|
_config.CapacityLimit.Value);
|
||||||
var existingTicket = _accessQueueRepo.GetTicket(userId);
|
var existingTicket = _accessQueueRepo.GetTicket(userId);
|
||||||
if (existingTicket != null && existingTicket.ExpiresOn > DateTime.UtcNow)
|
if (existingTicket != null && existingTicket.ExpiresOn > DateTime.UtcNow)
|
||||||
{
|
{
|
||||||
// Already has access
|
// Already has access
|
||||||
var expiresOn = existingTicket.ExpiresOn;
|
var expiresOn = existingTicket.ExpiresOn;
|
||||||
if (ROLLING_EXPIRATION)
|
if (_config.RollingExpiration.Value)
|
||||||
{
|
{
|
||||||
expiresOn = DateTime.UtcNow.AddSeconds(EXP_SECONDS);
|
expiresOn = DateTime.UtcNow.AddSeconds(_config.ExpirationSeconds.Value);
|
||||||
}
|
}
|
||||||
_accessQueueRepo.UpsertTicket(new AccessTicket
|
_accessQueueRepo.UpsertTicket(new AccessTicket
|
||||||
{
|
{
|
||||||
|
@ -62,7 +77,7 @@ namespace AccessQueueService.Services
|
||||||
var accessTicket = new AccessTicket
|
var accessTicket = new AccessTicket
|
||||||
{
|
{
|
||||||
UserId = userId,
|
UserId = userId,
|
||||||
ExpiresOn = DateTime.UtcNow.AddSeconds(EXP_SECONDS),
|
ExpiresOn = DateTime.UtcNow.AddSeconds(_config.ExpirationSeconds.Value),
|
||||||
LastActive = DateTime.UtcNow
|
LastActive = DateTime.UtcNow
|
||||||
};
|
};
|
||||||
_accessQueueRepo.UpsertTicket(accessTicket);
|
_accessQueueRepo.UpsertTicket(accessTicket);
|
||||||
|
|
|
@ -7,5 +7,8 @@ namespace AccessQueueService.Services
|
||||||
public Task<AccessResponse> RequestAccess(string userId);
|
public Task<AccessResponse> RequestAccess(string userId);
|
||||||
public Task<bool> RevokeAccess(string userId);
|
public Task<bool> RevokeAccess(string userId);
|
||||||
public Task<int> DeleteExpiredTickets();
|
public Task<int> DeleteExpiredTickets();
|
||||||
|
public AccessQueueConfig GetConfiguration();
|
||||||
|
public void UpdateConfiguration(AccessQueueConfig config);
|
||||||
|
public void PatchConfiguration(AccessQueueConfig partialConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue