// Tells the local API when new diagnosis keys have been obtained from the server
        static async Task <(ExposureDetectionSummary, IEnumerable <ExposureInfo>)> PlatformDetectExposuresAsync(IEnumerable <string> keyFiles)
        {
            // Submit to the API
            var c = await GetConfigurationAsync();

            var m = await GetManagerAsync();

            var detectionSummary = await m.DetectExposuresAsync(
                c,
                keyFiles.Select(k => new NSUrl(k, false)).ToArray());

            var summary = new ExposureDetectionSummary(
                (int)detectionSummary.DaysSinceLastExposure,
                detectionSummary.MatchedKeyCount,
                detectionSummary.MaximumRiskScore);

            // Get the info
            IEnumerable <ExposureInfo> info = Array.Empty <ExposureInfo>();

            if (summary?.MatchedKeyCount > 0)
            {
                var exposures = await m.GetExposureInfoAsync(detectionSummary, Handler.UserExplanation);

                info = exposures.Select(i => new ExposureInfo(
                                            ((DateTime)i.Date).ToLocalTime(),
                                            TimeSpan.FromMinutes(i.Duration),
                                            i.AttenuationValue,
                                            i.TotalRiskScore,
                                            i.TransmissionRiskLevel.FromNative()));
            }

            // Return everything
            return(summary, info);
        }
Example #2
0
        // Tells the local API when new diagnosis keys have been obtained from the server
        static async Task <(ExposureDetectionSummary, Func <Task <IEnumerable <ExposureInfo> > >)> PlatformDetectExposuresAsync(IEnumerable <string> keyFiles, CancellationToken cancellationToken)
        {
            // Submit to the API
            var c = await GetConfigurationAsync();

            var m = await GetManagerAsync();

            // Extract all the files from the zips
            var allFiles = new List <string>();

            foreach (var file in keyFiles)
            {
                using var stream  = File.OpenRead(file);
                using var archive = new ZipArchive(stream, ZipArchiveMode.Read);

                // .bin
                var binTmp = Path.Combine(FileSystem.CacheDirectory, Guid.NewGuid().ToString() + ".bin");
                using (var binWrite = File.Create(binTmp))
                {
                    var bin = archive.GetEntry("export.bin");
                    using var binRead = bin.Open();
                    await binRead.CopyToAsync(binWrite);
                }
                allFiles.Add(binTmp);

                // .sig
                var sigTmp = Path.ChangeExtension(binTmp, ".sig");
                using (var sigWrite = File.Create(sigTmp))
                {
                    var sig = archive.GetEntry("export.sig");
                    using var sigRead = sig.Open();
                    await sigRead.CopyToAsync(sigWrite);
                }
                allFiles.Add(sigTmp);
            }

            // Start the detection
            var detectionSummaryTask = m.DetectExposuresAsync(
                c,
                allFiles.Select(k => new NSUrl(k, false)).ToArray(),
                out var detectProgress);

            cancellationToken.Register(detectProgress.Cancel);
            var detectionSummary = await detectionSummaryTask;

            // Delete all the extracted files
            foreach (var file in allFiles)
            {
                try
                {
                    File.Delete(file);
                }
                catch
                {
                    // no-op
                }
            }

            var attDurTs = new List <TimeSpan>();
            var dictKey  = new NSString("attenuationDurations");

            if (detectionSummary.Metadata.ContainsKey(dictKey))
            {
                var attDur = detectionSummary.Metadata.ObjectForKey(dictKey) as NSArray;

                for (nuint i = 0; i < attDur.Count; i++)
                {
                    attDurTs.Add(TimeSpan.FromSeconds(attDur.GetItem <NSNumber>(i).Int32Value));
                }
            }

            var sumRisk = 0;

            dictKey = new NSString("riskScoreSumFullRange");
            if (detectionSummary.Metadata.ContainsKey(dictKey))
            {
                var sro = detectionSummary.Metadata.ObjectForKey(dictKey);
                if (sro is NSNumber sron)
                {
                    sumRisk = sron.Int32Value;
                }
            }

            var maxRisk = 0;

            dictKey = new NSString("maximumRiskScoreFullRange");
            if (detectionSummary.Metadata.ContainsKey(dictKey))
            {
                var sro = detectionSummary.Metadata.ObjectForKey(dictKey);
                if (sro is NSNumber sron)
                {
                    maxRisk = sron.Int32Value;
                }
            }
            else
            {
                maxRisk = detectionSummary.MaximumRiskScore;
            }

            var summary = new ExposureDetectionSummary(
                (int)detectionSummary.DaysSinceLastExposure,
                detectionSummary.MatchedKeyCount,
                maxRisk,
                attDurTs.ToArray(),
                sumRisk);

            async Task <IEnumerable <ExposureInfo> > GetInfo()
            {
                // Get the info
                IEnumerable <ExposureInfo> info = Array.Empty <ExposureInfo>();

                if (summary?.MatchedKeyCount > 0)
                {
                    var exposures = await m.GetExposureInfoAsync(detectionSummary, Handler.UserExplanation, out var exposuresProgress);

                    cancellationToken.Register(exposuresProgress.Cancel);
                    info = exposures.Select(i =>
                    {
                        var totalRisk = 0;
                        var dictKey   = new NSString("totalRiskScoreFullRange");
                        if (i.Metadata.ContainsKey(dictKey))
                        {
                            var sro = i.Metadata.ObjectForKey(dictKey);
                            if (sro is NSNumber sron)
                            {
                                totalRisk = sron.Int32Value;
                            }
                        }
                        else
                        {
                            totalRisk = i.TotalRiskScore;
                        }

                        return(new ExposureInfo(
                                   (DateTime)i.Date,
                                   TimeSpan.FromMinutes(i.Duration),
                                   i.AttenuationValue,
                                   totalRisk,
                                   i.TransmissionRiskLevel.FromNative()));
                    });
                }
                return(info);
            }

            // Return everything
            return(summary, GetInfo);
        }