private string GenerateSubpath(FileReleaseData fileToRelease)
        {
            var fi = new FileInfo(fileToRelease.FileMap.LocalSourcePath);

            using var hash = System.Security.Cryptography.SHA256.Create();
            var enc = System.Text.Encoding.UTF8;

            byte[] hashResult = hash.ComputeHash(enc.GetBytes(fileToRelease.FileMap.RelativeOutputPath));
            string pathHash   = BitConverter.ToString(hashResult).Replace("-", String.Empty);

            return($"{_productReleaseMetadata.ReleaseVersion}/{pathHash}/{fi.Name}");
        }
        private string GenerateLinkFromMetadata(FileReleaseData fileToRelease, string linkSchema)
        {
            var    fi   = new FileInfo(fileToRelease.FileMap.LocalSourcePath);
            string link = linkSchema;
            //TODO: Revisit for perf if necessary...
            MatchCollection results = s_akaMsMetadataMatcher.Matches(linkSchema);

            foreach (Match match in results)
            {
                if (!match.Groups.TryGetValue("metadata", out Group metadataGroup))
                {
                    // Give up if the capturing failed
                    return(null);
                }

                string metadataValue = metadataGroup.Value switch {
                    "FileName" => fi.Name,
                    "FileNameNoExt" => Path.GetFileNameWithoutExtension(fi.Name),
                    "Rid" => fileToRelease.FileMetadata.Rid,
                    "Sha512" => fileToRelease.FileMetadata.Sha512,
                    "AssetCategory" => fileToRelease.FileMetadata.AssetCategory,
                    _ => null
                };

                if (string.IsNullOrEmpty(metadataValue))
                {
                    _logger.LogWarning("Can't replace metadata {metadataGroup.Value} for {fileToRelease.FileMap.LocalSourcePath}",
                                       metadataGroup.Value, fileToRelease.FileMap.LocalSourcePath);
                    return(null);
                }
                else
                {
                    link = link.Replace($"<{metadataGroup.Value}>", metadataValue);
                }
            }

            if (Uri.TryCreate(link, UriKind.Absolute, out Uri uriResult) &&
                (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps))
            {
                return(link);
            }

            return(null);
        }
        private FileWithCdnData GetFileWithCdnData(FileReleaseData fileToRelease)
        {
            bool categoryHasData = _assetManifestManifestDom.RootElement.TryGetProperty(
                fileToRelease.FileMetadata.AssetCategory,
                out JsonElement dataForCategory);

            string akaLink = null;

            if (categoryHasData && dataForCategory.TryGetProperty("AkaMsSchema", out JsonElement linkSchema))
            {
                akaLink = GenerateLinkFromMetadata(fileToRelease, linkSchema.GetString());
            }

            string subPath = GenerateSubpath(fileToRelease);

            return(new FileWithCdnData(
                       filePath: fileToRelease.PublishUri,
                       sha512: fileToRelease.FileMetadata.Sha512,
                       publishUrlSubPath: subPath,
                       akaMsLink: akaLink,
                       comment: null
                       ));
        }