using System; using System.IO; using System.Linq; using System.Threading.Tasks; using Consul; using Hangfire; using Hangfire.States; using MalwareMultiScan.Api.Data; using MalwareMultiScan.Api.Services.Interfaces; using MalwareMultiScan.Shared.Enums; using MalwareMultiScan.Shared.Message; using MalwareMultiScan.Shared.Services.Interfaces; using MongoDB.Bson; using MongoDB.Driver; using MongoDB.Driver.GridFS; namespace MalwareMultiScan.Api.Services { /// public class ScanResultService : IScanResultService { private const string CollectionName = "ScanResults"; private readonly IBackgroundJobClient _backgroundJobClient; private readonly IGridFSBucket _bucket; private readonly IMongoCollection _collection; private readonly IConsulClient _consulClient; /// /// Initialize scan result service. /// /// Mongo database. /// GridFS bucket. /// Consul client. /// Background job client. public ScanResultService( IMongoDatabase db, IGridFSBucket bucket, IConsulClient consulClient, IBackgroundJobClient backgroundJobClient) { _bucket = bucket; _consulClient = consulClient; _backgroundJobClient = backgroundJobClient; _collection = db.GetCollection(CollectionName); } /// public async Task CreateScanResult(Uri callbackUrl) { var scanResult = new ScanResult { CallbackUrl = callbackUrl }; await _collection.InsertOneAsync(scanResult); return scanResult; } /// public async Task GetScanResult(string id) { var result = await _collection.FindAsync( Builders.Filter.Where(r => r.Id == id)); return await result.FirstOrDefaultAsync(); } /// public async Task UpdateScanResultForBackend(string resultId, string backendId, ScanResultMessage result = null) { result ??= new ScanResultMessage { Status = ScanResultStatus.Queued }; await _collection.UpdateOneAsync( Builders.Filter.Where(r => r.Id == resultId), Builders.Update.Set(r => r.Results[backendId], result)); } /// public async Task QueueUrlScan(ScanResult result, string fileUrl) { var message = new ScanQueueMessage { Id = result.Id, Uri = new Uri(fileUrl) }; var scanners = await _consulClient.Health.Service("scanner", null, true); var backends = scanners.Response .Select(s => s.Service.Meta.TryGetValue("BackendId", out var backendId) ? backendId : null) .Where(q => q != null) .Distinct() .ToArray(); foreach (var backend in backends) { await UpdateScanResultForBackend(result.Id, backend); _backgroundJobClient.Create( j => j.Process(message), new EnqueuedState(backend)); } } /// public async Task StoreFile(string fileName, Stream fileStream) { var objectId = await _bucket.UploadFromStreamAsync( fileName, fileStream); return objectId.ToString(); } /// public async Task ObtainFile(string id) { if (!ObjectId.TryParse(id, out var objectId)) return null; try { return await _bucket.OpenDownloadStreamAsync(objectId, new GridFSDownloadOptions { Seekable = true }); } catch (GridFSFileNotFoundException) { return null; } } } }