예제 #1
0
        private static async Task<int> ExecuteAsync(Options options)
        {
            // build the implementation models
            using (var stdin = Console.OpenStandardInput())
            {
                var client = new Client(new SystemTime(), new PathBuilder());

                if (options.OnlyUnique)
                {
                    var uniqueClient = new UniqueClient(client);

                    // we have to buffer the input for byte-by-byte comparison
                    using (var buffer = new MemoryStream())
                    {
                        await stdin.CopyToAsync(buffer);
                        buffer.Seek(0, SeekOrigin.Begin);

                        var request = new UniqueUploadRequest
                        {
                            ConnectionString = options.ConnectionString,
                            Container = options.Container,
                            ContentType = options.ContentType,
                            PathFormat = options.PathFormat,
                            Stream = buffer,
                            EqualsAsync = null,
                            UploadDirect = !options.NoDirect,
                            Trace = Console.Out
                        };

                        // upload
                        await uniqueClient.UploadAsync(request);
                    }

                }
                else
                {
                    var request = new UploadRequest
                    {
                        ConnectionString = options.ConnectionString,
                        Container = options.Container,
                        ContentType = options.ContentType,
                        PathFormat = options.PathFormat,
                        UploadDirect = !options.NoDirect,
                        UploadLatest = !options.NoLatest,
                        Stream = stdin,
                        Trace = Console.Out
                    };

                    // upload
                    await client.UploadAsync(request);
                }

            }

            return 0;
        }
예제 #2
0
        public async Task<UploadResult> UploadAsync(UploadRequest request)
        {
            // validate input
            _pathBuilder.Validate(request.PathFormat);

            // initialize
            request.Trace.Write("Initializing...");
            var context = new CloudContext(request.ConnectionString, request.Container);

            await context.BlobContainer.CreateIfNotExistsAsync(
                BlobContainerPublicAccessType.Blob,
                new BlobRequestOptions(),
                null);
            request.Trace.WriteLine(" done.");

            // set the direct
            var result = new UploadResult();
            CloudBlockBlob directBlob = null;
            if (request.UploadDirect)
            {
                if (request.Type == UploadRequestType.Number)
                {
                    directBlob = await UploadDirectNumberAsync(request, context, result);
                }
                else
                {
                    directBlob = await UploadDirectTimestampAsync(request, context);
                }
            }

            // set the latest
            CloudBlockBlob latestBlob = null;
            if (request.UploadLatest)
            {
                var latestPath = _pathBuilder.GetLatest(request.PathFormat);
                if (directBlob == null)
                {
                    latestBlob = await UploadBlobAsync(context, request, latestPath, direct: false);
                }
                else
                {
                    request.Trace.Write($"Copying the direct blob to the latest blob at '{latestPath}'...");
                    latestBlob = context.BlobContainer.GetBlockBlobReference(latestPath);
                    var sourceAccessCondition = new AccessCondition {IfMatchETag = directBlob.Properties.ETag};
                    var destAccessCondition = new AccessCondition {IfMatchETag = request.ETag};
                    await latestBlob.StartCopyAsync(directBlob, sourceAccessCondition, destAccessCondition, null, null);
                    while (latestBlob.CopyState.Status == CopyStatus.Pending)
                    {
                        await Task.Delay(100);
                        await latestBlob.ExistsAsync();
                    }
                    request.Trace.WriteLine(" done.");
                }
            }

            request.Trace.WriteLine();

            if (directBlob != null)
            {
                result.DirectUri = directBlob.Uri;
                result.DirectETag = directBlob.Properties.ETag;
                request.Trace.WriteLine($"Direct: {directBlob.Uri}");
            }
            
            if (latestBlob != null)
            {
                result.LatestUri = latestBlob.Uri;
                result.LatestETag = latestBlob.Properties.ETag;
                request.Trace.WriteLine($"Latest: {latestBlob.Uri}");
            }

            return result;
        }
