示例#1
0
        public async Task PushesVerifiedPackagesData()
        {
            HashSet <string> data            = null;
            IAccessCondition accessCondition = null;

            _verifiedPackagesDataClient
            .Setup(x => x.ReplaceLatestAsync(It.IsAny <HashSet <string> >(), It.IsAny <IAccessCondition>()))
            .Returns(Task.CompletedTask)
            .Callback <HashSet <string>, IAccessCondition>((d, a) =>
            {
                data            = d;
                accessCondition = a;
            });

            await _target.ExecuteAsync();

            Assert.Same(_initialAuxiliaryData.VerifiedPackages, data);

            Assert.Equal("*", accessCondition.IfNoneMatchETag);
            Assert.Null(accessCondition.IfMatchETag);

            _verifiedPackagesDataClient.Verify(
                x => x.ReplaceLatestAsync(It.IsAny <HashSet <string> >(), It.IsAny <IAccessCondition>()),
                Times.Once);
        }
示例#2
0
        public async Task ReplaceAsync(string id, VersionListData data, IAccessCondition accessCondition)
        {
            using (var stream = new MemoryStream())
            {
                using (var streamWriter = new StreamWriter(
                           stream,
                           encoding: new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true),
                           bufferSize: 1024,
                           leaveOpen: true))
                    using (var jsonTextWriter = new JsonTextWriter(streamWriter))
                    {
                        Serializer.Serialize(jsonTextWriter, data);
                    }

                stream.Position = 0;

                _logger.LogInformation("Replacing the version list for package ID {PackageId}.", id);

                var mappedAccessCondition = new AccessCondition
                {
                    IfNoneMatchETag = accessCondition.IfNoneMatchETag,
                    IfMatchETag     = accessCondition.IfMatchETag,
                };

                var blobReference = Container.GetBlobReference(GetFileName(id));
                blobReference.Properties.ContentType = "application/json";

                await blobReference.UploadFromStreamAsync(
                    stream,
                    mappedAccessCondition);
            }
        }
示例#3
0
        public async Task PushesPopularityTransferData()
        {
            PopularityTransferData data            = null;
            IAccessCondition       accessCondition = null;

            _popularityTransferDataClient
            .Setup(x => x.ReplaceLatestIndexedAsync(It.IsAny <PopularityTransferData>(), It.IsAny <IAccessCondition>()))
            .Returns(Task.CompletedTask)
            .Callback <PopularityTransferData, IAccessCondition>((d, a) =>
            {
                data            = d;
                accessCondition = a;
            });

            await _target.ExecuteAsync();

            Assert.Same(_initialAuxiliaryData.PopularityTransfers, data);

            Assert.Equal("*", accessCondition.IfNoneMatchETag);
            Assert.Null(accessCondition.IfMatchETag);

            _popularityTransferDataClient.Verify(
                x => x.ReplaceLatestIndexedAsync(It.IsAny <PopularityTransferData>(), It.IsAny <IAccessCondition>()),
                Times.Once);
        }
 public Task CopyFileAsync(Uri srcUri, string destFolderName, string destFileName,
                           IAccessCondition destAccessCondition)
 {
     // We could theoretically support this by downloading the source URI to the destination path. This is not
     // needed today so this method will remain unimplemented until it is needed.
     throw new NotImplementedException();
 }
示例#5
0
        public async Task PushesOwnerData()
        {
            SortedDictionary <string, SortedSet <string> > data = null;
            IAccessCondition accessCondition = null;

            _ownerDataClient
            .Setup(x => x.ReplaceLatestIndexedAsync(It.IsAny <SortedDictionary <string, SortedSet <string> > >(), It.IsAny <IAccessCondition>()))
            .Returns(Task.CompletedTask)
            .Callback <SortedDictionary <string, SortedSet <string> >, IAccessCondition>((d, a) =>
            {
                data            = d;
                accessCondition = a;
            });

            await _target.ExecuteAsync();

            Assert.Same(_initialAuxiliaryData.Owners, data);

            Assert.Equal("*", accessCondition.IfNoneMatchETag);
            Assert.Null(accessCondition.IfMatchETag);

            _ownerDataClient.Verify(
                x => x.ReplaceLatestIndexedAsync(It.IsAny <SortedDictionary <string, SortedSet <string> > >(), It.IsAny <IAccessCondition>()),
                Times.Once);
        }
