@@ -35,121 +35,116 @@ limitations under the License.
35
35
36
36
namespace Google . Apis . Upload
37
37
{
38
- public sealed class ResumableUploadSessionOptions
38
+ /// <summary>
39
+ /// Options for <c>ResumableUpload</c> operations.
40
+ /// </summary>
41
+ public sealed class ResumableUploadOptions
39
42
{
43
+ /// <summary>
44
+ /// Gets or sets the HTTP client to use when starting the upload sessions and uploading data.
45
+ /// </summary>
40
46
public HttpClient HttpClient { get ; set ; }
41
47
42
48
internal ConfigurableHttpClient ConfigurableHttpClient { get { return HttpClient as ConfigurableHttpClient ; } }
43
49
44
- public Action < HttpRequestMessage > ModifySessionUriRequest { get ; set ; }
50
+ /// <summary>
51
+ /// Gets or sets the callback for modifying the session initiation request.
52
+ /// See https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload#start-resumable for more information.
53
+ /// </summary>
54
+ /// <remarks>
55
+ /// Note: If these options are used with a <see cref="TmpResumableUpload"/> created using <see cref="TmpResumableUpload.CreateFromSessionUri"/>,
56
+ /// this property will be ignored as the session has already been initiated.
57
+ /// </remarks>
58
+ public Action < HttpRequestMessage > ModifySessionInitiationRequest { get ; set ; }
45
59
60
+ /// <summary>
61
+ /// Gets or sets the serializer to use when parsing error responses.
62
+ /// </summary>
46
63
public ISerializer Serializer { get ; set ; }
47
64
65
+ /// <summary>
66
+ /// Gets or sets the name of the service performing the upload.
67
+ /// </summary>
68
+ /// <remarks>
69
+ /// This will be used to set the <see cref="GoogleApiException.ServiceName"/> in the event of an error.
70
+ /// </remarks>
48
71
public string ServiceName { get ; set ; }
49
72
}
50
73
74
+ /// <summary>
75
+ /// Media upload which uses Google's resumable media upload protocol to upload data.
76
+ /// </summary>
77
+ /// <remarks>
78
+ /// See: https://developers.google.com/drive/manage-uploads#resumable for more information on the protocol.
79
+ /// </remarks>
51
80
public class TmpResumableUpload
52
81
{
53
- protected ConfigurableHttpClient HttpClient { get ; }
54
-
55
- private ResumableUploadSessionOptions Options { get ; }
56
-
57
- private string SignedUrl { get ; set ; }
82
+ internal ConfigurableHttpClient HttpClient { get ; }
58
83
84
+ /// <summary>
85
+ /// Gets the options used to control the resumable upload.
86
+ /// </summary>
87
+ protected ResumableUploadOptions Options { get ; }
59
88
60
- protected TmpResumableUpload ( Stream contentStream , ResumableUploadSessionOptions options )
89
+ /// <summary>
90
+ /// Creates a <see cref="TmpResumableUpload"/> instance.
91
+ /// </summary>
92
+ /// <param name="contentStream">The data to be uploaded.</param>
93
+ /// <param name="options">The options for the upload operation.</param>
94
+ protected TmpResumableUpload ( Stream contentStream , ResumableUploadOptions options )
61
95
{
96
+ contentStream . ThrowIfNull ( nameof ( contentStream ) ) ;
62
97
ContentStream = contentStream ;
63
98
HttpClient = options ? . ConfigurableHttpClient ?? new ConfigurableHttpClient ( new ConfigurableMessageHandler ( new HttpClientHandler ( ) ) ) ;
64
99
Options = options ;
65
100
}
66
101
67
- private TmpResumableUpload ( string signedUrl , Stream contentStream , ResumableUploadSessionOptions options )
68
- : this ( contentStream , options )
69
- {
70
- SignedUrl = signedUrl ;
71
- }
72
-
73
- private TmpResumableUpload ( Uri sessionUri , Stream contentStream , ResumableUploadSessionOptions options )
102
+ private TmpResumableUpload ( Uri sessionUri , Stream contentStream , ResumableUploadOptions options )
74
103
: this ( contentStream , options )
75
104
{
76
105
UploadUri = sessionUri ;
77
106
}
78
107
79
108
/// <summary>
80
- /// Initializes the resumable upload by calling the resumable rest interface to get a unique upload location.
81
- /// See https://developers.google.com/drive/manage-uploads#start-resumable for more details.
109
+ /// Initiates the resumable upload session and returns the session URI.
110
+ /// See https://developers.google.com/drive/manage-uploads#start-resumable and
111
+ /// https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload#start-resumable for more information.
82
112
/// </summary>
113
+ /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
83
114
/// <returns>
84
- /// The unique upload location for this upload, returned in the Location header
115
+ /// The task containing the session URI to use for the resumable upload.
85
116
/// </returns>
86
- protected virtual async Task < Uri > GetSessionUriAsync ( CancellationToken cancellationToken )
117
+ protected virtual Task < Uri > InitiateSessionAsync ( CancellationToken cancellationToken )
87
118
{
88
119
if ( UploadUri != null )
89
120
{
90
- return UploadUri ;
91
- }
92
-
93
- if ( SignedUrl != null )
94
- {
95
- return await GetSessionUriAsync ( SignedUrl , Options , cancellationToken ) ;
121
+ return Task . FromResult ( UploadUri ) ;
96
122
}
97
-
98
- throw new InvalidOperationException ( $ "Could not obtain a session URI with the information in the { nameof ( TmpResumableUpload ) } instance.") ;
123
+
124
+ throw new InvalidOperationException ( $ "Could not initiate the resumable upload session with the information in the { this . GetType ( ) . Name } instance.") ;
99
125
}
100
126
127
+ /// <summary>
128
+ /// Creates a <see cref="TmpResumableUpload"/> instance for a resumable upload session which has already been initiated.
129
+ /// </summary>
130
+ /// <remarks>
131
+ /// See https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload#start-resumable for more information about initiating
132
+ /// resumable upload sessions and saving the session URI.
133
+ /// </remarks>
134
+ /// <param name="sessionUri">The session URI of the resumable upload session.</param>
135
+ /// <param name="contentStream">The data to be uploaded.</param>
136
+ /// <param name="options">The options for the upload operation.</param>
137
+ /// <returns>The instance which can be used to upload the specified content.</returns>
101
138
public static TmpResumableUpload CreateFromSessionUri (
102
139
Uri sessionUri ,
103
140
Stream contentStream ,
104
- ResumableUploadSessionOptions options = null )
141
+ ResumableUploadOptions options = null )
105
142
{
106
143
sessionUri . ThrowIfNull ( nameof ( sessionUri ) ) ;
107
144
return new TmpResumableUpload ( sessionUri , contentStream , options ) ;
108
145
}
109
-
110
- public static TmpResumableUpload CreateFromSignedUrl (
111
- string signedUrl ,
112
- Stream contentStream ,
113
- ResumableUploadSessionOptions options = null )
114
- {
115
- signedUrl . ThrowIfNull ( nameof ( signedUrl ) ) ;
116
- return new TmpResumableUpload ( signedUrl , contentStream , options ) ;
117
- }
118
-
119
- public static Uri GetSessionUri ( string signedUrl , ResumableUploadSessionOptions options = null ) =>
120
- GetResult ( token => GetSessionUriAsync ( signedUrl , options ) ) ;
121
-
122
- public static async Task < Uri > GetSessionUriAsync (
123
- string signedUrl ,
124
- ResumableUploadSessionOptions options = null ,
125
- CancellationToken cancellationToken = default ( CancellationToken ) )
126
- {
127
- var httpClient = options ? . HttpClient ?? new HttpClient ( ) ;
128
- var request = new HttpRequestMessage ( HttpMethod . Post , signedUrl ) ;
129
- request . Headers . Add ( "x-goog-resumable" , "start" ) ;
130
- options ? . ModifySessionUriRequest ? . Invoke ( request ) ;
131
- var result = await httpClient . SendAsync ( request , cancellationToken ) . ConfigureAwait ( false ) ;
132
- if ( ! result . IsSuccessStatusCode )
133
- {
134
- throw await MediaApiErrorHandling . ExceptionForResponseAsync ( options ? . Serializer , options ? . ServiceName , result ) . ConfigureAwait ( false ) ;
135
- }
136
- return result . Headers . Location ;
137
- }
138
-
139
- private static T GetResult < T > ( Func < CancellationToken , Task < T > > operation )
140
- {
141
- try
142
- {
143
- return operation ( CancellationToken . None ) . Result ;
144
- }
145
- catch ( AggregateException e )
146
- {
147
- throw e . InnerExceptions . FirstOrDefault ( ) ?? e ;
148
- }
149
- }
150
-
151
-
152
-
146
+
147
+
153
148
/// <summary>The class logger.</summary>
154
149
protected static ILogger Logger { get ; } = ApplicationContext . Logger . ForType < TmpResumableUpload > ( ) ;
155
150
@@ -273,7 +268,7 @@ public async Task<IUploadProgress> UploadAsync(CancellationToken cancellationTok
273
268
274
269
try
275
270
{
276
- UploadUri = await GetSessionUriAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
271
+ UploadUri = await InitiateSessionAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
277
272
if ( ContentStream . CanSeek )
278
273
{
279
274
SendUploadSessionData ( new ResumeableUploadSessionData ( UploadUri ) ) ;
@@ -376,6 +371,11 @@ protected async Task<bool> HandleResponse(HttpResponseMessage response)
376
371
throw await ExceptionForResponseAsync ( response ) . ConfigureAwait ( false ) ;
377
372
}
378
373
374
+ /// <summary>
375
+ /// Creates a <see cref="GoogleApiException"/> instance using the error response from the server.
376
+ /// </summary>
377
+ /// <param name="response">The error response.</param>
378
+ /// <returns>An exception which can be thrown by the caller.</returns>
379
379
protected Task < GoogleApiException > ExceptionForResponseAsync ( HttpResponseMessage response )
380
380
{
381
381
return MediaApiErrorHandling . ExceptionForResponseAsync ( Options ? . Serializer , Options ? . ServiceName , response ) ;
@@ -662,7 +662,7 @@ public async Task<IUploadProgress> ResumeAsync(Uri uploadUri, CancellationToken
662
662
/// were successfully uploaded before the error occurred.
663
663
/// See https://developers.google.com/drive/manage-uploads#resume-upload for more details.
664
664
/// </summary>
665
- protected sealed class ServerErrorCallback : IHttpUnsuccessfulResponseHandler , IHttpExceptionHandler , IDisposable
665
+ private sealed class ServerErrorCallback : IHttpUnsuccessfulResponseHandler , IHttpExceptionHandler , IDisposable
666
666
{
667
667
private TmpResumableUpload Owner { get ; set ; }
668
668
@@ -730,7 +730,7 @@ public void Dispose()
730
730
#region Progress Monitoring
731
731
732
732
/// <summary>Class that communicates the progress of resumable uploads to a container.</summary>
733
- protected sealed class ResumableUploadProgress : IUploadProgress
733
+ private sealed class ResumableUploadProgress : IUploadProgress
734
734
{
735
735
/// <summary>
736
736
/// Create a ResumableUploadProgress instance.
@@ -764,12 +764,12 @@ public ResumableUploadProgress(Exception exception, long bytesSent)
764
764
/// Current state of progress of the upload.
765
765
/// </summary>
766
766
/// <seealso cref="ProgressChanged"/>
767
- protected ResumableUploadProgress Progress { get ; set ; }
767
+ private ResumableUploadProgress Progress { get ; set ; }
768
768
769
769
/// <summary>
770
770
/// Updates the current progress and call the <see cref="ProgressChanged"/> event to notify listeners.
771
771
/// </summary>
772
- protected void UpdateProgress ( ResumableUploadProgress progress )
772
+ private void UpdateProgress ( ResumableUploadProgress progress )
773
773
{
774
774
Progress = progress ;
775
775
ProgressChanged ? . Invoke ( progress ) ;
@@ -872,7 +872,7 @@ public abstract class TmpResumableUpload<TRequest> : TmpResumableUpload
872
872
/// </remarks>
873
873
protected TmpResumableUpload ( IClientService service , string path , string httpMethod , Stream contentStream ,
874
874
string contentType )
875
- : base ( contentStream , new ResumableUploadSessionOptions {
875
+ : base ( contentStream , new ResumableUploadOptions {
876
876
HttpClient = service . HttpClient ,
877
877
Serializer = service . Serializer ,
878
878
ServiceName = service . Name
@@ -914,16 +914,11 @@ protected TmpResumableUpload(IClientService service, string path, string httpMet
914
914
915
915
#endregion // Properties
916
916
917
- /// <summary>
918
- /// Initializes the resumable upload by calling the resumable rest interface to get a unique upload location.
919
- /// See https://developers.google.com/drive/manage-uploads#start-resumable for more details.
920
- /// </summary>
921
- /// <returns>
922
- /// The unique upload location for this upload, returned in the Location header
923
- /// </returns>
924
- protected override async Task < Uri > GetSessionUriAsync ( CancellationToken cancellationToken )
917
+ /// <inheritdoc/>
918
+ protected override async Task < Uri > InitiateSessionAsync ( CancellationToken cancellationToken )
925
919
{
926
920
HttpRequestMessage request = CreateInitializeRequest ( ) ;
921
+ Options ? . ModifySessionInitiationRequest ? . Invoke ( request ) ;
927
922
var response = await Service . HttpClient . SendAsync ( request , cancellationToken ) . ConfigureAwait ( false ) ;
928
923
929
924
if ( ! response . IsSuccessStatusCode )
0 commit comments