예제 #3
0
            public TestContext()
            {
                // data
                UtcNow = new DateTimeOffset(2015, 1, 2, 3, 4, 5, 6, TimeSpan.Zero);
                Content = "foobar";
                Container = TestSupport.GetTestContainer();
                UploadRequest = new UploadRequest
                {
                    ConnectionString = TestSupport.ConnectionString,
                    Container = Container,
                    ContentType = "text/plain",
                    PathFormat = "testpath/{0}.txt",
                    UploadDirect = true,
                    UploadLatest = true,
                    Stream = new MemoryStream(Encoding.UTF8.GetBytes(Content)),
                    Trace = TextWriter.Null
                };
                GetLatestRequest = new GetLatestRequest
                {
                    ConnectionString = UploadRequest.ConnectionString,
                    Container = UploadRequest.Container,
                    PathFormat = UploadRequest.PathFormat,
                    Trace = TextWriter.Null
                };

                // dependencies
                SystemTime = new Mock<ISystemTime>();
                PathBuilder = new PathBuilder();

                // setup
                SystemTime.Setup(x => x.UtcNow).Returns(() => UtcNow);

                // target
                Target = new Client(SystemTime.Object, PathBuilder);
            }
예제 #4
0
        private static async Task<CloudBlockBlob> UploadBlobAsync(CloudContext context, UploadRequest request, string blobPath, bool direct)
        {
            request.Trace.Write($"Uploading the blob at '{blobPath}'...");
            var blob = context.BlobContainer.GetBlockBlobReference(blobPath);

            AccessCondition accessCondition;
            if (!direct && !request.UseETags)
            {
                accessCondition = null;
            }
            if (direct || request.ETag == null)
            {
                accessCondition = AccessCondition.GenerateIfNoneMatchCondition("*");
            }
            else
            {
                accessCondition = AccessCondition.GenerateIfMatchCondition(request.ETag);
            }

            // upload the blob
            await blob.UploadFromStreamAsync(request.Stream, accessCondition, options: null, operationContext: null);
            request.Trace.WriteLine(" done.");

            // set the content type
            if (!string.IsNullOrWhiteSpace(request.ContentType))
            {
                request.Trace.Write($"Setting the content type of '{blobPath}'...");
                blob.Properties.ContentType = request.ContentType;
                await blob.SetPropertiesAsync();
                request.Trace.WriteLine(" done.");
            }

            return blob;
        }
예제 #5
0
        private async Task<CloudBlockBlob> UploadDirectNumberAsync(UploadRequest request, CloudContext context, UploadResult result)
        {
            var latestNumberPath = _pathBuilder.GetDirect(request.PathFormat, 0);
            var latestNumberBlob = context.BlobContainer.GetBlockBlobReference(latestNumberPath);
            string latestNumberEtag = null;
            var latestNumber = 0;

            if (request.LatestNumber.HasValue)
            {
                // Use the provided version number
                latestNumberEtag = request.LatestNumberETag;
                latestNumber = request.LatestNumber.Value;
            }
            else
            {
                // Determine what version number what last used
                try
                {
                    await latestNumberBlob.FetchAttributesAsync();

                    latestNumberEtag = latestNumberBlob.Properties.ETag;

                    var latestNumberString = latestNumberBlob.Metadata[LatestNumberMetadataKey];
                    latestNumber = int.Parse(latestNumberString);
                }
                catch (StorageException e)
                {
                    if (e.RequestInformation.HttpStatusCode != 404)
                    {
                        throw;
                    }
                }

                latestNumber++;
            }

            // Upload the stream
            var latestPath = _pathBuilder.GetDirect(request.PathFormat, latestNumber);

            var directBlob = await UploadBlobAsync(context, request, latestPath, direct: true);
            
            // Update the latest version record
            AccessCondition accessCondition;
            if (!request.UseETags)
            {
                accessCondition = null;
            }
            else if (latestNumberEtag != null)
            {
                accessCondition = AccessCondition.GenerateIfMatchCondition(latestNumberEtag);
            }
            else
            {
                accessCondition = AccessCondition.GenerateIfNoneMatchCondition("*");
            }

            latestNumberBlob.Metadata[LatestNumberMetadataKey] = latestNumber.ToString();

            await latestNumberBlob.UploadFromByteArrayAsync(new byte[0], 0, 0, accessCondition, options: null, operationContext: null);

            // Set the latest etag and number on the result
            result.LatestNumberETag = latestNumberBlob.Properties.ETag;
            result.LatestNumber = latestNumber;

            return directBlob;
        }