示例#6
0
        public async Task ReplaceLatestIndexedAsync(
            PopularityTransferData newData,
            IAccessCondition accessCondition)
        {
            using (_telemetryService.TrackReplaceLatestIndexedPopularityTransfers(newData.Count))
            {
                var blobName = GetLatestIndexedBlobName();
                _logger.LogInformation("Replacing the latest indexed popularity transfers from {BlobName}.", blobName);

                var mappedAccessCondition = new AccessCondition
                {
                    IfNoneMatchETag = accessCondition.IfNoneMatchETag,
                    IfMatchETag     = accessCondition.IfMatchETag,
                };

                var blobReference = Container.GetBlobReference(blobName);

                using (var stream = await blobReference.OpenWriteAsync(mappedAccessCondition))
                    using (var streamWriter = new StreamWriter(stream))
                        using (var jsonTextWriter = new JsonTextWriter(streamWriter))
                        {
                            blobReference.Properties.ContentType = "application/json";
                            Serializer.Serialize(jsonTextWriter, newData);
                        }
            }
        }
示例#7
0
 private static AccessCondition MapAccessCondition(IAccessCondition accessCondition)
 {
     return(new AccessCondition
     {
         IfNoneMatchETag = accessCondition.IfNoneMatchETag,
         IfMatchETag = accessCondition.IfMatchETag,
     });
 }
示例#8
0
        public async Task <AuxiliaryFileResult <DownloadData> > ReadLatestIndexedAsync(
            IAccessCondition accessCondition,
            StringCache stringCache)
        {
            var stopwatch     = Stopwatch.StartNew();
            var blobName      = GetLatestIndexedBlobName();
            var blobReference = Container.GetBlobReference(blobName);

            _logger.LogInformation("Reading the latest indexed downloads from {BlobName}.", blobName);

            bool modified;
            var  downloads = new DownloadData();
            AuxiliaryFileMetadata metadata;

            try
            {
                using (var stream = await blobReference.OpenReadAsync(accessCondition))
                {
                    ReadStream(
                        stream,
                        (id, version, downloadCount) =>
                    {
                        id      = stringCache.Dedupe(id);
                        version = stringCache.Dedupe(version);
                        downloads.SetDownloadCount(id, version, downloadCount);
                    });
                    modified = true;
                    metadata = new AuxiliaryFileMetadata(
                        lastModified: new DateTimeOffset(blobReference.LastModifiedUtc, TimeSpan.Zero),
                        loadDuration: stopwatch.Elapsed,
                        fileSize: blobReference.Properties.Length,
                        etag: blobReference.ETag);
                }
            }
            catch (StorageException ex) when(ex.RequestInformation.HttpStatusCode == (int)HttpStatusCode.NotModified)
            {
                _logger.LogInformation("The blob {BlobName} has not changed.", blobName);
                modified  = false;
                downloads = null;
                metadata  = null;
            }

            stopwatch.Stop();
            _telemetryService.TrackReadLatestIndexedDownloads(downloads?.Count, modified, stopwatch.Elapsed);

            return(new AuxiliaryFileResult <DownloadData>(
                       modified,
                       downloads,
                       metadata));
        }
        public Task <string> CopyFileAsync(string srcFolderName, string srcFileName, string destFolderName,
                                           string destFileName, IAccessCondition destAccessCondition)
        {
            if (srcFolderName == null)
            {
                throw new ArgumentNullException(nameof(srcFolderName));
            }

            if (srcFileName == null)
            {
                throw new ArgumentNullException(nameof(srcFileName));
            }

            if (destFolderName == null)
            {
                throw new ArgumentNullException(nameof(destFolderName));
            }

            if (destFileName == null)
            {
                throw new ArgumentNullException(nameof(destFileName));
            }

            var srcFilePath  = buildPath(srcFolderName, srcFileName);
            var destFilePath = buildPath(destFolderName, destFileName);

            _fileSystemService.CreateDirectory(Path.GetDirectoryName(destFilePath));

            if (!_fileSystemService.FileExists(srcFilePath))
            {
                throw new InvalidOperationException("Could not copy because source file does not exists");
            }

            if (_fileSystemService.FileExists(destFilePath))
            {
                throw new InvalidOperationException("Could not copy because destination file already exists");
            }

            try
            {
                _fileSystemService.Copy(srcFilePath, destFilePath, overwrite: false);
            }
            catch (IOException e)
            {
                throw new InvalidOperationException("Could not copy because destination file already exists", e);
            }

            return(Task.FromResult <string>(null));
        }
