public override async Task <TimeStampFeedEntries> GetTimeStampServers(CancellationToken cancellationToken = default) { // The following code makes sure that the list of servers is shown in a random order (not to prefer any specific server). var originalList = await base.GetTimeStampServers(cancellationToken).ConfigureAwait(false); if (originalList?.Servers?.Any() != true) { return(originalList); } Logger.Debug("Randomizing the list of timestamp servers..."); var randomList = new TimeStampFeedEntries { Servers = new List <TimeStampServerEntry>() }; var rnd = new Random(); while (originalList.Servers.Any()) { var randomElement = rnd.Next(0, originalList.Servers.Count); randomList.Servers.Add(originalList.Servers[randomElement]); originalList.Servers.RemoveAt(randomElement); } return(randomList); }
public override async Task <TimeStampFeedEntries> GetTimeStampServers(CancellationToken cancellationToken = default) { Logger.Debug("Getting exclusive lock for cached read operation..."); var gotLock = this.syncObject.WaitOne(TimeSpan.FromSeconds(10)); try { if (!gotLock) { Logger.Debug("Could not get an exclusive lock in 10 seconds, aborting..."); return(new TimeStampFeedEntries()); } if (this.cache?.Servers != null) { if (this.lastRead > DateTime.Now.Subtract(this.invalidateAfter)) { Logger.Debug($"Returning the cached copy of servers (last modification {this.lastRead}) which is not older than {this.invalidateAfter} ago..."); return(this.cache); } Logger.Debug($"Invalidating the cached copy of servers (last modification {this.lastRead}) which was older than {this.invalidateAfter} ago..."); this.cache = null; this.lastRead = DateTime.MinValue; } var file = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.DoNotVerify), "msix-hero", "timestamps.json"); bool commit; if (File.Exists(file)) { var lastDate = File.GetLastWriteTimeUtc(file); if (lastDate > DateTime.UtcNow.Subtract(this.invalidateAfter)) { Logger.Debug($"Returning the local copy of servers from file {file} (last modification {lastDate}) which is not older than {this.invalidateAfter} ago..."); // the file is in accepted date range, so we can deserialize it and return the results await using var fs = await this.OpenStream(cancellationToken).ConfigureAwait(false); this.cache = await this.GetTimeStampServers(fs, cancellationToken).ConfigureAwait(false); commit = false; } else { Logger.Debug($"Invalidating the cached copy of servers from file {file} (last modification {lastDate}) which is older than {this.invalidateAfter} ago..."); this.cache = await this.decoratedFeed.GetTimeStampServers(cancellationToken).ConfigureAwait(false); this.lastRead = DateTime.UtcNow; Logger.Info($"New last read date is {this.lastRead}."); commit = true; } } else { Logger.Debug("There is no cached copy available, getting the list from the actual provider..."); this.cache = await this.decoratedFeed.GetTimeStampServers(cancellationToken).ConfigureAwait(false); this.lastRead = DateTime.UtcNow; Logger.Info($"New last read date is {this.lastRead}."); commit = true; } if (commit) { var fileInfo = new FileInfo(file); if (fileInfo.Exists) { Logger.Info($"Deleting existing cached copy {fileInfo.FullName}..."); fileInfo.Delete(); } else if (fileInfo.Directory?.Exists == false) { Logger.Info($"Creating directory {fileInfo.Directory.FullName}..."); fileInfo.Directory.Create(); } Logger.Debug($"Serializing cached entries into JSON format..."); var jsonString = JsonConvert.SerializeObject(this.cache, Formatting.Indented); Logger.Debug($"Writing cached entries in JSON format into {fileInfo.FullName}..."); await File.WriteAllTextAsync(fileInfo.FullName, jsonString, cancellationToken).ConfigureAwait(false); } return(this.cache); } finally { if (gotLock) { Logger.Debug("Returning from exclusive lock..."); this.syncObject.Set(); } } }