public async Task <HttpGetIksSuccessResult> ExecuteAsync(DateTime date, string batchTag) { _logger.WriteRequestingData(date, batchTag); var uri = new Uri($"{_efgsConfig.BaseUrl}/diagnosiskeys/download/{date:yyyy-MM-dd}"); try { // Configure authentication certificate using var clientCert = _certificateProvider.GetCertificate(); using var clientHandler = new HttpClientHandler { ClientCertificateOptions = ClientCertificateOption.Manual }; // Provide the authentication certificate manually clientHandler.ClientCertificates.Clear(); clientHandler.ClientCertificates.Add(clientCert); // Build the request var request = new HttpRequestMessage { RequestUri = uri }; request.Headers.Add("Accept", ApplicationProtobuf); if (!string.IsNullOrWhiteSpace(batchTag)) { request.Headers.Add("batchTag", batchTag); } if (_efgsConfig.SendClientAuthenticationHeaders) { request.Headers.Add("X-SSL-Client-SHA256", clientCert.ComputeSha256Hash()); request.Headers.Add("X-SSL-Client-DN", clientCert.Subject.Replace(" ", string.Empty)); } using var client = new HttpClient(clientHandler); _logger.WriteRequest(request); var response = await client.SendAsync(request); _logger.WriteResponse(response.StatusCode); _logger.WriteResponseHeaders(response.Headers); // Handle response switch (response.StatusCode) { case HttpStatusCode.OK: // EFGS returns the string 'null' if there is no batch tag. We will represent this with an actual null. var nextBatchTag = response.Headers.SafeGetValue("nextBatchTag"); nextBatchTag = nextBatchTag == "null" ? null : nextBatchTag; return(new HttpGetIksSuccessResult { //TODO errors if info not present BatchTag = response.Headers.SafeGetValue("batchTag"), NextBatchTag = nextBatchTag, Content = await response.Content.ReadAsByteArrayAsync() }); case HttpStatusCode.NotFound: _logger.WriteResponseNotFound(); return(null); case HttpStatusCode.Gone: _logger.WriteResponseGone(); return(null); case HttpStatusCode.BadRequest: _logger.WriteResponseBadRequest(); throw new EfgsCommunicationException(); case HttpStatusCode.Forbidden: _logger.WriteResponseForbidden(); throw new EfgsCommunicationException(); case HttpStatusCode.NotAcceptable: _logger.WriteResponseNotAcceptable(); throw new EfgsCommunicationException(); default: _logger.WriteResponseUndefined(response.StatusCode); throw new EfgsCommunicationException(); } } catch (Exception e) { _logger.WriteEfgsError(e); throw; } }
public async Task ExecuteAsync() { var jobInfo = GetJobInfo(); var downloadCount = 0; var lastWrittenBatchTag = jobInfo.LastBatchTag; // Set date to a default of today. // Either we continue where we left off, or we grab as many batches as allowed // (i.e., a few days worth back from today) var date = _dateTimeProvider.Snapshot.Date; var batchTagDatePart = lastWrittenBatchTag.Split("-").FirstOrDefault(); if (!string.IsNullOrEmpty(batchTagDatePart)) { // All is good, start requesting batch from where we left off. // The date and the batchTag's creation date need to be the same, // otherwise EFGS will return a HTTP status 404. date = DateTime.ParseExact(batchTagDatePart, "yyyyMMdd", null); } else { // If lastWrittenBatchTag is somehow unusable or unavailable, // go as far back as allowed and don't send a batchTag to EFGS. date = date.AddDays(_efgsConfig.DaysToDownload * -1); lastWrittenBatchTag = string.Empty; } // If we have a batchTag, we will re-request that batch from EFGS to start our run. // If we do not have a batchTag (it is null or empty), the first batch of the date requested will be returned by EFGS. // We may already have some of that requested date's batches, // but we may not have all its batches or batches from the subsequent days. var result = await _receiverFactory().ExecuteAsync(date, lastWrittenBatchTag); downloadCount++; while (result != null && downloadCount <= _efgsConfig.MaxBatchesPerRun) { // If we haven't already received the current batchTag, process it if (!_iksInDbContext.Received.Any(x => x.BatchTag == result.BatchTag)) { _logger.WriteProcessingData(date, result.BatchTag); try { await WriteSingleBatchAsync(result.BatchTag, result.Content); lastWrittenBatchTag = result.BatchTag; await UpdateJobInfoAsync(jobInfo, lastWrittenBatchTag); } catch (Exception e) { _logger.WriteEfgsError(e); } } else { _logger.WriteBatchAlreadyProcessed(result.BatchTag); } // Move on to the next batchTag if (!string.IsNullOrEmpty(result.NextBatchTag)) { _logger.WriteNextBatchFound(result.NextBatchTag); _logger.WriteBatchProcessedInNextLoop(result.NextBatchTag); result = await _receiverFactory().ExecuteAsync(date, result.NextBatchTag); downloadCount++; } else { // No next batch available, we're done for lastWrittenBatchTag's day's set of batches. _logger.WriteNoNextBatch(); // Check if we can move on to a possible next day's worth of batches, // now that this current set of batches is finished. // Don't move past today though :) if (date < _dateTimeProvider.Snapshot.Date) { _logger.WriteMovingToNextDay(); date = date.AddDays(1); result = await _receiverFactory().ExecuteAsync(date, string.Empty); downloadCount++; } else { // No more days with batches available, we're done. _logger.WriteNoNextBatchNoMoreDays(); result = null; } } // Log this for informational purposes if (downloadCount > _efgsConfig.MaxBatchesPerRun) { _logger.WriteBatchMaximumReached(_efgsConfig.MaxBatchesPerRun); } } }