示例#10
0
        public Task CopyFileAsync(
            Uri srcUri,
            string destFolderName,
            string destFileName,
            IAccessCondition destAccessCondition)
        {
            if (srcUri == null)
            {
                throw new ArgumentNullException(nameof(srcUri));
            }

            var srcBlob = _client.GetBlobFromUri(srcUri);

            return(CopyFileAsync(srcBlob, destFolderName, destFileName, destAccessCondition));
        }
示例#11
0
        public virtual Task CopyValidationSetPackageToPackageFileAsync(
            PackageValidationSet validationSet,
            IAccessCondition destAccessCondition)
        {
            var srcFileName = BuildValidationSetPackageFileName(validationSet,
                                                                _fileMetadataService.FileExtension);

            var destFileName = BuildFileName(validationSet,
                                             _fileMetadataService.FileSavePathTemplate,
                                             _fileMetadataService.FileExtension);

            return(CopyFileAsync(
                       _fileMetadataService.ValidationFolderName,
                       srcFileName,
                       _fileMetadataService.FileFolderName,
                       destFileName,
                       destAccessCondition));
        }
示例#12
0
        public async Task <AuxiliaryFileResult <HashSet <string> > > ReadLatestAsync(
            IAccessCondition accessCondition,
            StringCache stringCache)
        {
            var stopwatch     = Stopwatch.StartNew();
            var blobName      = GetLatestIndexedBlobName();
            var blobReference = Container.GetBlobReference(blobName);

            _logger.LogInformation("Reading the latest verified packages from {BlobName}.", blobName);

            bool modified;
            var  data = new HashSet <string>(StringComparer.OrdinalIgnoreCase);
            AuxiliaryFileMetadata metadata;

            try
            {
                using (var stream = await blobReference.OpenReadAsync(accessCondition))
                {
                    ReadStream(stream, id => data.Add(stringCache.Dedupe(id)));
                    modified = true;
                    metadata = new AuxiliaryFileMetadata(
                        lastModified: new DateTimeOffset(blobReference.LastModifiedUtc, TimeSpan.Zero),
                        loadDuration: stopwatch.Elapsed,
                        fileSize: blobReference.Properties.Length,
                        etag: blobReference.ETag);
                }
            }
            catch (StorageException ex) when(ex.RequestInformation.HttpStatusCode == (int)HttpStatusCode.NotModified)
            {
                _logger.LogInformation("The blob {BlobName} has not changed.", blobName);
                modified = false;
                data     = null;
                metadata = null;
            }

            stopwatch.Stop();
            _telemetryService.TrackReadLatestVerifiedPackages(data?.Count, modified, stopwatch.Elapsed);

            return(new AuxiliaryFileResult <HashSet <string> >(
                       modified,
                       data,
                       metadata));
        }
示例#13
0
        public Task <string> CopyFileAsync(
            string srcFolderName,
            string srcFileName,
            string destFolderName,
            string destFileName,
            IAccessCondition destAccessCondition)
        {
            if (srcFolderName == null)
            {
                throw new ArgumentNullException(nameof(srcFolderName));
            }

            if (srcFileName == null)
            {
                throw new ArgumentNullException(nameof(srcFileName));
            }

            if (destFolderName == null)
            {
                throw new ArgumentNullException(nameof(destFolderName));
            }

            if (destFileName == null)
            {
                throw new ArgumentNullException(nameof(destFileName));
            }

            var srcFilePath  = BuildPath(_configuration.FileStorageDirectory, srcFolderName, srcFileName);
            var destFilePath = BuildPath(_configuration.FileStorageDirectory, destFolderName, destFileName);

            _fileSystemService.CreateDirectory(Path.GetDirectoryName(destFilePath));

            try
            {
                _fileSystemService.Copy(srcFilePath, destFilePath, overwrite: false);
            }
            catch (IOException e)
            {
                throw new FileAlreadyExistsException("Could not copy because destination file already exists", e);
            }

            return(Task.FromResult <string>(null));
        }
示例#14
0
        public Task CopyValidationSetPackageToPackageFileAsync(
            PackageValidationSet validationSet,
            IAccessCondition destAccessCondition)
        {
            var srcFileName = BuildValidationSetPackageFileName(validationSet);

            var destFileName = BuildFileName(
                validationSet.PackageId,
                validationSet.PackageNormalizedVersion,
                CoreConstants.PackageFileSavePathTemplate,
                CoreConstants.NuGetPackageFileExtension);

            return(CopyFileAsync(
                       CoreConstants.ValidationFolderName,
                       srcFileName,
                       CoreConstants.PackagesFolderName,
                       destFileName,
                       destAccessCondition));
        }
