Skip to content

Commit

Permalink
feat: implement list
Browse files Browse the repository at this point in the history
  • Loading branch information
Dovchik committed May 16, 2024
1 parent 10f8d86 commit 442cf9e
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 72 deletions.
74 changes: 37 additions & 37 deletions src/Sinch/Core/Http.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ internal interface IHttp
/// <returns></returns>
Task<TResponse> Send<TResponse>(Uri uri, HttpMethod httpMethod,
CancellationToken cancellationToken = default);

Task<TResponse> SendMultipart<TRequest, TResponse>(Uri uri, TRequest request, Stream stream, string fileName,
CancellationToken cancellationToken = default);

/// <summary>
/// Use to send http request with a body
/// </summary>
Expand All @@ -52,14 +52,14 @@ Task<TResponse> SendMultipart<TRequest, TResponse>(Uri uri, TRequest request, St
Task<TResponse> Send<TRequest, TResponse>(Uri uri, HttpMethod httpMethod, TRequest httpContent,
CancellationToken cancellationToken = default);
}

/// <summary>
/// Represents an empty response for cases where no json is expected.
/// </summary>
public class EmptyResponse
{
}

/// <inheritdoc />
internal class Http : IHttp
{
Expand All @@ -68,8 +68,8 @@ internal class Http : IHttp
private readonly ILoggerAdapter<IHttp>? _logger;
private readonly ISinchAuth _auth;
private readonly string _userAgentHeaderValue;


public Http(ISinchAuth auth, HttpClient httpClient, ILoggerAdapter<IHttp>? logger,
JsonNamingPolicy jsonNamingPolicy)
{
Expand All @@ -85,7 +85,7 @@ public Http(ISinchAuth auth, HttpClient httpClient, ILoggerAdapter<IHttp>? logge
_userAgentHeaderValue =
$"sinch-sdk/{sdkVersion} (csharp/{RuntimeInformation.FrameworkDescription};;)";
}

public Task<TResponse> SendMultipart<TRequest, TResponse>(Uri uri, TRequest request, Stream stream,
string fileName, CancellationToken cancellationToken = default)
{
Expand All @@ -100,7 +100,7 @@ public Task<TResponse> SendMultipart<TRequest, TResponse>(Uri uri, TRequest requ
{
continue;
}

var type = value.GetType();
if (type == typeof(List<string>))
{
Expand All @@ -124,7 +124,7 @@ public Task<TResponse> SendMultipart<TRequest, TResponse>(Uri uri, TRequest requ
}
}
}

stream.Position = 0;
var isContentType = new FileExtensionContentTypeProvider().TryGetContentType(fileName, out var contentType);
var streamContent = new StreamContent(stream)
Expand All @@ -135,27 +135,27 @@ public Task<TResponse> SendMultipart<TRequest, TResponse>(Uri uri, TRequest requ
}
};
content.Add(streamContent, "file", fileName);


return SendHttpContent<TResponse>(uri, HttpMethod.Post, content, cancellationToken);

bool DoesntHaveJsonIgnoreAttribute(PropertyInfo prop)
{
return !prop.GetCustomAttributes(typeof(JsonIgnoreAttribute)).Any();
}

bool HasNonNullValue(PropertyInfo x)
{
return x.GetValue(request) != null;
}
}

public Task<TResponse> Send<TResponse>(Uri uri, HttpMethod httpMethod,
CancellationToken cancellationToken = default)
{
return Send<EmptyResponse, TResponse>(uri, httpMethod, null, cancellationToken);
}

private async Task<TResponse> SendHttpContent<TResponse>(Uri uri, HttpMethod httpMethod,
HttpContent? httpContent,
CancellationToken cancellationToken = default)
Expand All @@ -164,18 +164,18 @@ private async Task<TResponse> SendHttpContent<TResponse>(Uri uri, HttpMethod htt
while (true)
{
_logger?.LogDebug("Sending request to {uri}", uri);

#if DEBUG
Debug.WriteLine($"Http Method: {httpMethod}");
Debug.WriteLine($"Request uri: {uri}");
Debug.WriteLine($"Request body: {httpContent?.ReadAsStringAsync(cancellationToken).Result}");
#endif

using var msg = new HttpRequestMessage();
msg.RequestUri = uri;
msg.Method = httpMethod;
msg.Content = httpContent;

string token;
// Due to all the additional params appSignAuth is requiring,
// it's makes sense to still keep it in Http to manage all the details.
Expand All @@ -185,13 +185,13 @@ private async Task<TResponse> SendHttpContent<TResponse>(Uri uri, HttpMethod htt
var now = DateTime.UtcNow.ToString("O", CultureInfo.InvariantCulture);
const string headerName = "x-timestamp";
msg.Headers.Add(headerName, now);

var bytes = Array.Empty<byte>();
if (msg.Content is not null)
{
bytes = await msg.Content.ReadAsByteArrayAsync(cancellationToken);
}

token = appSignAuth.GetSignedAuth(
bytes,
msg.Method.ToString().ToUpperInvariant(), msg.RequestUri.PathAndQuery,
Expand All @@ -203,13 +203,13 @@ private async Task<TResponse> SendHttpContent<TResponse>(Uri uri, HttpMethod htt
// try force get new token if retrying
token = await _auth.GetAuthToken(force: !retry);
}

msg.Headers.Authorization = new AuthenticationHeaderValue(_auth.Scheme, token);

msg.Headers.Add("User-Agent", _userAgentHeaderValue);

var result = await _httpClient.SendAsync(msg, cancellationToken);

if (result.StatusCode == HttpStatusCode.Unauthorized && retry)
{
// will not retry when no "expired" header for a token.
Expand All @@ -225,10 +225,10 @@ private async Task<TResponse> SendHttpContent<TResponse>(Uri uri, HttpMethod htt
continue;
}
}

await result.EnsureSuccessApiStatusCode(_jsonSerializerOptions);
_logger?.LogDebug("Finished processing request for {uri}", uri);

#if DEBUG
try
{
Expand All @@ -243,24 +243,24 @@ private async Task<TResponse> SendHttpContent<TResponse>(Uri uri, HttpMethod htt
Debug.WriteLine($"Failed to parse json {e.Message}");
}
#endif

// NOTE: there wil probably be other files supported in the future
if (result.IsPdf())
{
if (typeof(TResponse) != typeof(Stream))
{
throw new InvalidOperationException(
"Received pdf, but expected response type is not a Stream.");
}

return (TResponse)(object)await result.Content.ReadAsStreamAsync(cancellationToken);
}

if (result.IsJson())
return await result.Content.ReadFromJsonAsync<TResponse>(cancellationToken: cancellationToken,
options: _jsonSerializerOptions)
?? throw new InvalidOperationException(
$"{typeof(TResponse).Name} is null");

// if empty response is expected, any non related response is dropped
if (typeof(TResponse) == typeof(EmptyResponse))
{
Expand All @@ -272,29 +272,29 @@ private async Task<TResponse> SendHttpContent<TResponse>(Uri uri, HttpMethod htt
_logger?.LogDebug("Expected empty content, but got {content}",
await result.Content.ReadAsStringAsync(cancellationToken));
}

return (TResponse)(object)new EmptyResponse();
}

// unexpected content, log warning and throw exception
_logger?.LogWarning("Response is not json, but {content}",
await result.Content.ReadAsStringAsync(cancellationToken));

throw new InvalidOperationException("The response is not Json or EmptyResponse");
}
}

public async Task<TResponse> Send<TRequest, TResponse>(Uri uri, HttpMethod httpMethod, TRequest? request,
CancellationToken cancellationToken = default)
{
HttpContent? httpContent =
request == null ? null : JsonContent.Create(request, options: _jsonSerializerOptions);


return await SendHttpContent<TResponse>(uri: uri, httpMethod: httpMethod, httpContent,
cancellationToken: cancellationToken);
}

public Task<TResponse> SendMultipart<TRequest, TResponse>(Uri uri, HttpMethod httpMethod, TRequest request,
Stream stream, string fileName, CancellationToken cancellationToken = default)
{
Expand Down
5 changes: 5 additions & 0 deletions src/Sinch/Core/StringUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ public static string ToIso8601(DateTime date)
return date.ToString("O", CultureInfo.InvariantCulture);
}

public static string ToIso8601(DateOnly date)
{
return date.ToString("O", CultureInfo.InvariantCulture);
}

public static string ToIso8601NoTicks(DateTime date)
{
return date.ToString("yyyy-MM-ddTHH:mm:ssZ", CultureInfo.InvariantCulture);
Expand Down
31 changes: 18 additions & 13 deletions src/Sinch/Fax/Faxes/ListFaxesRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,23 @@ public ListFaxesRequest()
/// Filters faxes created on the specified date in UTC
/// </summary>
/// <param name="createTime"></param>
public ListFaxesRequest(DateTime createTime)
public ListFaxesRequest(DateOnly createTime)
{

CreateTime = new DateTime(createTime.Ticks, DateTimeKind.Utc);
CreateTime = createTime;
}

/// <summary>
/// Filters faxes created in a time range in UTC
/// </summary>
/// <param name="createTimeAfter"></param>
/// <param name="createTimeBefore"></param>
public ListFaxesRequest(DateTime createTimeAfter, DateTime createTimeBefore)
public ListFaxesRequest(DateTime? createTimeAfter, DateTime? createTimeBefore)
{
CreateTimeAfter = createTimeAfter;
CreateTimeBefore = createTimeBefore;
}

public DateTime? CreateTime { get; private set; }
public DateOnly? CreateTime { get; private set; }

public DateTime? CreateTimeAfter { get; private set; }

Expand All @@ -52,18 +51,24 @@ public string ToQueryString()
{
var queryString = new List<KeyValuePair<string, string>>();

if (CreateTime.HasValue)
if (CreateTime.HasValue) // mutually exclusive
{
queryString.Add(new("createTime",
StringUtils.ToIso8601NoTicks(CreateTime.Value)));
StringUtils.ToIso8601(CreateTime.Value)));
}

if (CreateTimeAfter.HasValue && CreateTimeBefore.HasValue)
else
{
queryString.Add(new("createTime>=",
StringUtils.ToIso8601(CreateTimeAfter.Value)));
queryString.Add(new("createTime<=",
StringUtils.ToIso8601(CreateTimeBefore.Value)));
if (CreateTimeAfter.HasValue)
{
queryString.Add(new("createTime>",
StringUtils.ToIso8601NoTicks(CreateTimeAfter.Value)));
}

if (CreateTimeBefore.HasValue)
{
queryString.Add(new("createTime<",
StringUtils.ToIso8601NoTicks(CreateTimeBefore.Value)));
}
}

if (Direction != null)
Expand Down
4 changes: 2 additions & 2 deletions src/Sinch/Fax/Faxes/SendFaxRequest.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Sinch.Core;
Expand Down Expand Up @@ -154,7 +153,8 @@ public ValueTask DisposeAsync()
}
}

public sealed class Base64File
/// TODO: think about if it's worth implementing base64 send
internal sealed class Base64File
{
/// <summary>
/// Base64 encoded file content.
Expand Down
Loading

0 comments on commit 442cf9e

Please sign in to comment.