/// <summary> /// Creates the metadata.txt file for a list of updates to export. /// Copies update IDs and XML data to this file /// </summary> /// <param name="updatesToExport">The updates to export</param> /// <param name="metadataTextFile">Destination metadata file</param> private void WriteMetadataFile(List <Update> updatesToExport, string metadataTextFile) { // Each line in the metadata text file contains multiple lines of the following format: // <update GUID>,<update revision>,<xml size>,<xml>\r\n // There is one line for each update exported // Open the metadata file for writing using (var metadataFile = File.CreateText(metadataTextFile)) { var allUpdates = new List <Update>(MetadataSource.GetCategories()); allUpdates.AddRange(updatesToExport); var progress = new OperationProgress() { CurrentOperation = OperationType.ExportUpdateXmlBlobProgress, Maximum = allUpdates.Count, Current = 0 }; foreach (var update in allUpdates) { using (var metadataStream = MetadataSource.GetUpdateMetadataStream(update.Identity)) { using (var metadataReader = new StreamReader(metadataStream)) { var xmlData = metadataReader.ReadToEnd(); // Write one line with GUID, revision, XML length, XML data metadataFile.WriteLine("{0},{1:x8},{2:x8},{3}", update.Identity.Raw.UpdateID, update.Identity.Raw.RevisionNumber, xmlData.Length, xmlData); } } progress.Current += 1; ExportProgress?.Invoke(this, progress); } } }
/// <summary> /// Loads extended attributes from XML. Classes that inherit should provide an implementation. /// </summary> internal virtual void LoadAttributesFromMetadataSource() { lock (this) { if (!AttributesLoaded) { using (var metadataStream = MetadataSource.GetUpdateMetadataStream(Identity)) using (var metadataReader = new StreamReader(metadataStream)) { var xdoc = XDocument.Parse(metadataReader.ReadToEnd(), LoadOptions.None); GetDescriptionFromXml(xdoc); } AttributesLoaded = true; } } }
/// <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)); }