227 lines
9.4 KiB
C#
227 lines
9.4 KiB
C#
using CANFDApiProxy.Messages;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using System.CodeDom;
|
|
using System.ComponentModel;
|
|
using System.IO;
|
|
using System.Net.Http;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace CANFDApiProxy
|
|
{
|
|
internal static class RESTWrapper
|
|
{
|
|
/// <summary>
|
|
/// Get the description part of the enum
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="source"></param>
|
|
/// <returns></returns>
|
|
private static string DescriptionAttr<T>(this T source)
|
|
{
|
|
FieldInfo fi = source.GetType().GetField(source.ToString());
|
|
|
|
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(
|
|
typeof(DescriptionAttribute), false);
|
|
|
|
if (attributes != null && attributes.Length > 0) return attributes[0].Description;
|
|
else return source.ToString();
|
|
}
|
|
|
|
public static int Port { get; set; } = 5000;
|
|
private static readonly TimeSpan TIMEOUT_DEFAULT = TimeSpan.FromSeconds(30);
|
|
public static TimeSpan Timeout { get; set; } = TIMEOUT_DEFAULT;
|
|
|
|
public static Protocol Protocol { get; set; } = Protocol.http;
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="host">device ip address or host name</param>
|
|
/// <param name="command"></param>
|
|
/// <param name="cancellationToken"></param>
|
|
/// <returns></returns>
|
|
/// <exception cref="ArgumentNullException"></exception>
|
|
public static async Task<string> GetResourceAsync(string host, CommandName command, CancellationToken cancellationToken)
|
|
{
|
|
VerifyHost(host);
|
|
|
|
try
|
|
{
|
|
var httpClient = HttpClientFactory.CreateHttpClient();
|
|
|
|
httpClient.Timeout = Timeout;
|
|
|
|
var commandString = command.DescriptionAttr();
|
|
string requestUri = $"{Protocol.ToString()}://{host}:{Port}/{commandString}";
|
|
|
|
var response = await httpClient.GetAsync(requestUri, cancellationToken);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
|
|
{
|
|
var errorJson = await response.Content.ReadAsStringAsync();
|
|
var res = JsonConvert.DeserializeObject<ErrorMessage>(errorJson);
|
|
|
|
throw new CanApiException(res.Error, 500);
|
|
}
|
|
|
|
response.EnsureSuccessStatusCode();
|
|
}
|
|
|
|
return await response.Content.ReadAsStringAsync();
|
|
}
|
|
catch (TaskCanceledException ex)
|
|
{
|
|
throw new CanApiException("An API call was cancelled or timedout", ex);
|
|
}
|
|
}
|
|
|
|
public static async Task<string> PostResourceAsync<T>(string host, CommandName command, T request, CancellationToken cancellationToken)
|
|
{
|
|
VerifyHost(host);
|
|
|
|
try
|
|
{
|
|
HttpResponseMessage response = await PostAsJsonAsync(host, command, request, Timeout, cancellationToken);
|
|
return await response.Content.ReadAsStringAsync();
|
|
}
|
|
catch (TaskCanceledException ex)
|
|
{
|
|
throw new CanApiException("An API call was cancelled or timedout", ex);
|
|
}
|
|
}
|
|
|
|
public static async Task<Stream> SendResourceReadAsStreamAsync<T>(string host, CommandName command, T request, TimeSpan timeOut, CancellationToken cancellationToken)
|
|
{
|
|
VerifyHost(host);
|
|
return await SendResourceReadAsStreamProcess(host, command, request, timeOut, cancellationToken);
|
|
}
|
|
|
|
private static async Task<Stream> SendResourceReadAsStreamProcess<T>(string host, CommandName command, T request, TimeSpan timeOut, CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
HttpResponseMessage response = await SendAsync(host, command, request, timeOut, cancellationToken);
|
|
return await response.Content.ReadAsStreamAsync();
|
|
}
|
|
catch (TaskCanceledException ex)
|
|
{
|
|
throw new CanApiException("An API call was cancelled or timedout", ex);
|
|
}
|
|
}
|
|
|
|
private static void VerifyHost(string host)
|
|
{
|
|
if (string.IsNullOrEmpty(host)) { throw new ArgumentNullException("host", "host cannot be empty"); }
|
|
}
|
|
|
|
public static async Task<string> PostResourceReadAsStringAsync(string host, CommandName command, MultipartFormDataContent multipart, TimeSpan timeOut, CancellationToken cancellationToken)
|
|
{
|
|
VerifyHost(host);
|
|
|
|
try
|
|
{
|
|
var response = await PostWithMultipartFormAsync(host, command, multipart, timeOut, cancellationToken);
|
|
return await response.Content.ReadAsStringAsync();
|
|
}
|
|
catch (TaskCanceledException ex)
|
|
{
|
|
throw new CanApiException("An API call was cancelled or timedout", ex);
|
|
}
|
|
}
|
|
|
|
private static async Task<HttpResponseMessage> PostAsJsonAsync<T>(string host, CommandName command, T request, TimeSpan timeOut, CancellationToken cancellationToken)
|
|
{
|
|
var httpClient = HttpClientFactory.CreateHttpClient();
|
|
httpClient.Timeout = timeOut;
|
|
var commandString = command.DescriptionAttr();
|
|
|
|
string requestUri = $"{Protocol.ToString()}://{host}:{Port}/{commandString}";
|
|
|
|
var response = await httpClient.PostAsJsonAsync(requestUri, request, cancellationToken);
|
|
|
|
await ValidateResponse(response);
|
|
|
|
return response;
|
|
}
|
|
|
|
private static async Task<HttpResponseMessage> PostWithMultipartFormAsync(string host, CommandName command, MultipartFormDataContent multipart, TimeSpan timeOut, CancellationToken cancellationToken)
|
|
{
|
|
var httpClient = HttpClientFactory.CreateHttpClient();
|
|
httpClient.Timeout = timeOut;
|
|
var commandString = command.DescriptionAttr();
|
|
string requestUri = $"{Protocol.ToString()}://{host}:{Port}/{commandString}";
|
|
|
|
var response = await httpClient.PostAsync(requestUri, multipart, cancellationToken);
|
|
|
|
await ValidateResponse(response);
|
|
|
|
return response;
|
|
}
|
|
|
|
private static async Task<HttpResponseMessage> SendAsync<T>(string host, CommandName command, T request, TimeSpan timeOut, CancellationToken cancellationToken)
|
|
{
|
|
var httpClient = HttpClientFactory.CreateHttpClient();
|
|
httpClient.Timeout = timeOut;
|
|
var commandString = command.DescriptionAttr();
|
|
string requestUri = $"{Protocol.ToString()}://{host}:{Port}/{commandString}";
|
|
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri);
|
|
var json = JsonConvert.SerializeObject(request);
|
|
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
|
httpRequestMessage.Content = content;
|
|
var response = await httpClient.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
|
|
|
|
await ValidateResponse(response);
|
|
|
|
return response;
|
|
}
|
|
|
|
private static async Task<ErrorMessage> BuildErrorMessage(HttpResponseMessage response)
|
|
{
|
|
var errorJson = await response.Content.ReadAsStringAsync();
|
|
var res = JsonConvert.DeserializeObject<ErrorMessage>(errorJson);
|
|
return res;
|
|
}
|
|
|
|
private static async Task ValidateResponse(HttpResponseMessage response)
|
|
{
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
switch (response.StatusCode)
|
|
{
|
|
case System.Net.HttpStatusCode.BadRequest:
|
|
throw new CanApiException((await BuildErrorMessage(response)).Error, 400);
|
|
case System.Net.HttpStatusCode.Forbidden:
|
|
throw new CanApiException((await BuildErrorMessage(response)).Error, 403);
|
|
case System.Net.HttpStatusCode.NotFound:
|
|
throw new CanApiException((await BuildErrorMessage(response)).Error, 404);
|
|
|
|
case System.Net.HttpStatusCode.InternalServerError:
|
|
throw new CanApiException((await BuildErrorMessage(response)).Error, 500);
|
|
case System.Net.HttpStatusCode.ServiceUnavailable:
|
|
throw new CanApiException((await BuildErrorMessage(response)).Error, 503);
|
|
}
|
|
response.EnsureSuccessStatusCode();
|
|
}
|
|
}
|
|
|
|
public static async Task WriteStreamToFileAsync(Stream inputStream, string filePath)
|
|
{
|
|
if (inputStream.CanSeek)
|
|
{
|
|
inputStream.Position = 0;
|
|
}
|
|
|
|
using (FileStream fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
|
|
{
|
|
await inputStream.CopyToAsync(fileStream);
|
|
}
|
|
}
|
|
}
|
|
}
|