示例#15
0
        public async Task ReplaceLatestAsync(
            HashSet <string> newData,
            IAccessCondition accessCondition)
        {
            using (_telemetryService.TrackReplaceLatestVerifiedPackages(newData.Count))
            {
                var blobName = GetLatestIndexedBlobName();
                _logger.LogInformation("Replacing the latest verified packages from {BlobName}.", blobName);

                var blobReference = Container.GetBlobReference(blobName);

                using (var stream = await blobReference.OpenWriteAsync(accessCondition))
                    using (var streamWriter = new StreamWriter(stream))
                        using (var jsonTextWriter = new JsonTextWriter(streamWriter))
                        {
                            blobReference.Properties.ContentType = "application/json";
                            Serializer.Serialize(jsonTextWriter, newData);
                        }
            }
        }
示例#16
0
        private Task <string> CopyFileAsync(
            string srcFolderName,
            string srcFileName,
            string destFolderName,
            string destFileName,
            IAccessCondition destAccessCondition)
        {
            _logger.LogInformation(
                "Copying file {SrcFolderName}/{SrcFileName} to {DestFolderName}/{DestFileName}.",
                srcFolderName,
                srcFileName,
                destFolderName,
                destFileName);

            return(_fileStorageService.CopyFileAsync(
                       srcFolderName,
                       srcFileName,
                       destFolderName,
                       destFileName,
                       destAccessCondition));
        }
示例#17
0
        public async Task <string> CopyFileAsync(
            string srcFolderName,
            string srcFileName,
            string destFolderName,
            string destFileName,
            IAccessCondition destAccessCondition)
        {
            if (srcFolderName == null)
            {
                throw new ArgumentNullException(nameof(srcFolderName));
            }

            if (srcFileName == null)
            {
                throw new ArgumentNullException(nameof(srcFileName));
            }

            var srcContainer = await GetContainerAsync(srcFolderName);

            var srcBlob = srcContainer.GetBlobReference(srcFileName);

            return(await CopyFileAsync(srcBlob, destFolderName, destFileName, destAccessCondition));
        }
 public ResultAndAccessCondition(T result, IAccessCondition accessCondition)
 {
     Result          = result;
     AccessCondition = accessCondition;
 }
示例#19
0
        public async Task SaveFileAsync(string folderName, string fileName, Stream file, IAccessCondition accessConditions)
        {
            ICloudBlobContainer container = await GetContainerAsync(folderName);

            var blob = container.GetBlobReference(fileName);

            accessConditions = accessConditions ?? AccessConditionWrapper.GenerateIfNotExistsCondition();

            var mappedAccessCondition = new AccessCondition
            {
                IfNoneMatchETag = accessConditions.IfNoneMatchETag,
                IfMatchETag     = accessConditions.IfMatchETag,
            };

            try
            {
                await blob.UploadFromStreamAsync(file, mappedAccessCondition);
            }
            catch (StorageException ex) when(ex.IsFileAlreadyExistsException())
            {
                throw new FileAlreadyExistsException(
                          String.Format(
                              CultureInfo.CurrentCulture,
                              "There is already a blob with name {0} in container {1}.",
                              fileName,
                              folderName),
                          ex);
            }

            blob.Properties.ContentType = GetContentType(folderName);
            await blob.SetPropertiesAsync();
        }
