using System; using System.IO; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using MalwareMultiScan.Api.Data.Models; using Microsoft.Extensions.Logging; using MongoDB.Driver; using MongoDB.Driver.GridFS; namespace MalwareMultiScan.Api.Services { public class ScanRequestService { private const string CollectionName = "ScanRequests"; private readonly GridFSBucket _bucket; private readonly IMongoCollection _collection; private readonly BackendConfigurationReader _configurationReader; private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger _logger; public ScanRequestService(IMongoDatabase db, BackendConfigurationReader configurationReader, IHttpClientFactory httpClientFactory, ILogger logger) { _configurationReader = configurationReader; _httpClientFactory = httpClientFactory; _logger = logger; _bucket = new GridFSBucket(db); _collection = db.GetCollection(CollectionName); } private async Task QueueScans(string requestId, string fileName, Stream fileStream) { foreach (var backend in _configurationReader.Backends) { var cancellationTokenSource = new CancellationTokenSource( TimeSpan.FromSeconds(5)); using var httpClient = _httpClientFactory.CreateClient(); try { var endpointUri = new Uri( new Uri(backend.Endpoint), "/scan/file"); var formContent = new MultipartFormDataContent { {new StringContent("value1"), "callbackUrl"}, {new StreamContent(fileStream), "inputFile", fileName} }; var response = await httpClient.PostAsync( endpointUri, formContent, cancellationTokenSource.Token); response.EnsureSuccessStatusCode(); // TODO: update scan request } catch (Exception e) { _logger.LogError(e, $"Failed to queue scanning job on {backend.Id} ({backend.Endpoint})"); } } } public async Task InitializeNewRequest(string fileName, Stream fileStream, CancellationToken cancellationToken = default) { var fileId = await _bucket.UploadFromStreamAsync(fileName, fileStream, cancellationToken: cancellationToken); var scanRequest = new ScanRequest { FileId = fileId.ToString() }; await _collection.InsertOneAsync(scanRequest, new InsertOneOptions { BypassDocumentValidation = false }, cancellationToken); await QueueScans(scanRequest.Id, fileName, fileStream); return scanRequest.Id; } } }