/// <summary> /// Retrieves update data for the list of update ids /// </summary> /// <param name="updateIds">The ids to retrieve data for</param> /// <param name="destination">The metadata destination to write update metadata to</param> private void GetUpdateDataForIds(List <UpdateIdentity> updateIds, IMetadataSink destination) { // Data retrieval is done is done in batches of upto MaxNumberOfUpdatesPerRequest var retrieveBatches = CreateBatchedListFromFlatList(updateIds, ConfigData.MaxNumberOfUpdatesPerRequest); // Progress tracking and reporting int batchesDone = 0; var progress = new MetadataQueryProgress() { CurrentTask = MetadataQueryStage.GetUpdateMetadataProgress, Maximum = updateIds.Count, Current = 0 }; MetadataQueryProgress?.Invoke(this, progress); // Run batches in parallel retrieveBatches.AsParallel().ForAll(batch => { var updateDataRequest = new GetUpdateDataRequest(); updateDataRequest.GetUpdateData = new GetUpdateDataRequestBody(); updateDataRequest.GetUpdateData.cookie = AccessToken.AccessCookie; updateDataRequest.GetUpdateData.updateIds = batch; GetUpdateDataResponse updateDataReply; int retryCount = 0; do { try { updateDataReply = ServerSyncClient.GetUpdateDataAsync(updateDataRequest).GetAwaiter().GetResult(); } catch (System.TimeoutException) { updateDataReply = null; } retryCount++; } while (updateDataReply == null && retryCount < 10); if (updateDataReply == null || updateDataReply.GetUpdateDataResponse1 == null || updateDataReply.GetUpdateDataResponse1.GetUpdateDataResult == null) { throw new Exception("Failed to get update metadata"); } // Parse the list of raw files into a more usable format var filesList = new List <UpdateFileUrl>(updateDataReply.GetUpdateDataResponse1.GetUpdateDataResult.fileUrls.Select(rawFile => new UpdateFileUrl(rawFile))); // First add the files information to the store; it will be used to link update files with urls later filesList.ForEach(file => destination.AddFile(file)); // Add the updates to the result, converting them to a higher level representation destination.AddUpdates(updateDataReply.GetUpdateDataResponse1.GetUpdateDataResult.updates); lock (destination) { // Track progress batchesDone++; progress.PercentDone = ((double)batchesDone * 100) / retrieveBatches.Count; progress.Current += batch.Count(); MetadataQueryProgress?.Invoke(this, progress); } }); }
/// <summary> /// Return metadata for updates /// </summary> /// <param name="request">The request; contains IDs for updates to retrieve metadata for</param> /// <returns>Update metadata for requested updates</returns> public Task <ServerUpdateData> GetUpdateDataAsync(GetUpdateDataRequest request) { var response = new ServerUpdateData(); // Make sure the request is not larger than the config says var updateRequestCount = request.GetUpdateData.updateIds.Count(); if (updateRequestCount > ServiceConfiguration.MaxNumberOfUpdatesPerRequest) { return(null); } var returnUpdatesList = new List <ServerSyncUpdateData>(); var returnFilesList = new List <ServerSyncUrlData>(); foreach (var rawIdentity in request.GetUpdateData.updateIds) { var updateIdentity = new Identity(rawIdentity); // Find the update; it can be either category or update Update update; if (!FilteredUpdates.TryGetValue(updateIdentity, out update)) { if ((update = Categories.First(c => c.Identity.Equals(updateIdentity))) == null) { throw new Exception("Update not found"); } } if (update.HasFiles) { // if update contains files, we must also gather file information foreach (var updateFile in update.Files) { returnFilesList.Add( new ServerSyncUrlData() { FileDigest = Convert.FromBase64String(updateFile.Digests[0].DigestBase64), MUUrl = updateFile.Urls[0].MuUrl, UssUrl = $"Content/{updateFile.GetContentDirectoryName()}/{updateFile.FileName}" }); } } var rawUpdateData = new ServerSyncUpdateData(); rawUpdateData.Id = rawIdentity; using (var metadataReader = new StreamReader(MetadataSource.GetUpdateMetadataStream(update.Identity))) { rawUpdateData.XmlUpdateBlob = metadataReader.ReadToEnd(); } returnUpdatesList.Add(rawUpdateData); } response.updates = returnUpdatesList.ToArray(); // Deduplicate list of files response.fileUrls = returnFilesList.GroupBy(f => f.MUUrl).Select(k => k.First()).ToArray(); return(Task.FromResult(response)); }