예제 #6
0
        private async Task<CloudBlockBlob> UploadDirectTimestampAsync(UploadRequest request, CloudContext context)
        {
            var latestPath = _pathBuilder.GetDirect(request.PathFormat, _systemTime.UtcNow);

            var directBlob = await UploadBlobAsync(context, request, latestPath, direct: true);

            return directBlob;
        }
예제 #7
0
            public TestContext()
            {
                // data
                UtcNow = new DateTimeOffset(2015, 1, 2, 3, 4, 5, 6, TimeSpan.Zero);
                Content = "foobar";
                Container = TestSupport.GetTestContainer();
                Prefix = "testpath";
                UploadRequest = new UploadRequest
                {
                    ConnectionString = TestSupport.ConnectionString,
                    Container = Container,
                    ContentType = "text/plain",
                    PathFormat = Prefix + "/{0}.txt",
                    UploadDirect = true,
                    UploadLatest = true,
                    Stream = new MemoryStream(Encoding.UTF8.GetBytes(Content)),
                    Trace = TextWriter.Null
                };
                CollapseRequest = new CollapseRequest
                {
                    ConnectionString = UploadRequest.ConnectionString,
                    Container = UploadRequest.Container,
                    PathFormat = UploadRequest.PathFormat,
                    Comparer = new OrdinalCollapserComparer(),
                    Trace = TextWriter.Null
                };
                CloudContext = new CloudContext(UploadRequest.ConnectionString, UploadRequest.Container);

                // dependencies
                SystemTime = new Mock<ISystemTime>();
                PathBuilder = new PathBuilder();
                Client = new Client(SystemTime.Object, PathBuilder);

                // setup
                SystemTime
                    .Setup(x => x.UtcNow)
                    .Returns(() => UtcNow).Callback(() => UtcNow = UtcNow.AddSeconds(1));

                // target
                Target = new Collapser(PathBuilder);
            }
예제 #8
0
        public async Task<UploadResult> UploadAsync(UniqueUploadRequest request)
        {
            if (!request.Stream.CanRead)
            {
                throw new ArgumentException("The provided stream must be readable.");
            }

            using (request.Stream)
            {
                // get the current
                var getLatestRequest = new GetLatestRequest
                {
                    ConnectionString = request.ConnectionString,
                    Container = request.Container,
                    PathFormat = request.PathFormat,
                    Trace = request.Trace
                };

                request.Trace.Write("Gettings the existing latest...");
                string etag = null;
                using (var currentResult = await _innerClient.GetLatestStreamAsync(getLatestRequest))
                {
                    // return nothing if the streams are equivalent
                    if (currentResult != null)
                    {
                        if (!request.Stream.CanSeek)
                        {
                            throw new ArgumentException("The provided stream must be seekable");
                        }

                        // seek to the beginning for calculating the hash
                        request.Stream.Seek(0, SeekOrigin.Begin);
                        var contentMD5 = await GetStreamContentMD5(request.Stream);
                        if (contentMD5 == currentResult.ContentMD5)
                        {
                            request.Trace.WriteLine(" exactly the same! No upload required.");
                            return null;
                        }

                        if (request.EqualsAsync != null)
                        {
                            // seek to the beginning for comparing the content
                            request.Stream.Seek(0, SeekOrigin.Begin);
                            if (await request.EqualsAsync(currentResult))
                            {
                                request.Trace.WriteLine(" equivalent! No upload required.");
                                return null;
                            }
                        }

                        etag = currentResult.ETag;

                        request.Trace.WriteLine(" different! The provided content will be uploaded.");
                    }
                    else
                    {
                        request.Trace.WriteLine(" non-existent! The provided content will be uploaded.");
                    }
                }

                // Seek to the beginning for uploading the blob.
                request.Stream.Seek(0, SeekOrigin.Begin);
                var uploadRequest = new UploadRequest
                {
                    ConnectionString = request.ConnectionString,
                    ETag = etag,
                    UseETags = request.UseETag,
                    Stream = request.Stream,
                    PathFormat = request.PathFormat,
                    Container = request.Container,
                    Trace = request.Trace,
                    UploadDirect = request.UploadDirect,
                    UploadLatest = true,
                    ContentType = request.ContentType,
                    Type = request.Type
                };

                return await _innerClient.UploadAsync(uploadRequest);
            }
        }