using System; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using EasyNetQ; using MalwareMultiScan.Backends.Interfaces; using MalwareMultiScan.Backends.Messages; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace MalwareMultiScan.Scanner.Services { internal class ScanHostedService : IHostedService { private readonly IScanBackend _backend; private readonly IConfiguration _configuration; private readonly ILogger _logger; private IBus _bus; public ScanHostedService(ILogger logger, IConfiguration configuration, IScanBackend backend) { _logger = logger; _configuration = configuration; _backend = backend; } public Task StartAsync(CancellationToken cancellationToken) { _bus = RabbitHutch.CreateBus( _configuration.GetConnectionString("RabbitMQ")); _bus.Receive(_backend.Id, Scan); _logger.LogInformation( $"Started scan hosting service for the backend {_backend.Id}"); return Task.CompletedTask; } public Task StopAsync(CancellationToken cancellationToken) { _bus.Dispose(); _logger.LogInformation( $"Stopped scan hosting service for the backend {_backend.Id}"); return Task.CompletedTask; } private async Task Scan(ScanRequestMessage message) { _logger.LogInformation( $"Starting scan of {message.Uri} via backend {_backend.Id} from {message.Id}"); var cancellationTokenSource = new CancellationTokenSource( TimeSpan.FromSeconds(_configuration.GetValue("MaxScanningTime"))); var result = new ScanResultMessage { Id = message.Id, Backend = _backend.Id }; var stopwatch = new Stopwatch(); stopwatch.Start(); try { result.Threats = await _backend.ScanAsync( message.Uri, cancellationTokenSource.Token); result.Succeeded = true; _logger.LogInformation( $"Backend {_backend.Id} completed a scan of {message.Id} " + $"with result '{string.Join(", ", result.Threats)}'"); } catch (Exception exception) { result.Succeeded = false; _logger.LogError( exception, "Scanning failed with exception"); } finally { stopwatch.Stop(); } result.Duration = stopwatch.ElapsedMilliseconds / 1000; _logger.LogInformation( $"Sending scan results with status {result.Succeeded}"); await _bus.SendAsync( _configuration.GetValue("ResultsSubscriptionId"), result); } } }