Skip to content

Commit

Permalink
Move Rest classes to Management project
Browse files Browse the repository at this point in the history
  • Loading branch information
terencefan committed Sep 11, 2024
1 parent 2dff80e commit 33f0813
Show file tree
Hide file tree
Showing 15 changed files with 137 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.SignalR.Common;

namespace Microsoft.Azure.SignalR;

#nullable enable

internal partial class MicrosoftEntraAccessKey
{
internal sealed class RestApiEndpoint
{
public string Audience { get; }

public string Token { get; }

public RestApiEndpoint(string endpoint, string token)
{
Audience = endpoint;
Token = token;
}
}

internal sealed class RestClient
{
private readonly IHttpClientFactory _httpClientFactory;

public RestClient(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}

public Task SendAsync(
RestApiEndpoint api,
HttpMethod httpMethod,
Func<HttpResponseMessage, Task<bool>>? handleExpectedResponseAsync = null,
CancellationToken cancellationToken = default)
{
return SendAsyncCore(Constants.HttpClientNames.UserDefault, api, httpMethod, handleExpectedResponseAsync, cancellationToken);
}

private async Task ThrowExceptionOnResponseFailureAsync(HttpResponseMessage response)
{
if (response.IsSuccessStatusCode)
{
return;
}

var detail = await response.Content.ReadAsStringAsync();

#if NET5_0_OR_GREATER
var innerException = new HttpRequestException(
$"Response status code does not indicate success: {(int)response.StatusCode} ({response.ReasonPhrase})", null, response.StatusCode);
#else
var innerException = new HttpRequestException(
$"Response status code does not indicate success: {(int)response.StatusCode} ({response.ReasonPhrase})");
#endif
throw response.StatusCode switch
{
HttpStatusCode.BadRequest => new AzureSignalRInvalidArgumentException(response.RequestMessage?.RequestUri?.ToString(), innerException, detail),
HttpStatusCode.Unauthorized => new AzureSignalRUnauthorizedException(response.RequestMessage?.RequestUri?.ToString(), innerException),
HttpStatusCode.NotFound => new AzureSignalRInaccessibleEndpointException(response.RequestMessage?.RequestUri?.ToString(), innerException),
_ => new AzureSignalRRuntimeException(response.RequestMessage?.RequestUri?.ToString(), innerException),
};
}

private async Task SendAsyncCore(
string httpClientName,
RestApiEndpoint api,
HttpMethod httpMethod,
Func<HttpResponseMessage, Task<bool>>? handleExpectedResponseAsync = null,
CancellationToken cancellationToken = default)
{
using var httpClient = _httpClientFactory.CreateClient(httpClientName);
using var request = BuildRequest(api, httpMethod);

try
{
using var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
if (handleExpectedResponseAsync == null)
{
await ThrowExceptionOnResponseFailureAsync(response);
}
else
{
if (!await handleExpectedResponseAsync(response))
{
await ThrowExceptionOnResponseFailureAsync(response);
}
}
}
catch (HttpRequestException ex)
{
throw new AzureSignalRException($"An error happened when making request to {request.RequestUri}", ex);
}
}

private HttpRequestMessage BuildRequest(RestApiEndpoint api, HttpMethod httpMethod)
{
return GenerateHttpRequest(api.Audience, httpMethod, api.Token);
}

private HttpRequestMessage GenerateHttpRequest(string url, HttpMethod httpMethod, string tokenString)
{
var request = new HttpRequestMessage(httpMethod, new Uri(url));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokenString);
return request;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

namespace Microsoft.Azure.SignalR;

internal class MicrosoftEntraAccessKey : AccessKey
internal partial class MicrosoftEntraAccessKey : AccessKey
{
internal static readonly TimeSpan GetAccessKeyTimeout = TimeSpan.FromSeconds(100);

Expand Down Expand Up @@ -169,7 +169,7 @@ private async Task GetAccessKeyInternalAsync(string accessToken, CancellationTok
{
var api = new RestApiEndpoint(GetAccessKeyUrl, accessToken);

await new RestClient().SendAsync(
await new RestClient(HttpClientFactory.Instance).SendAsync(
api,
HttpMethod.Get,
handleExpectedResponseAsync: HandleHttpResponseAsync,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

#nullable enable

namespace Microsoft.Azure.SignalR.Common
namespace Microsoft.Azure.SignalR.Management
{
internal class BinaryPayloadContentBuilder : IPayloadContentBuilder
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using MessagePack;
using Microsoft.AspNetCore.SignalR.Protocol;

namespace Microsoft.Azure.SignalR.Common
namespace Microsoft.Azure.SignalR.Management
{
internal class BinaryPayloadMessageContent : HttpContent
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

#nullable enable

namespace Microsoft.Azure.SignalR.Common
namespace Microsoft.Azure.SignalR.Management
{
internal interface IPayloadContentBuilder
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using Azure.Core.Serialization;

#nullable enable
namespace Microsoft.Azure.SignalR.Common
namespace Microsoft.Azure.SignalR.Management
{
internal class JsonPayloadContentBuilder : IPayloadContentBuilder
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
using System.Threading.Tasks;
using Azure.Core.Serialization;

namespace Microsoft.Azure.SignalR
namespace Microsoft.Azure.SignalR.Management
{
internal class JsonPayloadMessageContent : HttpContent
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Microsoft.Azure.SignalR
namespace Microsoft.Azure.SignalR.Management
{
internal class PayloadMessage
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using System.Security.Claims;
using System.Threading.Tasks;

namespace Microsoft.Azure.SignalR
namespace Microsoft.Azure.SignalR.Management
{
internal class RestApiAccessTokenGenerator
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

using Microsoft.Extensions.Primitives;

namespace Microsoft.Azure.SignalR
namespace Microsoft.Azure.SignalR.Management
{
internal class RestApiEndpoint
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

#nullable enable

namespace Microsoft.Azure.SignalR
namespace Microsoft.Azure.SignalR.Management
{
internal class RestClient
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using MessagePack;
using Microsoft.AspNetCore.SignalR.Protocol;
using Xunit;

namespace Microsoft.Azure.SignalR.Common.Tests
namespace Microsoft.Azure.SignalR.Management.Tests
{
public class BinaryPayloadMessageContentTest
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
using System.Linq;
using System.Threading.Tasks;
using Azure.Core.Serialization;
using Microsoft.Azure.SignalR;
using Xunit;

namespace Microsoft.Azure.SignalR.Common.Tests
namespace Microsoft.Azure.SignalR.Management.Tests
{
public class JsonPayloadMessageContentTest
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
using Microsoft.Azure.SignalR.Tests;
using Xunit;

namespace Microsoft.Azure.SignalR.Management.Tests
namespace Microsoft.Azure.SignalR.Management.Tests.Rest
{
public class RestApiProviderFacts
{
Expand All @@ -25,7 +25,7 @@ internal async Task RestApiTest(Task<RestApiEndpoint> task, string expectedAudie
{
var api = await task;
var token = JwtTokenHelper.JwtHandler.ReadJwtToken(api.Token);
string expectedTokenString = JwtTokenHelper.GenerateExpectedAccessToken(token, expectedAudience, _accessKey);
var expectedTokenString = JwtTokenHelper.GenerateExpectedAccessToken(token, expectedAudience, _accessKey);

Assert.Equal(expectedAudience, api.Audience);
Assert.Equal(expectedTokenString, api.Token);
Expand All @@ -45,8 +45,8 @@ from pair in GetTestDataByContext(context)

private static IEnumerable<object[]> GetTestDataByContext((string appName, string hubName, string userId, string groupName, string connectionId) context)
{
string commonEndpoint = $"{_endpoint}/api/hubs/{Uri.EscapeDataString(context.hubName.ToLowerInvariant())}";
string commonQueryString = $"application={Uri.EscapeDataString(context.appName.ToLowerInvariant())}&api-version=2022-06-01";
var commonEndpoint = $"{_endpoint}/api/hubs/{Uri.EscapeDataString(context.hubName.ToLowerInvariant())}";
var commonQueryString = $"application={Uri.EscapeDataString(context.appName.ToLowerInvariant())}&api-version=2022-06-01";
yield return new object[] { _restApiProvider.GetBroadcastEndpointAsync(context.appName, context.hubName), $"{commonEndpoint}/:send?{commonQueryString}" };
yield return new object[] { _restApiProvider.GetSendToUserEndpointAsync(context.appName, context.hubName, context.userId), $"{commonEndpoint}/users/{Uri.EscapeDataString(context.userId)}/:send?{commonQueryString}" };
yield return new object[] { _restApiProvider.GetSendToGroupEndpointAsync(context.appName, context.hubName, context.groupName), $"{commonEndpoint}/groups/{Uri.EscapeDataString(context.groupName)}/:send?{commonQueryString}" };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.SignalR.Common;
using Microsoft.Azure.SignalR.Tests.Common;
using Microsoft.Extensions.DependencyInjection;
using Xunit;

namespace Microsoft.Azure.SignalR.Common.Tests.RestClients
namespace Microsoft.Azure.SignalR.Management.Tests.Rest
{
public class RestClientFacts
{
Expand Down

0 comments on commit 33f0813

Please sign in to comment.