Added puppeteerConfig. Setup timing logic for keeping users logged in
This commit is contained in:
parent
0944642656
commit
06b461985c
@ -30,6 +30,7 @@
|
|||||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.8" />
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.8" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.4" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.4" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="7.0.13" />
|
<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="7.0.13" />
|
||||||
|
<PackageReference Include="PuppeteerSharp" Version="15.1.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.35.0" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.35.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
namespace AAIntegration.SimmonsBank.API.Configs;
|
|
||||||
|
|
||||||
public class EnvelopeFundConfig
|
|
||||||
{
|
|
||||||
public int CheckIntervalInMinutes { get; set; }
|
|
||||||
}
|
|
15
AAIntegration.SimmonsBank.API/Configs/PuppeteerConfig.cs
Normal file
15
AAIntegration.SimmonsBank.API/Configs/PuppeteerConfig.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
namespace AAIntegration.SimmonsBank.API.Configs;
|
||||||
|
|
||||||
|
public class PuppeteerConfig
|
||||||
|
{
|
||||||
|
public int KeepAliveIntervalMinutes { get; set; }
|
||||||
|
public int CheckForNewDataIntervalMinutes { get; set; }
|
||||||
|
public int TaskCheckIntervalMinutes { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PuppeteerConfigConstants
|
||||||
|
{
|
||||||
|
public const string KeepAliveIntervalMinutes = "KeepAliveIntervalMinutes";
|
||||||
|
public const string CheckForNewDataIntervalMinutes = "CheckForNewDataIntervalMinutes";
|
||||||
|
public const string TaskCheckIntervalMinutes = "TaskCheckIntervalMinutes";
|
||||||
|
}
|
@ -10,5 +10,4 @@ public class AccountCreateRequest
|
|||||||
public string InitialBalance { get; set; }
|
public string InitialBalance { get; set; }
|
||||||
public int Currency { get; set; }
|
public int Currency { get; set; }
|
||||||
public string ExternalAccountNumber { get; set; }
|
public string ExternalAccountNumber { get; set; }
|
||||||
public int Owner { get; set; }
|
|
||||||
}
|
}
|
@ -1,9 +1,10 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using AAIntegration.SimmonsBank.API.Entities;
|
||||||
using AAIntegration.SimmonsBank.API.Services;
|
using AAIntegration.SimmonsBank.API.Services;
|
||||||
|
|
||||||
namespace AAIntegration.SimmonsBank.API.Processes;
|
namespace AAIntegration.SimmonsBank.API.Processes;
|
||||||
|
|
||||||
public interface IPuppeteerProcess
|
public interface IPuppeteerProcess
|
||||||
{
|
{
|
||||||
Task FundEnvelopes();
|
Task StayLoggedIn(User user);
|
||||||
}
|
}
|
||||||
|
@ -6,48 +6,33 @@ using AAIntegration.SimmonsBank.API.Entities;
|
|||||||
using AAIntegration.SimmonsBank.API.Models.Transactions;
|
using AAIntegration.SimmonsBank.API.Models.Transactions;
|
||||||
using AAIntegration.SimmonsBank.API.Services;
|
using AAIntegration.SimmonsBank.API.Services;
|
||||||
using Internal;
|
using Internal;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace AAIntegration.SimmonsBank.API.Processes;
|
namespace AAIntegration.SimmonsBank.API.Processes;
|
||||||
|
|
||||||
public class PuppeteerProcess : IPuppeteerProcess
|
public class PuppeteerProcess : IPuppeteerProcess
|
||||||
{
|
{
|
||||||
private readonly EnvelopeFundConfig _config;
|
private readonly PuppeteerConfig _config;
|
||||||
private readonly ILogger<PuppeteerProcess> _logger;
|
private readonly ILogger<PuppeteerProcess> _logger;
|
||||||
|
private readonly IMemoryCache _memoryCache;
|
||||||
|
|
||||||
public PuppeteerProcess(
|
public PuppeteerProcess(
|
||||||
IOptions<EnvelopeFundConfig> config,
|
IOptions<PuppeteerConfig> config,
|
||||||
ILogger<PuppeteerProcess> logger)
|
ILogger<PuppeteerProcess> logger,
|
||||||
|
IMemoryCache memoryCache)
|
||||||
{
|
{
|
||||||
_config = config.Value;
|
_config = config.Value;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_memoryCache = memoryCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task FundEnvelopes()
|
public async Task StayLoggedIn(User user)
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"Starting envelope funding...");
|
_logger.LogInformation($"... doing work and processing for user {user.Id} ...");
|
||||||
|
|
||||||
// Grab envelopes
|
|
||||||
/*List<Envelope> envelopes = envelopeService.GetAll().ToList();
|
|
||||||
|
|
||||||
bool anyTriggered = false;
|
|
||||||
|
|
||||||
foreach (Envelope env in envelopes)
|
|
||||||
{
|
|
||||||
// Check if needs triggering
|
|
||||||
if (env.Enabled && !envelopeService.HasBeenFundedThisMonth(env.Id))
|
|
||||||
{
|
|
||||||
_logger.LogInformation($"Envelope '{env.Name}' (id={env.Id}) needs funding - Has now been triggered.");
|
|
||||||
anyTriggered = true;
|
|
||||||
|
|
||||||
// Fund Envelope
|
|
||||||
envelopeService.FundEnvelopeForThisMonth(env.Id);
|
|
||||||
}
|
}
|
||||||
}*/
|
|
||||||
|
|
||||||
if (false)
|
// Helper Functions
|
||||||
_logger.LogInformation($"No action taken.");
|
|
||||||
else
|
|
||||||
_logger.LogInformation($"Envelope funding complete.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ internal class Program
|
|||||||
|
|
||||||
// Configure strongly typed settings object
|
// Configure strongly typed settings object
|
||||||
builder.Services.Configure<AppSettings>(builder.Configuration.GetSection("AppSettings"));
|
builder.Services.Configure<AppSettings>(builder.Configuration.GetSection("AppSettings"));
|
||||||
builder.Services.Configure<EnvelopeFundConfig>(builder.Configuration.GetSection("EnvelopeFund"));
|
builder.Services.Configure<PuppeteerConfig>(builder.Configuration.GetSection("Puppeteer"));
|
||||||
builder.Services.Configure<DatabaseConfig>(builder.Configuration.GetSection("ActiveAllocator:Database"));
|
builder.Services.Configure<DatabaseConfig>(builder.Configuration.GetSection("ActiveAllocator:Database"));
|
||||||
|
|
||||||
DatabaseConfig dbConfig = builder.Configuration.GetSection("ActiveAllocator:Database").Get<DatabaseConfig>();
|
DatabaseConfig dbConfig = builder.Configuration.GetSection("ActiveAllocator:Database").Get<DatabaseConfig>();
|
||||||
|
@ -24,6 +24,7 @@ public interface IUserService
|
|||||||
void Delete(string apiKey);
|
void Delete(string apiKey);
|
||||||
Dictionary<string, int> GetAllApiKeys();
|
Dictionary<string, int> GetAllApiKeys();
|
||||||
User GetUser(string ApiKey);
|
User GetUser(string ApiKey);
|
||||||
|
IEnumerable<User> GetAll();
|
||||||
|
|
||||||
/* Other cringe way
|
/* Other cringe way
|
||||||
AuthenticateResponse Authenticate(AuthenticateRequest model);
|
AuthenticateResponse Authenticate(AuthenticateRequest model);
|
||||||
@ -116,6 +117,11 @@ public class UserService : IUserService
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<User> GetAll()
|
||||||
|
{
|
||||||
|
return _context.Users;
|
||||||
|
}
|
||||||
|
|
||||||
// helper methods
|
// helper methods
|
||||||
|
|
||||||
private User getUser(int id)
|
private User getUser(int id)
|
||||||
|
@ -4,50 +4,136 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using AAIntegration.SimmonsBank.API.Processes;
|
using AAIntegration.SimmonsBank.API.Processes;
|
||||||
using AAIntegration.SimmonsBank.API.Services;
|
using AAIntegration.SimmonsBank.API.Services;
|
||||||
|
using AAIntegration.SimmonsBank.API.Entities;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
|
||||||
namespace AAIntegration.SimmonsBank.API.Workers;
|
namespace AAIntegration.SimmonsBank.API.Workers;
|
||||||
|
|
||||||
public class PuppeteerWorker : BackgroundService
|
public class PuppeteerWorker : BackgroundService
|
||||||
{
|
{
|
||||||
private readonly EnvelopeFundConfig _config;
|
private readonly PuppeteerConfig _config;
|
||||||
private readonly IPuppeteerProcess _puppeteerProcess;
|
private readonly IPuppeteerProcess _puppeteerProcess;
|
||||||
private readonly ILogger<PuppeteerWorker> _logger;
|
private readonly ILogger<PuppeteerWorker> _logger;
|
||||||
|
private readonly IMemoryCache _memoryCache;
|
||||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||||
|
|
||||||
public PuppeteerWorker(
|
public PuppeteerWorker(
|
||||||
IOptions<EnvelopeFundConfig> config,
|
IOptions<PuppeteerConfig> config,
|
||||||
IPuppeteerProcess puppeteerProcess,
|
IPuppeteerProcess puppeteerProcess,
|
||||||
ILogger<PuppeteerWorker> logger,
|
ILogger<PuppeteerWorker> logger,
|
||||||
|
IMemoryCache memoryCache,
|
||||||
IServiceScopeFactory serviceScopeFactory)
|
IServiceScopeFactory serviceScopeFactory)
|
||||||
{
|
{
|
||||||
_config = config.Value;
|
_config = config.Value;
|
||||||
_puppeteerProcess = puppeteerProcess;
|
_puppeteerProcess = puppeteerProcess;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_memoryCache = memoryCache;
|
||||||
_serviceScopeFactory = serviceScopeFactory;
|
_serviceScopeFactory = serviceScopeFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IUserService _userService;
|
||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
DateTime? lastExecutedOn = null;
|
DateTime? lastExecutedOn = null;
|
||||||
|
bool operationOccurred = false;
|
||||||
|
|
||||||
using (var scope = _serviceScopeFactory.CreateScope())
|
using (var scope = _serviceScopeFactory.CreateScope())
|
||||||
{
|
{
|
||||||
//IEnvelopeService envelopeService = scope.ServiceProvider.GetService<IEnvelopeService>();
|
_userService = scope.ServiceProvider.GetService<IUserService>();
|
||||||
|
|
||||||
// This is how we keep the app running (in the background)
|
// This is how we keep the app running (in the background)
|
||||||
while (!stoppingToken.IsCancellationRequested)
|
while (!stoppingToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
if (lastExecutedOn != null)
|
// Keep Alive processing
|
||||||
|
operationOccurred = await ProcessUsersKeepalive();
|
||||||
|
|
||||||
|
|
||||||
|
_logger.LogInformation($"Operation occurred? {operationOccurred}");
|
||||||
|
|
||||||
|
// If no operation occurred, waits before looping again
|
||||||
|
if (lastExecutedOn != null && operationOccurred == false)
|
||||||
{
|
{
|
||||||
int minutesRemaining = _config.CheckIntervalInMinutes - (int)DateTime.UtcNow.Subtract(lastExecutedOn.Value).TotalMinutes;
|
await Task.Delay(TimeSpan.FromMinutes(_config.TaskCheckIntervalMinutes), stoppingToken);
|
||||||
await Task.Delay(TimeSpan.FromMinutes(minutesRemaining < 0 ? 0 : minutesRemaining), stoppingToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lastExecutedOn = DateTime.UtcNow;
|
lastExecutedOn = DateTime.UtcNow;
|
||||||
_logger.LogInformation("EnvelopeFundWorker running at: {time}", DateTimeOffset.Now);
|
_logger.LogInformation("PuppeteerWorker executed at: {time}", DateTimeOffset.Now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//await _puppeteerProcess.FundEnvelopes(envelopeService);
|
private async Task<bool> ProcessUsersKeepalive()
|
||||||
}
|
{
|
||||||
|
bool operationOccurred = false;
|
||||||
|
|
||||||
|
foreach (User user in _userService.GetAll().ToList())
|
||||||
|
{
|
||||||
|
int ka = _config.KeepAliveIntervalMinutes;
|
||||||
|
int uka = (int)DateTime.UtcNow.Subtract(GetUserLastExecution(PuppeteerConfigConstants.KeepAliveIntervalMinutes, user.Id)).TotalMinutes;
|
||||||
|
|
||||||
|
//_logger.LogInformation($"KeepAlive configured to {ka}. This user hasn't been kept alive in {uka} minute(s).");
|
||||||
|
|
||||||
|
if (_config.KeepAliveIntervalMinutes < (int)DateTime.UtcNow.Subtract(GetUserLastExecution(PuppeteerConfigConstants.KeepAliveIntervalMinutes, user.Id)).TotalMinutes)
|
||||||
|
{
|
||||||
|
await _puppeteerProcess.StayLoggedIn(user);
|
||||||
|
SetUserLastExecution(PuppeteerConfigConstants.KeepAliveIntervalMinutes, user.Id, DateTime.UtcNow);
|
||||||
|
operationOccurred = true;
|
||||||
|
_logger.LogInformation($"Operation set to true because of user {user.Id}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return operationOccurred;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DateTime GetUserLastExecution(string cacheKey, int userId)
|
||||||
|
{
|
||||||
|
var internalKeys = GetLastExecutionCachedDictionary(cacheKey);
|
||||||
|
|
||||||
|
if (!internalKeys.TryGetValue(userId, out var lastExecution))
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Could not find userId in '{cacheKey}' cache. Returning '{DateTime.MinValue}'.");
|
||||||
|
return DateTime.MinValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation($"Just got user {userId} from cache with value {lastExecution}");
|
||||||
|
return lastExecution;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetUserLastExecution(string cacheKey, int userId, DateTime lastExecution)
|
||||||
|
{
|
||||||
|
var internalKeys = GetLastExecutionCachedDictionary(cacheKey);
|
||||||
|
|
||||||
|
if (internalKeys.ContainsKey(userId))
|
||||||
|
internalKeys[userId] = lastExecution;
|
||||||
|
else
|
||||||
|
internalKeys.Add(userId, lastExecution);
|
||||||
|
|
||||||
|
_memoryCache.Set(cacheKey, internalKeys);
|
||||||
|
_logger.LogInformation($"Just set user {userId} into cache with value {lastExecution}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<int, DateTime> GetLastExecutionCachedDictionary(string cacheKey)
|
||||||
|
{
|
||||||
|
// Sets cache if no dictionary is found
|
||||||
|
if (!_memoryCache.TryGetValue<Dictionary<int, DateTime>>(cacheKey, out var internalKeys))
|
||||||
|
{
|
||||||
|
internalKeys = _userService.GetAll()
|
||||||
|
.ToDictionary(u => u.Id, u => DateTime.MinValue);
|
||||||
|
_memoryCache.Set(cacheKey, internalKeys);
|
||||||
|
_logger.LogInformation($"Updated users in '{cacheKey}' cache with new id list.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return internalKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintCacheValues(string cacheKey)
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Printing cache values from '{cacheKey}'");
|
||||||
|
Dictionary<int, DateTime> internalKeys = GetLastExecutionCachedDictionary(cacheKey);
|
||||||
|
foreach (KeyValuePair<int, DateTime> entry in internalKeys)
|
||||||
|
{
|
||||||
|
_logger.LogInformation($" {entry.Key} <=> {entry.Value}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,9 @@
|
|||||||
"Secret": "5de80277015f9fd564c4d1cc2cf827dbb1774cd66e7d79aa258d9c35a9f67f32fc6cf0dc24244242bd9501288e0fd69e315b",
|
"Secret": "5de80277015f9fd564c4d1cc2cf827dbb1774cd66e7d79aa258d9c35a9f67f32fc6cf0dc24244242bd9501288e0fd69e315b",
|
||||||
"APIUrl": "https://localhost:7260"
|
"APIUrl": "https://localhost:7260"
|
||||||
},
|
},
|
||||||
"EnvelopeFund": {
|
"Puppeteer": {
|
||||||
"CheckIntervalInMinutes": 10
|
"TaskCheckIntervalMinutes": 1,
|
||||||
|
"KeepAliveIntervalMinutes": 10,
|
||||||
|
"CheckForNewDataIntervalMinutes": 15
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user