private async Task InternalExposureDetectionAsync(CancellationTokenSource cancellationTokenSource = null) { bool isEnabled = await _exposureNotificationApiService.IsEnabledAsync(); if (!isEnabled) { _loggerService.Info($"EN API is not enabled."); return; } IEnumerable <int> statuseCodes = await _exposureNotificationApiService.GetStatusCodesAsync(); bool isActivated = statuseCodes.Contains(ExposureNotificationStatus.Code_Android.ACTIVATED) | statuseCodes.Contains(ExposureNotificationStatus.Code_iOS.Active); if (!isActivated) { _loggerService.Info($"EN API is not ACTIVATED."); return; } var cancellationToken = cancellationTokenSource?.Token ?? default(CancellationToken); await _serverConfigurationRepository.LoadAsync(); bool canConfirmExposure = true; bool isMaxPerDayExposureDetectionAPILimitReached = false; foreach (var region in _serverConfigurationRepository.Regions) { _loggerService.Info($"Region: {region}"); var diagnosisKeyListProvideServerUrl = _serverConfigurationRepository.GetDiagnosisKeyListProvideServerUrl(region); _loggerService.Info($"diagnosisKeyListProvideServerUrl: {diagnosisKeyListProvideServerUrl}"); List <string> downloadedFileNameList = new List <string>(); try { var tmpDir = PrepareDir(region); var(httpStatus, diagnosisKeyEntryList) = await _diagnosisKeyRepository.GetDiagnosisKeysListAsync( diagnosisKeyListProvideServerUrl, cancellationToken ); if (httpStatus != HttpStatusCode.OK) { _loggerService.Info($"URL: {diagnosisKeyListProvideServerUrl}, Response StatusCode: {httpStatus}"); canConfirmExposure = false; continue; } var lastProcessTimestamp = await _userDataRepository.GetLastProcessDiagnosisKeyTimestampAsync(region); _loggerService.Info($"Region: {region}, lastProcessTimestamp: {lastProcessTimestamp}"); var targetDiagnosisKeyEntryList = FilterDiagnosisKeysAfterLastProcessTimestamp(diagnosisKeyEntryList, lastProcessTimestamp); if (targetDiagnosisKeyEntryList.Count() == 0) { _loggerService.Info($"No new diagnosis-key found on {diagnosisKeyListProvideServerUrl}"); continue; } _loggerService.Info($"{targetDiagnosisKeyEntryList.Count()} new keys found."); foreach (var diagnosisKeyEntry in targetDiagnosisKeyEntryList) { string filePath = await _diagnosisKeyRepository.DownloadDiagnosisKeysAsync(diagnosisKeyEntry, tmpDir, cancellationToken); _loggerService.Info($"URL {diagnosisKeyEntry.Url} have been downloaded."); downloadedFileNameList.Add(filePath); } var downloadedFileNames = string.Join("\n", downloadedFileNameList); _loggerService.Debug(downloadedFileNames); await _exposureNotificationApiService.ProvideDiagnosisKeysAsync( downloadedFileNameList, cancellationTokenSource ); // Save LastProcessDiagnosisKeyTimestamp after ProvideDiagnosisKeysAsync was succeeded. var latestProcessTimestamp = targetDiagnosisKeyEntryList .Select(diagnosisKeyEntry => diagnosisKeyEntry.Created) .Max(); await _userDataRepository.SetLastProcessDiagnosisKeyTimestampAsync(region, latestProcessTimestamp); _userDataRepository.SetLastConfirmedDate(_dateTimeUtility.UtcNow); _userDataRepository.SetCanConfirmExposure(true); _userDataRepository.SetIsMaxPerDayExposureDetectionAPILimitReached(isMaxPerDayExposureDetectionAPILimitReached); } catch (ENException exception) { canConfirmExposure = false; isMaxPerDayExposureDetectionAPILimitReached = CheckMaxPerDayExposureDetectionAPILimitReached(exception); _loggerService.Exception($"ENExcepiton occurred, Code:{exception.Code}, Message:{exception.Message}", exception); throw; } catch (Exception exception) { canConfirmExposure = false; _loggerService.Exception($"Exception occurred: {region}", exception); throw; } finally { RemoveFiles(downloadedFileNameList); _userDataRepository.SetCanConfirmExposure(canConfirmExposure); _userDataRepository.SetIsMaxPerDayExposureDetectionAPILimitReached(isMaxPerDayExposureDetectionAPILimitReached); } } }