public override async Task <UploadResult> UploadAsync(string name, string originalName, string mimeType, string description, Stream data, UploadAs uploadAs, IProgress <AsyncProgressEntry> progress, CancellationToken cancellation) { await PrepareAsync(cancellation); if (_authToken == null) { throw new Exception(ToolsStrings.Uploader_AuthenticationTokenIsMissing); } var path = DestinationDirectoryId == null ? $"drive/special/approot:/{name}" : $"drive/items/{DestinationDirectoryId}:/{name}"; var total = data.Length; var bufferSize = Math.Min(total, 10 * 320 * 1024); var totalPieces = ((double)total / bufferSize).Ceiling(); JObject result = null; if (totalPieces == 1) { // https://graph.microsoft.com/v1.0/drive/root:/3ds%20Max/Newtonsoft.Json.xml:/content var bytes = await data.ReadAsBytesAsync(); cancellation.ThrowIfCancellationRequested(); result = await Request.Put <JObject>( $@"https://graph.microsoft.com/v1.0/{path}:/[email protected]=rename", bytes, _authToken.AccessToken, progress, cancellation); } else { var ended = false; var buffer = new byte[bufferSize]; var uploaded = 0; async Task <int> NextPiece() { if (ended) { return(0); } var piece = await data.ReadAsync(buffer, 0, buffer.Length); cancellation.ThrowIfCancellationRequested(); // ReSharper disable once AccessToModifiedClosure ended = piece == 0 || uploaded + piece == total; return(piece); } progress.Report("Starting upload session…", 0.00001d); Logging.Debug(path); var uploadUrl = (await Request.Post <JObject>( $@"https://graph.microsoft.com/v1.0/{path}:/createUploadSession", new JObject { ["item"] = new JObject { ["@microsoft.graph.conflictBehavior"] = "rename", ["name"] = name, } }, _authToken.AccessToken, null, cancellation))?.GetStringValueOnly("uploadUrl"); try { cancellation.ThrowIfCancellationRequested(); if (uploadUrl == null) { RaiseShareFailedException(); } for (var index = 1; index < 100000 && !ended; index++) { var rangeFrom = uploaded; var piece = await NextPiece(); result = await Request.Put <JObject>(uploadUrl, buffer.Slice(0, piece), null, progress.Subrange((double)uploaded / total, (double)piece / total, $"Uploading piece #{index} out of {totalPieces} ({{0}})…"), cancellation, new NameValueCollection { ["Content-Range"] = $@"bytes {rangeFrom}-{rangeFrom + piece - 1}/{total}" }); uploaded += piece; cancellation.ThrowIfCancellationRequested(); } } catch (Exception) when(uploadUrl != null) { try { Request.Send("DELETE", uploadUrl, new byte[0], null, null, default(CancellationToken), null).Ignore(); } catch { // ignored } throw; } } cancellation.ThrowIfCancellationRequested(); if (result?["id"] == null) { RaiseUploadFailedException(); } var link = (await Request.Post <JObject>($"https://graph.microsoft.com/v1.0/drive/items/{result["id"]}/createLink", new { type = "view" }, _authToken.AccessToken, null, cancellation))?["link"] as JObject; cancellation.ThrowIfCancellationRequested(); if (link == null) { RaiseShareFailedException(); } #if DEBUG Logging.Debug(link.ToString(Formatting.Indented)); #endif return(WrapUrl((string)link["webUrl"], uploadAs)); }
#pragma warning restore 0649 public override async Task <UploadResult> UploadAsync(string name, string originalName, string mimeType, string description, Stream data, UploadAs uploadAs, IProgress <AsyncProgressEntry> progress, CancellationToken cancellation) { await PrepareAsync(cancellation); if (_authToken == null) { throw new Exception(ToolsStrings.Uploader_AuthenticationTokenIsMissing); } var bytes = await data.ReadAsBytesAsync(); cancellation.ThrowIfCancellationRequested(); var entry = await Request.PostMultipart <InsertResult>(@"https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart", new InsertParams { Title = name, OriginalFilename = originalName, Description = description, MimeType = mimeType, ParentIds = DestinationDirectoryId == null ? null : new[] { new InsertParamsParent { Id = DestinationDirectoryId } } }, _authToken.AccessToken, bytes, mimeType, progress, cancellation); cancellation.ThrowIfCancellationRequested(); if (entry == null) { RaiseUploadFailedException(); } var shared = await Request.Post <PermissionResult>($"https://www.googleapis.com/drive/v2/files/fileId/permissions?fileId={entry.Id}", new { role = @"reader", type = @"anyone" }, _authToken.AccessToken, cancellation : cancellation); cancellation.ThrowIfCancellationRequested(); if (shared == null) { RaiseShareFailedException(); } return(new UploadResult { Id = $"{(uploadAs == UploadAs.Content ? "Gi" : "RG")}{entry.Id}", DirectUrl = $"https://drive.google.com/uc?export=download&id={entry.Id}" }); }