示例#20
0
        private async Task <string> CopyFileAsync(
            ISimpleCloudBlob srcBlob,
            string destFolderName,
            string destFileName,
            IAccessCondition destAccessCondition)
        {
            if (destFolderName == null)
            {
                throw new ArgumentNullException(nameof(destFolderName));
            }

            if (destFileName == null)
            {
                throw new ArgumentNullException(nameof(destFileName));
            }

            var destContainer = await GetContainerAsync(destFolderName);

            var destBlob = destContainer.GetBlobReference(destFileName);

            destAccessCondition = destAccessCondition ?? AccessConditionWrapper.GenerateIfNotExistsCondition();
            var mappedDestAccessCondition = new AccessCondition
            {
                IfNoneMatchETag = destAccessCondition.IfNoneMatchETag,
                IfMatchETag     = destAccessCondition.IfMatchETag,
            };

            if (!await srcBlob.ExistsAsync())
            {
                _trace.TraceEvent(
                    TraceEventType.Warning,
                    id: 0,
                    message: $"Before calling FetchAttributesAsync(), the source blob '{srcBlob.Name}' does not exist.");
            }

            // Determine the source blob etag.
            await srcBlob.FetchAttributesAsync();

            var srcAccessCondition = AccessCondition.GenerateIfMatchCondition(srcBlob.ETag);

            // Check if the destination blob already exists and fetch attributes.
            if (await destBlob.ExistsAsync())
            {
                if (destBlob.CopyState?.Status == CopyStatus.Failed)
                {
                    // If the last copy failed, allow this copy to occur no matter what the caller's destination
                    // condition is. This is because the source blob is preferable over a failed copy. We use the etag
                    // of the failed blob to avoid inadvertently replacing a blob that is now valid (i.e. has a
                    // successful copy status).
                    _trace.TraceEvent(
                        TraceEventType.Information,
                        id: 0,
                        message: $"Destination blob '{destFolderName}/{destFileName}' already exists but has a " +
                        $"failed copy status. This blob will be replaced if the etag matches '{destBlob.ETag}'.");

                    mappedDestAccessCondition = AccessCondition.GenerateIfMatchCondition(destBlob.ETag);
                }
                else if ((srcBlob.Properties.ContentMD5 != null &&
                          srcBlob.Properties.ContentMD5 == destBlob.Properties.ContentMD5 &&
                          srcBlob.Properties.Length == destBlob.Properties.Length))
                {
                    // If the blob hash is the same and the length is the same, no-op the copy.
                    _trace.TraceEvent(
                        TraceEventType.Information,
                        id: 0,
                        message: $"Destination blob '{destFolderName}/{destFileName}' already has hash " +
                        $"'{destBlob.Properties.ContentMD5}' and length '{destBlob.Properties.Length}'. The copy " +
                        $"will be skipped.");

                    return(srcBlob.ETag);
                }
            }

            _trace.TraceEvent(
                TraceEventType.Information,
                id: 0,
                message: $"Copying of source blob '{srcBlob.Uri}' to '{destFolderName}/{destFileName}' with source " +
                $"access condition {Log(srcAccessCondition)} and destination access condition " +
                $"{Log(mappedDestAccessCondition)}.");

            // Start the server-side copy and wait for it to complete. If "If-None-Match: *" was specified and the
            // destination already exists, HTTP 409 is thrown. If "If-Match: ETAG" was specified and the destination
            // has changed, HTTP 412 is thrown.
            try
            {
                await destBlob.StartCopyAsync(
                    srcBlob,
                    srcAccessCondition,
                    mappedDestAccessCondition);
            }
            catch (StorageException ex) when(ex.IsFileAlreadyExistsException())
            {
                throw new FileAlreadyExistsException(
                          String.Format(
                              CultureInfo.CurrentCulture,
                              "There is already a blob with name {0} in container {1}.",
                              destFileName,
                              destFolderName),
                          ex);
            }

            var stopwatch = Stopwatch.StartNew();

            while (destBlob.CopyState.Status == CopyStatus.Pending &&
                   stopwatch.Elapsed < MaxCopyDuration)
            {
                if (!await destBlob.ExistsAsync())
                {
                    _trace.TraceEvent(
                        TraceEventType.Warning,
                        id: 0,
                        message: $"Before calling FetchAttributesAsync(), the destination blob '{destBlob.Name}' does not exist.");
                }

                await destBlob.FetchAttributesAsync();

                await Task.Delay(CopyPollFrequency);
            }

            if (destBlob.CopyState.Status == CopyStatus.Pending)
            {
                throw new TimeoutException($"Waiting for the blob copy operation to complete timed out after {MaxCopyDuration.TotalSeconds} seconds.");
            }
            else if (destBlob.CopyState.Status != CopyStatus.Success)
            {
                throw new StorageException($"The blob copy operation had copy status {destBlob.CopyState.Status} ({destBlob.CopyState.StatusDescription}).");
            }

            return(srcBlob.ETag);
        }
示例#21
0
 public static async Task <Stream> OpenWriteAsync(this ISimpleCloudBlob blob, IAccessCondition accessCondition)
 {
     return(await blob.OpenWriteAsync(MapAccessCondition(accessCondition)));
 }
示例#22
0
 public async Task SaveFileAsync(string folderName, string fileName, Stream file, IAccessCondition condition)
 {
     await SaveFileAsync(folderName, fileName, file);
 }