Moved the puppeteer logic to the new PuppeteerService class
This commit is contained in:
parent
8231cedcf1
commit
436c1baaf7
@ -17,3 +17,9 @@ public class PuppeteerConfigConstants
|
|||||||
public const string SimmonsBankBaseUrl = "SimmonsBankBaseUrl";
|
public const string SimmonsBankBaseUrl = "SimmonsBankBaseUrl";
|
||||||
public const string BrowserOperationTimeoutSeconds = "BrowserOperationTimeoutSeconds";
|
public const string BrowserOperationTimeoutSeconds = "BrowserOperationTimeoutSeconds";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PuppeteerConstants
|
||||||
|
{
|
||||||
|
public const string BROWSER_CACHE_KEY = "BrowserCacheKey";
|
||||||
|
public const string USER_SB_ID = "UserSimmonsBankId";
|
||||||
|
}
|
@ -6,6 +6,7 @@ namespace AAIntegration.SimmonsBank.API.Processes;
|
|||||||
|
|
||||||
public interface IPuppeteerProcess
|
public interface IPuppeteerProcess
|
||||||
{
|
{
|
||||||
|
void SetService(IPuppeteerService puppeteerService);
|
||||||
void SetStoppingToken(CancellationToken stoppingToken);
|
void SetStoppingToken(CancellationToken stoppingToken);
|
||||||
Task StayLoggedIn(User user);
|
Task StayLoggedIn(User user);
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,9 @@ public class PuppeteerProcess : IPuppeteerProcess
|
|||||||
private readonly PuppeteerConfig _config;
|
private readonly PuppeteerConfig _config;
|
||||||
private readonly ILogger<PuppeteerProcess> _logger;
|
private readonly ILogger<PuppeteerProcess> _logger;
|
||||||
private readonly IMemoryCache _memoryCache;
|
private readonly IMemoryCache _memoryCache;
|
||||||
private const string BROWSER_CACHE_KEY = "BrowserCacheKey";
|
|
||||||
private const string DASHBOARD_SELECTOR = "body > banno-web > bannoweb-layout > bannoweb-dashboard";
|
private const string DASHBOARD_SELECTOR = "body > banno-web > bannoweb-layout > bannoweb-dashboard";
|
||||||
private CancellationToken _stoppingToken;
|
private CancellationToken _stoppingToken;
|
||||||
|
private IPuppeteerService _puppeteerService;
|
||||||
|
|
||||||
public PuppeteerProcess(
|
public PuppeteerProcess(
|
||||||
IOptions<PuppeteerConfig> config,
|
IOptions<PuppeteerConfig> config,
|
||||||
@ -34,6 +34,11 @@ public class PuppeteerProcess : IPuppeteerProcess
|
|||||||
_stoppingToken = new CancellationToken();
|
_stoppingToken = new CancellationToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetService(IPuppeteerService puppeteerService)
|
||||||
|
{
|
||||||
|
_puppeteerService = puppeteerService;
|
||||||
|
}
|
||||||
|
|
||||||
public void SetStoppingToken(CancellationToken stoppingToken)
|
public void SetStoppingToken(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
_stoppingToken = stoppingToken;
|
_stoppingToken = stoppingToken;
|
||||||
@ -43,12 +48,12 @@ public class PuppeteerProcess : IPuppeteerProcess
|
|||||||
{
|
{
|
||||||
_logger.LogInformation($"... doing work and processing for user {user.Id} ...");
|
_logger.LogInformation($"... doing work and processing for user {user.Id} ...");
|
||||||
|
|
||||||
IBrowser browser = await GetUserBrowserAsync(user);
|
if (!await _puppeteerService.IsLoggedIn(user, _stoppingToken))
|
||||||
|
|
||||||
if (!await IsLoggedIn(user, browser))
|
|
||||||
{
|
{
|
||||||
await Login(user, browser);
|
await _puppeteerService.Login(user, _stoppingToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await Delay(1000000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper Functions
|
// Helper Functions
|
||||||
@ -57,166 +62,4 @@ public class PuppeteerProcess : IPuppeteerProcess
|
|||||||
{
|
{
|
||||||
await Task.Delay(TimeSpan.FromMilliseconds(milliseconds), _stoppingToken);
|
await Task.Delay(TimeSpan.FromMilliseconds(milliseconds), _stoppingToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IBrowser> GetUserBrowserAsync(User user)
|
|
||||||
{
|
|
||||||
if (_memoryCache.TryGetValue<Dictionary<int, IBrowser>>(BROWSER_CACHE_KEY, out var internalKeys))
|
|
||||||
{
|
|
||||||
List<KeyValuePair<int, IBrowser>> list = internalKeys.Where(x => x.Key == user.Id).ToList();
|
|
||||||
|
|
||||||
if (list.Count > 0 && list.First().Value != null)
|
|
||||||
{
|
|
||||||
_logger.LogInformation($"Found the browser for user with id '{user.Id}'.");
|
|
||||||
return list.First().Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation($"Could NOT find the browser for user with id '{user.Id}'. About to create one...");
|
|
||||||
|
|
||||||
using var browserFetcher = new BrowserFetcher();
|
|
||||||
await browserFetcher.DownloadAsync();
|
|
||||||
|
|
||||||
var options = new LaunchOptions {
|
|
||||||
Headless = false,
|
|
||||||
IgnoreHTTPSErrors = true
|
|
||||||
};
|
|
||||||
|
|
||||||
IBrowser browser = await Puppeteer.LaunchAsync(options);
|
|
||||||
|
|
||||||
internalKeys ??= new Dictionary<int, IBrowser>();
|
|
||||||
internalKeys.Add(user.Id, browser);
|
|
||||||
_memoryCache.Set(BROWSER_CACHE_KEY, internalKeys);
|
|
||||||
|
|
||||||
return browser;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<bool> Login(User user, IBrowser browser)
|
|
||||||
{
|
|
||||||
TimeSpan timeout = TimeSpan.FromSeconds(_config.BrowserOperationTimeoutSeconds);
|
|
||||||
|
|
||||||
// Setup Page
|
|
||||||
await using IPage page = await browser.NewPageAsync();
|
|
||||||
await page.SetViewportAsync(new ViewPortOptions { Width = 1200, Height = 720 });
|
|
||||||
WaitUntilNavigation[] waitUntils = { WaitUntilNavigation.Networkidle0 };
|
|
||||||
|
|
||||||
// Navigate to login screen
|
|
||||||
await page.GoToAsync(_config.SimmonsBankBaseUrl + "/login");//, null, waitUntils); // wait until page load
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Type username
|
|
||||||
string selector = "#username";
|
|
||||||
await page.WaitForSelectorAsync(selector).WaitAsync(timeout, _stoppingToken);
|
|
||||||
await page.TypeAsync(selector, user.SimmonsBankUsername);
|
|
||||||
|
|
||||||
// Press 1st Submit Button
|
|
||||||
selector = "jha-button";
|
|
||||||
await page.WaitForSelectorAsync(selector).WaitAsync(timeout, _stoppingToken);
|
|
||||||
await page.ClickAsync(selector);
|
|
||||||
|
|
||||||
// Type password
|
|
||||||
selector = "#password";
|
|
||||||
await page.WaitForSelectorAsync(selector).WaitAsync(timeout, _stoppingToken);
|
|
||||||
await page.TypeAsync(selector, user.SimmonsBankPassword);
|
|
||||||
|
|
||||||
// Click SignIn button - In Chrome -> JS Path worked well
|
|
||||||
selector = "#login-password-form > bannoweb-flex-wrapper:nth-child(5) > div > jha-button";
|
|
||||||
await page.WaitForSelectorAsync(selector).WaitAsync(timeout, _stoppingToken);
|
|
||||||
IElementHandle signInButton = await page.QuerySelectorAsync(selector);
|
|
||||||
|
|
||||||
if (signInButton != null)
|
|
||||||
{
|
|
||||||
await signInButton.ClickAsync();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogError("Failed to find Sign-In button");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
await page.WaitForNetworkIdleAsync();
|
|
||||||
|
|
||||||
// Find TOTP input
|
|
||||||
selector = "body > banno-web > bannoweb-login > bannoweb-login-steps > bannoweb-two-factor-verify > jha-slider > jha-slider-content > jha-slider-pane:nth-child(4) > bannoweb-two-factor-enter-code > article > form > jha-form-floating-group > input[type=text]";
|
|
||||||
await page.WaitForSelectorAsync(selector).WaitAsync(timeout, _stoppingToken);
|
|
||||||
//await Delay(150);
|
|
||||||
|
|
||||||
// Generate TOTP code
|
|
||||||
Totp totpInstance = new Totp(Base32Encoding.ToBytes(user.MFAKey));
|
|
||||||
string totpCode = totpInstance.ComputeTotp();
|
|
||||||
|
|
||||||
// Type TOTP code
|
|
||||||
IElementHandle totpInput = await page.QuerySelectorAsync(selector);
|
|
||||||
await totpInput.TypeAsync(totpCode);
|
|
||||||
|
|
||||||
// Click Verify Button
|
|
||||||
selector = "body > banno-web > bannoweb-login > bannoweb-login-steps > bannoweb-two-factor-verify > jha-slider > jha-slider-content > jha-slider-pane:nth-child(4) > bannoweb-two-factor-enter-code > article > form > jha-button";
|
|
||||||
await page.WaitForSelectorAsync(selector).WaitAsync(timeout, _stoppingToken);
|
|
||||||
IElementHandle verifyButton = await page.QuerySelectorAsync(selector);
|
|
||||||
if (verifyButton != null)
|
|
||||||
{
|
|
||||||
await verifyButton.ClickAsync();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogError("Failed to find Verify button");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await page.WaitForSelectorAsync(DASHBOARD_SELECTOR).WaitAsync(timeout, _stoppingToken);
|
|
||||||
}
|
|
||||||
catch(TimeoutException)
|
|
||||||
{
|
|
||||||
_logger.LogWarning($"Dashboard isn't loading after login for user '{user.Id}'");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation($"Dashboard found for '{user.Id}'");
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (TaskCanceledException)
|
|
||||||
{
|
|
||||||
_logger.LogError($"Login Task for user '{user.Id}' was canceled");
|
|
||||||
}
|
|
||||||
catch (TimeoutException)
|
|
||||||
{
|
|
||||||
_logger.LogWarning($"Login Task timed out for user '{user.Id}' after {timeout} seconds");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
await page.CloseAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation($"Login completed for user {user.Id}");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<bool> IsLoggedIn(User user, IBrowser browser)
|
|
||||||
{
|
|
||||||
// Setup Page
|
|
||||||
await using IPage page = await browser.NewPageAsync();
|
|
||||||
await page.SetViewportAsync(new ViewPortOptions { Width = 1200, Height = 720 });
|
|
||||||
|
|
||||||
// Navigate to home screen
|
|
||||||
await page.GoToAsync(_config.SimmonsBankBaseUrl);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await page.WaitForSelectorAsync(DASHBOARD_SELECTOR).WaitAsync(TimeSpan.FromSeconds(_config.BrowserOperationTimeoutSeconds), _stoppingToken);
|
|
||||||
}
|
|
||||||
catch(TaskCanceledException)
|
|
||||||
{
|
|
||||||
_logger.LogWarning($"IsLoggedIn Task for user '{user.Id}' was canceled");
|
|
||||||
}
|
|
||||||
catch(TimeoutException)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,7 @@ internal class Program
|
|||||||
builder.Services.AddScoped<ITransactionService, TransactionService>();
|
builder.Services.AddScoped<ITransactionService, TransactionService>();
|
||||||
builder.Services.AddScoped<ICacheService, CacheService>();
|
builder.Services.AddScoped<ICacheService, CacheService>();
|
||||||
builder.Services.AddScoped<IVersionService, VersionService>();
|
builder.Services.AddScoped<IVersionService, VersionService>();
|
||||||
|
builder.Services.AddScoped<IPuppeteerService, PuppeteerService>();
|
||||||
|
|
||||||
builder.Services.AddScoped<ApiKeyAuthenticationHandler>();
|
builder.Services.AddScoped<ApiKeyAuthenticationHandler>();
|
||||||
|
|
||||||
|
234
AAIntegration.SimmonsBank.API/Services/PuppeteerService.cs
Normal file
234
AAIntegration.SimmonsBank.API/Services/PuppeteerService.cs
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
namespace AAIntegration.SimmonsBank.API.Services;
|
||||||
|
|
||||||
|
using AutoMapper;
|
||||||
|
using BCrypt.Net;
|
||||||
|
using AAIntegration.SimmonsBank.API.Entities;
|
||||||
|
using AAIntegration.SimmonsBank.API.Config;
|
||||||
|
using AAIntegration.SimmonsBank.API.Models.Users;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Internal;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using System.Text;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using PuppeteerSharp;
|
||||||
|
using AAIntegration.SimmonsBank.API.Configs;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using OtpNet;
|
||||||
|
|
||||||
|
public interface IPuppeteerService
|
||||||
|
{
|
||||||
|
Task<bool> Login(User user, CancellationToken cancellationToken);
|
||||||
|
Task<bool> IsLoggedIn(User user, CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PuppeteerService : IPuppeteerService
|
||||||
|
{
|
||||||
|
private const string DASHBOARD_SELECTOR = "body > banno-web > bannoweb-layout > bannoweb-dashboard";
|
||||||
|
private readonly PuppeteerConfig _config;
|
||||||
|
private readonly ILogger<PuppeteerService> _logger;
|
||||||
|
private readonly IMemoryCache _memoryCache;
|
||||||
|
private DataContext _context;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
private readonly IOptions<AppSettings> _appSettings;
|
||||||
|
|
||||||
|
public PuppeteerService(
|
||||||
|
IOptions<PuppeteerConfig> config,
|
||||||
|
ILogger<PuppeteerService> logger,
|
||||||
|
IMemoryCache memoryCache,
|
||||||
|
DataContext context,
|
||||||
|
IMapper mapper,
|
||||||
|
IOptions<AppSettings> appSettings)
|
||||||
|
{
|
||||||
|
_config = config.Value;
|
||||||
|
_logger = logger;
|
||||||
|
_memoryCache = memoryCache;
|
||||||
|
_context = context;
|
||||||
|
_mapper = mapper;
|
||||||
|
_appSettings = appSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> Login(User user, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
TimeSpan timeout = TimeSpan.FromSeconds(_config.BrowserOperationTimeoutSeconds);
|
||||||
|
|
||||||
|
// Setup Page
|
||||||
|
IBrowser browser = await GetUserBrowserAsync(user, cancellationToken);
|
||||||
|
await using IPage page = await browser.NewPageAsync();
|
||||||
|
await page.SetViewportAsync(new ViewPortOptions { Width = 1200, Height = 720 });
|
||||||
|
WaitUntilNavigation[] waitUntils = { WaitUntilNavigation.Networkidle0 };
|
||||||
|
|
||||||
|
// Navigate to login screen
|
||||||
|
await page.GoToAsync(_config.SimmonsBankBaseUrl + "/login");//, null, waitUntils); // wait until page load
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Type username
|
||||||
|
string selector = "#username";
|
||||||
|
await page.WaitForSelectorAsync(selector).WaitAsync(timeout, cancellationToken);
|
||||||
|
await page.TypeAsync(selector, user.SimmonsBankUsername);
|
||||||
|
|
||||||
|
// Press 1st Submit Button
|
||||||
|
selector = "jha-button";
|
||||||
|
await page.WaitForSelectorAsync(selector).WaitAsync(timeout, cancellationToken);
|
||||||
|
await page.ClickAsync(selector);
|
||||||
|
|
||||||
|
// Type password
|
||||||
|
selector = "#password";
|
||||||
|
await page.WaitForSelectorAsync(selector).WaitAsync(timeout, cancellationToken);
|
||||||
|
await page.TypeAsync(selector, user.SimmonsBankPassword);
|
||||||
|
|
||||||
|
// Click SignIn button - In Chrome -> JS Path worked well
|
||||||
|
selector = "#login-password-form > bannoweb-flex-wrapper:nth-child(5) > div > jha-button";
|
||||||
|
await page.WaitForSelectorAsync(selector).WaitAsync(timeout, cancellationToken);
|
||||||
|
IElementHandle signInButton = await page.QuerySelectorAsync(selector);
|
||||||
|
|
||||||
|
if (signInButton != null)
|
||||||
|
{
|
||||||
|
await signInButton.ClickAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogError("Failed to find Sign-In button");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
await page.WaitForNetworkIdleAsync();
|
||||||
|
|
||||||
|
// Find TOTP input
|
||||||
|
selector = "body > banno-web > bannoweb-login > bannoweb-login-steps > bannoweb-two-factor-verify > jha-slider > jha-slider-content > jha-slider-pane:nth-child(4) > bannoweb-two-factor-enter-code > article > form > jha-form-floating-group > input[type=text]";
|
||||||
|
await page.WaitForSelectorAsync(selector).WaitAsync(timeout, cancellationToken);
|
||||||
|
//await Delay(150);
|
||||||
|
|
||||||
|
// Generate TOTP code
|
||||||
|
Totp totpInstance = new Totp(Base32Encoding.ToBytes(user.MFAKey));
|
||||||
|
string totpCode = totpInstance.ComputeTotp();
|
||||||
|
|
||||||
|
// Type TOTP code
|
||||||
|
IElementHandle totpInput = await page.QuerySelectorAsync(selector);
|
||||||
|
await totpInput.TypeAsync(totpCode);
|
||||||
|
|
||||||
|
// Click Verify Button
|
||||||
|
selector = "body > banno-web > bannoweb-login > bannoweb-login-steps > bannoweb-two-factor-verify > jha-slider > jha-slider-content > jha-slider-pane:nth-child(4) > bannoweb-two-factor-enter-code > article > form > jha-button";
|
||||||
|
await page.WaitForSelectorAsync(selector).WaitAsync(timeout, cancellationToken);
|
||||||
|
IElementHandle verifyButton = await page.QuerySelectorAsync(selector);
|
||||||
|
if (verifyButton != null)
|
||||||
|
{
|
||||||
|
await verifyButton.ClickAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogError("Failed to find Verify button");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await page.WaitForSelectorAsync(DASHBOARD_SELECTOR).WaitAsync(timeout, cancellationToken);
|
||||||
|
}
|
||||||
|
catch(TimeoutException)
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"Dashboard isn't loading after login for user '{user.Id}'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation($"Dashboard found for '{user.Id}'");
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (TaskCanceledException)
|
||||||
|
{
|
||||||
|
_logger.LogError($"Login Task for user '{user.Id}' was canceled");
|
||||||
|
}
|
||||||
|
catch (TimeoutException)
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"Login Task timed out for user '{user.Id}' after {timeout} seconds");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await page.CloseAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation($"Login completed for user {user.Id}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> IsLoggedIn(User user, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// Setup Page
|
||||||
|
IBrowser browser = await GetUserBrowserAsync(user, cancellationToken);
|
||||||
|
await using IPage page = await browser.NewPageAsync();
|
||||||
|
await page.SetViewportAsync(new ViewPortOptions { Width = 1200, Height = 720 });
|
||||||
|
|
||||||
|
// Navigate to home screen
|
||||||
|
await page.GoToAsync(_config.SimmonsBankBaseUrl);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await page.WaitForSelectorAsync(DASHBOARD_SELECTOR).WaitAsync(TimeSpan.FromSeconds(_config.BrowserOperationTimeoutSeconds), cancellationToken);
|
||||||
|
}
|
||||||
|
catch(TaskCanceledException)
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"IsLoggedIn Task for user '{user.Id}' was canceled");
|
||||||
|
}
|
||||||
|
catch(TimeoutException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper / Private Functions
|
||||||
|
|
||||||
|
/*private void SetUserSBId(User user)
|
||||||
|
{
|
||||||
|
if (_memoryCache.TryGetValue<Dictionary<int, string>>(PuppeteerConstants.USER_SB_ID, out var internalKeys))
|
||||||
|
{
|
||||||
|
List<KeyValuePair<int, IBrowser>> list = internalKeys.Where(x => x.Key == user.Id).ToList();
|
||||||
|
|
||||||
|
if (list.Count > 0 && list.First().Value != null)
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Found the browser for user with id '{user.Id}'.");
|
||||||
|
return list.First().Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
private async Task<IBrowser> GetUserBrowserAsync(User user, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (_memoryCache.TryGetValue<Dictionary<int, IBrowser>>(PuppeteerConstants.BROWSER_CACHE_KEY, out var internalKeys))
|
||||||
|
{
|
||||||
|
List<KeyValuePair<int, IBrowser>> list = internalKeys.Where(x => x.Key == user.Id).ToList();
|
||||||
|
|
||||||
|
if (list.Count > 0 && list.First().Value != null)
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Found the browser for user with id '{user.Id}'.");
|
||||||
|
return list.First().Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation($"Could NOT find the browser for user with id '{user.Id}'. About to create one...");
|
||||||
|
|
||||||
|
using var browserFetcher = new BrowserFetcher();
|
||||||
|
await browserFetcher.DownloadAsync().WaitAsync(TimeSpan.FromSeconds(_config.BrowserOperationTimeoutSeconds * 20), cancellationToken);
|
||||||
|
|
||||||
|
var options = new LaunchOptions {
|
||||||
|
Headless = false,
|
||||||
|
IgnoreHTTPSErrors = true
|
||||||
|
};
|
||||||
|
|
||||||
|
IBrowser browser = await Puppeteer.LaunchAsync(options).WaitAsync(TimeSpan.FromSeconds(_config.BrowserOperationTimeoutSeconds), cancellationToken);
|
||||||
|
|
||||||
|
internalKeys ??= new Dictionary<int, IBrowser>();
|
||||||
|
internalKeys.Add(user.Id, browser);
|
||||||
|
_memoryCache.Set(PuppeteerConstants.BROWSER_CACHE_KEY, internalKeys);
|
||||||
|
|
||||||
|
return browser;
|
||||||
|
}
|
||||||
|
}
|
@ -32,6 +32,7 @@ public class PuppeteerWorker : BackgroundService
|
|||||||
}
|
}
|
||||||
|
|
||||||
private IUserService _userService;
|
private IUserService _userService;
|
||||||
|
private IPuppeteerService _puppeteerService;
|
||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
@ -41,7 +42,9 @@ public class PuppeteerWorker : BackgroundService
|
|||||||
using (var scope = _serviceScopeFactory.CreateScope())
|
using (var scope = _serviceScopeFactory.CreateScope())
|
||||||
{
|
{
|
||||||
_userService = scope.ServiceProvider.GetService<IUserService>();
|
_userService = scope.ServiceProvider.GetService<IUserService>();
|
||||||
|
_puppeteerService = scope.ServiceProvider.GetService<IPuppeteerService>();
|
||||||
_puppeteerProcess.SetStoppingToken(stoppingToken);
|
_puppeteerProcess.SetStoppingToken(stoppingToken);
|
||||||
|
_puppeteerProcess.SetService(_puppeteerService);
|
||||||
|
|
||||||
// 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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user