forked from FarmMaps/FarmMapsApiClient
160 lines
6.1 KiB
C#
160 lines
6.1 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.IO;
|
|
using System.Net.Http;
|
|
using System.Net.Mime;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using FarmmapsApi.Models;
|
|
using Google.Apis.Http;
|
|
using Google.Apis.Json;
|
|
using Google.Apis.Requests;
|
|
using Google.Apis.Upload;
|
|
using Google.Apis.Util;
|
|
using Newtonsoft.Json;
|
|
|
|
namespace FarmmapsApi.Services
|
|
{
|
|
public class FarmmapsUploader : ResumableUpload
|
|
{
|
|
/// <summary>Payload description headers, describing the content itself.</summary>
|
|
private const string PayloadContentTypeHeader = "X-Upload-Content-Type";
|
|
|
|
/// <summary>Payload description headers, describing the content itself.</summary>
|
|
private const string PayloadContentLengthHeader = "X-Upload-Content-Length";
|
|
|
|
private const int UnknownSize = -1;
|
|
|
|
/// <summary>Gets or sets the service.</summary>
|
|
private HttpClient HttpClient { get; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the path of the method (combined with
|
|
/// <see cref="Google.Apis.Services.IClientService.BaseUri"/>) to produce
|
|
/// absolute Uri.
|
|
/// </summary>
|
|
private string Path { get; }
|
|
|
|
/// <summary>Gets or sets the HTTP method of this upload (used to initialize the upload).</summary>
|
|
private string HttpMethod { get; }
|
|
|
|
/// <summary>Gets or sets the stream's Content-Type.</summary>
|
|
private string ContentType { get; }
|
|
|
|
/// <summary>Gets or sets the body of this request.</summary>
|
|
private FileRequest Body { get; }
|
|
|
|
private long _streamLength;
|
|
|
|
/// <summary>
|
|
/// Create a resumable upload instance with the required parameters.
|
|
/// </summary>
|
|
/// <param name="contentStream">The stream containing the content to upload.</param>
|
|
/// <remarks>
|
|
/// Caller is responsible for maintaining the <paramref name="contentStream"/> open until the upload is
|
|
/// completed.
|
|
/// Caller is responsible for closing the <paramref name="contentStream"/>.
|
|
/// </remarks>
|
|
public FarmmapsUploader(ConfigurableHttpClient httpClient, Stream contentStream, FileRequest body, string contentType)
|
|
: base(contentStream,
|
|
new ResumableUploadOptions
|
|
{
|
|
HttpClient = httpClient,
|
|
Serializer = new NewtonsoftJsonSerializer(),
|
|
ServiceName = "FarmMaps"
|
|
})
|
|
{
|
|
httpClient.ThrowIfNull(nameof(httpClient));
|
|
contentStream.ThrowIfNull(nameof(contentStream));
|
|
|
|
_streamLength = ContentStream.CanSeek ? ContentStream.Length : UnknownSize;
|
|
Body = body;
|
|
Path = "api/v1/file";
|
|
HttpClient = httpClient;
|
|
HttpMethod = HttpConsts.Post;
|
|
ContentType = contentType;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override async Task<Uri> InitiateSessionAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
HttpRequestMessage request = CreateInitializeRequest();
|
|
Options?.ModifySessionInitiationRequest?.Invoke(request);
|
|
var response = await HttpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
throw await ExceptionForResponseAsync(response).ConfigureAwait(false);
|
|
}
|
|
return response.Headers.Location;
|
|
}
|
|
|
|
/// <summary>Creates a request to initialize a request.</summary>
|
|
private HttpRequestMessage CreateInitializeRequest()
|
|
{
|
|
var baseAddres = HttpClient.BaseAddress;
|
|
var uri = new Uri($"{baseAddres.Scheme}://{baseAddres.Host}:{baseAddres.Port}");
|
|
var builder = new RequestBuilder()
|
|
{
|
|
BaseUri = uri,
|
|
Path = Path,
|
|
Method = HttpMethod,
|
|
};
|
|
|
|
SetAllPropertyValues(builder);
|
|
|
|
HttpRequestMessage request = builder.CreateRequest();
|
|
if (ContentType != null)
|
|
{
|
|
request.Headers.Add(PayloadContentTypeHeader, ContentType);
|
|
}
|
|
|
|
// if the length is unknown at the time of this request, omit "X-Upload-Content-Length" header
|
|
if (ContentStream.CanSeek)
|
|
{
|
|
request.Headers.Add(PayloadContentLengthHeader, _streamLength.ToString());
|
|
}
|
|
|
|
var jsonText = JsonConvert.SerializeObject(Body);
|
|
request.Content = new StringContent(jsonText, Encoding.UTF8, MediaTypeNames.Application.Json);
|
|
|
|
return request;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reflectively enumerate the properties of this object looking for all properties containing the
|
|
/// RequestParameterAttribute and copy their values into the request builder.
|
|
/// </summary>
|
|
private void SetAllPropertyValues(RequestBuilder requestBuilder)
|
|
{
|
|
Type myType = this.GetType();
|
|
var properties = myType.GetProperties();
|
|
|
|
foreach (var property in properties)
|
|
{
|
|
var attribute = property.GetCustomAttribute<RequestParameterAttribute>();
|
|
if (attribute != null)
|
|
{
|
|
string name = attribute.Name ?? property.Name.ToLower();
|
|
object value = property.GetValue(this, null);
|
|
if (value != null)
|
|
{
|
|
if (!(value is string) && value is IEnumerable valueAsEnumerable)
|
|
{
|
|
foreach (var elem in valueAsEnumerable)
|
|
{
|
|
requestBuilder.AddParameter(attribute.Type, name, Utilities.ConvertToString(elem));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Otherwise just convert it to a string.
|
|
requestBuilder.AddParameter(attribute.Type, name, Utilities.ConvertToString(value));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |