/// <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;
                }
            }
        }
Beispiel #3
0
        /// <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));
        }