voidkitty/VoidCat/Services/Background/VirusScannerService.cs
2023-08-24 11:53:12 +01:00

68 lines
2.6 KiB
C#

using VoidCat.Model;
using VoidCat.Services.Abstractions;
using VoidCat.Services.VirusScanner.Exceptions;
namespace VoidCat.Services.Background;
public class VirusScannerService : BackgroundService
{
private readonly ILogger<VirusScannerService> _logger;
private readonly IVirusScanner _scanner;
private readonly IFileMetadataStore _fileStore;
private readonly IVirusScanStore _scanStore;
public VirusScannerService(ILogger<VirusScannerService> logger, IVirusScanner scanner, IVirusScanStore scanStore,
IFileMetadataStore fileStore)
{
_scanner = scanner;
_logger = logger;
_scanStore = scanStore;
_fileStore = fileStore;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Virus scanner background service starting..");
while (!stoppingToken.IsCancellationRequested)
{
var page = 0;
while (true)
{
var files = await _fileStore.ListFiles(new(page++, 1_000));
if (files.Results == 0) break;
await foreach (var file in files.Data.WithCancellation(stoppingToken))
{
// file is too large, cant scan
if (file.Size > 4_000_000) continue;
// check for scans
var scan = await _scanStore.GetByFile(file.Id);
if (scan == default || scan.ScanTime < DateTime.UtcNow.Subtract(TimeSpan.FromDays(30)))
{
try
{
var result = await _scanner.ScanFile(file.Id, stoppingToken);
await _scanStore.Add(result.Id, result);
_logger.LogInformation("Scanned file {Id}, IsVirus = {Result}", result.File, result.Score);
}
catch (RateLimitedException rx)
{
var sleep = rx.RetryAfter ?? DateTimeOffset.UtcNow.AddMinutes(10);
_logger.LogWarning("VirusScanner was rate limited, sleeping until {Time}", sleep);
await Task.Delay(sleep - DateTimeOffset.UtcNow, stoppingToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to scan file {Id} error={Message}", file.Id, ex.Message);
}
}
}
}
await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
}
}
}