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;
            }
        }
Beispiel #2
0
        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);
                }
            }
        }