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="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.4" />
|
||||
<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="System.IdentityModel.Tokens.Jwt" Version="6.35.0" />
|
||||
</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 int Currency { get; set; }
|
||||
public string ExternalAccountNumber { get; set; }
|
||||
public int Owner { get; set; }
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
using System.Threading.Tasks;
|
||||
using AAIntegration.SimmonsBank.API.Entities;
|
||||
using AAIntegration.SimmonsBank.API.Services;
|
||||
|
||||
namespace AAIntegration.SimmonsBank.API.Processes;
|
||||
|
||||
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.Services;
|
||||
using Internal;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace AAIntegration.SimmonsBank.API.Processes;
|
||||
|
||||
public class PuppeteerProcess : IPuppeteerProcess
|
||||
{
|
||||
private readonly EnvelopeFundConfig _config;
|
||||
private readonly PuppeteerConfig _config;
|
||||
private readonly ILogger<PuppeteerProcess> _logger;
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
|
||||
public PuppeteerProcess(
|
||||
IOptions<EnvelopeFundConfig> config,
|
||||
ILogger<PuppeteerProcess> logger)
|
||||
IOptions<PuppeteerConfig> config,
|
||||
ILogger<PuppeteerProcess> logger,
|
||||
IMemoryCache memoryCache)
|
||||
{
|
||||
_config = config.Value;
|
||||
_logger = logger;
|
||||
_memoryCache = memoryCache;
|
||||
}
|
||||
|
||||
public async Task FundEnvelopes()
|
||||
public async Task StayLoggedIn(User user)
|
||||
{
|
||||
_logger.LogInformation($"Starting envelope funding...");
|
||||
|
||||
// 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);
|
||||
_logger.LogInformation($"... doing work and processing for user {user.Id} ...");
|
||||
}
|
||||
}*/
|
||||
|
||||
if (false)
|
||||
_logger.LogInformation($"No action taken.");
|
||||
else
|
||||
_logger.LogInformation($"Envelope funding complete.");
|
||||
}
|
||||
// Helper Functions
|
||||
|
||||
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ internal class Program
|
||||
|
||||
// Configure strongly typed settings object
|
||||
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"));
|
||||
|
||||
DatabaseConfig dbConfig = builder.Configuration.GetSection("ActiveAllocator:Database").Get<DatabaseConfig>();
|
||||
|
@ -24,6 +24,7 @@ public interface IUserService
|
||||
void Delete(string apiKey);
|
||||
Dictionary<string, int> GetAllApiKeys();
|
||||
User GetUser(string ApiKey);
|
||||
IEnumerable<User> GetAll();
|
||||
|
||||
/* Other cringe way
|
||||
AuthenticateResponse Authenticate(AuthenticateRequest model);
|
||||
@ -116,6 +117,11 @@ public class UserService : IUserService
|
||||
return user;
|
||||
}
|
||||
|
||||
public IEnumerable<User> GetAll()
|
||||
{
|
||||
return _context.Users;
|
||||
}
|
||||
|
||||
// helper methods
|
||||
|
||||
private User getUser(int id)
|
||||
|
@ -4,50 +4,136 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using AAIntegration.SimmonsBank.API.Processes;
|
||||
using AAIntegration.SimmonsBank.API.Services;
|
||||
using AAIntegration.SimmonsBank.API.Entities;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace AAIntegration.SimmonsBank.API.Workers;
|
||||
|
||||
public class PuppeteerWorker : BackgroundService
|
||||
{
|
||||
private readonly EnvelopeFundConfig _config;
|
||||
private readonly PuppeteerConfig _config;
|
||||
private readonly IPuppeteerProcess _puppeteerProcess;
|
||||
private readonly ILogger<PuppeteerWorker> _logger;
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||
|
||||
public PuppeteerWorker(
|
||||
IOptions<EnvelopeFundConfig> config,
|
||||
IOptions<PuppeteerConfig> config,
|
||||
IPuppeteerProcess puppeteerProcess,
|
||||
ILogger<PuppeteerWorker> logger,
|
||||
IMemoryCache memoryCache,
|
||||
IServiceScopeFactory serviceScopeFactory)
|
||||
{
|
||||
_config = config.Value;
|
||||
_puppeteerProcess = puppeteerProcess;
|
||||
_logger = logger;
|
||||
_memoryCache = memoryCache;
|
||||
_serviceScopeFactory = serviceScopeFactory;
|
||||
}
|
||||
|
||||
private IUserService _userService;
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
DateTime? lastExecutedOn = null;
|
||||
bool operationOccurred = false;
|
||||
|
||||
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)
|
||||
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(minutesRemaining < 0 ? 0 : minutesRemaining), stoppingToken);
|
||||
await Task.Delay(TimeSpan.FromMinutes(_config.TaskCheckIntervalMinutes), stoppingToken);
|
||||
}
|
||||
|
||||
lastExecutedOn = DateTime.UtcNow;
|
||||
_logger.LogInformation("EnvelopeFundWorker running at: {time}", DateTimeOffset.Now);
|
||||
|
||||
//await _puppeteerProcess.FundEnvelopes(envelopeService);
|
||||
_logger.LogInformation("PuppeteerWorker executed at: {time}", DateTimeOffset.Now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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",
|
||||
"APIUrl": "https://localhost:7260"
|
||||
},
|
||||
"EnvelopeFund": {
|
||||
"CheckIntervalInMinutes": 10
|
||||
"Puppeteer": {
|
||||
"TaskCheckIntervalMinutes": 1,
|
||||
"KeepAliveIntervalMinutes": 10,
|
||||
"CheckForNewDataIntervalMinutes": 15
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user