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; }
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; }
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); }
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; }
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; }
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; }
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); }
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); } }