diff --git a/sdk/webpubsub/Azure.Messaging.WebPubSub/api/Azure.Messaging.WebPubSub.netstandard2.0.cs b/sdk/webpubsub/Azure.Messaging.WebPubSub/api/Azure.Messaging.WebPubSub.netstandard2.0.cs index 94563ad6befa..9c5fa0c04310 100644 --- a/sdk/webpubsub/Azure.Messaging.WebPubSub/api/Azure.Messaging.WebPubSub.netstandard2.0.cs +++ b/sdk/webpubsub/Azure.Messaging.WebPubSub/api/Azure.Messaging.WebPubSub.netstandard2.0.cs @@ -19,43 +19,44 @@ public WebPubSubServiceClient(System.Uri endpoint, string hub, Azure.AzureKeyCre public virtual System.Threading.Tasks.Task AddConnectionToGroupAsync(string group, string connectionId, Azure.RequestOptions requestOptions = null) { throw null; } public virtual Azure.Response AddUserToGroup(string group, string userId, Azure.RequestOptions requestOptions = null) { throw null; } public virtual System.Threading.Tasks.Task AddUserToGroupAsync(string group, string userId, Azure.RequestOptions requestOptions = null) { throw null; } - public virtual Azure.Response CheckPermission(Azure.Messaging.WebPubSub.WebPubSubPermission permission, string connectionId, string targetName = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } - public virtual System.Threading.Tasks.Task CheckPermissionAsync(Azure.Messaging.WebPubSub.WebPubSubPermission permission, string connectionId, string targetName = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response CheckPermission(Azure.Messaging.WebPubSub.WebPubSubPermission permission, string connectionId, string targetName = null, Azure.RequestOptions options = null) { throw null; } + public virtual System.Threading.Tasks.Task> CheckPermissionAsync(Azure.Messaging.WebPubSub.WebPubSubPermission permission, string connectionId, string targetName = null, Azure.RequestOptions options = null) { throw null; } public virtual Azure.Response CloseClientConnection(string connectionId, string reason = null, Azure.RequestOptions requestOptions = null) { throw null; } public virtual System.Threading.Tasks.Task CloseClientConnectionAsync(string connectionId, string reason = null, Azure.RequestOptions requestOptions = null) { throw null; } - public virtual Azure.Response ConnectionExists(string connectionId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } - public virtual System.Threading.Tasks.Task> ConnectionExistsAsync(string connectionId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } - public virtual System.Uri GenerateClientAccessUri(string userId = null, string[] roles = null, System.TimeSpan expiresAfter = default(System.TimeSpan)) { throw null; } - public virtual Azure.Response GrantPermission(Azure.Messaging.WebPubSub.WebPubSubPermission permission, string connectionId, string targetName = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } - public virtual System.Threading.Tasks.Task GrantPermissionAsync(Azure.Messaging.WebPubSub.WebPubSubPermission permission, string connectionId, string targetName = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } - public virtual Azure.Response GroupExists(string group, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } - public virtual System.Threading.Tasks.Task> GroupExistsAsync(string group, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response ConnectionExists(string connectionId, Azure.RequestOptions options = null) { throw null; } + public virtual System.Threading.Tasks.Task> ConnectionExistsAsync(string connectionId, Azure.RequestOptions options = null) { throw null; } + public virtual System.Uri GenerateClientAccessUri(System.DateTime expiresAtUtc, string userId = null, params string[] roles) { throw null; } + public virtual System.Uri GenerateClientAccessUri(System.TimeSpan expiresAfter = default(System.TimeSpan), string userId = null, params string[] roles) { throw null; } + public virtual Azure.Response GrantPermission(Azure.Messaging.WebPubSub.WebPubSubPermission permission, string connectionId, string targetName = null, Azure.RequestOptions options = null) { throw null; } + public virtual System.Threading.Tasks.Task GrantPermissionAsync(Azure.Messaging.WebPubSub.WebPubSubPermission permission, string connectionId, string targetName = null, Azure.RequestOptions options = null) { throw null; } + public virtual Azure.Response GroupExists(string group, Azure.RequestOptions options = null) { throw null; } + public virtual System.Threading.Tasks.Task> GroupExistsAsync(string group, Azure.RequestOptions options = null) { throw null; } public virtual Azure.Response RemoveConnectionFromGroup(string group, string connectionId, Azure.RequestOptions requestOptions = null) { throw null; } public virtual System.Threading.Tasks.Task RemoveConnectionFromGroupAsync(string group, string connectionId, Azure.RequestOptions requestOptions = null) { throw null; } public virtual Azure.Response RemoveUserFromAllGroups(string userId, Azure.RequestOptions requestOptions = null) { throw null; } public virtual System.Threading.Tasks.Task RemoveUserFromAllGroupsAsync(string userId, Azure.RequestOptions requestOptions = null) { throw null; } public virtual Azure.Response RemoveUserFromGroup(string group, string userId, Azure.RequestOptions requestOptions = null) { throw null; } public virtual System.Threading.Tasks.Task RemoveUserFromGroupAsync(string group, string userId, Azure.RequestOptions requestOptions = null) { throw null; } - public virtual Azure.Response RevokePermission(Azure.Messaging.WebPubSub.WebPubSubPermission permission, string connectionId, string targetName = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } - public virtual System.Threading.Tasks.Task RevokePermissionAsync(Azure.Messaging.WebPubSub.WebPubSubPermission permission, string connectionId, string targetName = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response RevokePermission(Azure.Messaging.WebPubSub.WebPubSubPermission permission, string connectionId, string targetName = null, Azure.RequestOptions options = null) { throw null; } + public virtual System.Threading.Tasks.Task RevokePermissionAsync(Azure.Messaging.WebPubSub.WebPubSubPermission permission, string connectionId, string targetName = null, Azure.RequestOptions options = null) { throw null; } + public virtual Azure.Response SendToAll(string content, Azure.Core.ContentType contentType = default(Azure.Core.ContentType)) { throw null; } public virtual Azure.Response SendToAll(string contentType, Azure.Core.RequestContent requestBody, System.Collections.Generic.IEnumerable excluded = null, Azure.RequestOptions requestOptions = null) { throw null; } - public virtual Azure.Response SendToAll(string message, System.Collections.Generic.IEnumerable excluded = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task SendToAllAsync(string content, Azure.Core.ContentType contentType = default(Azure.Core.ContentType)) { throw null; } public virtual System.Threading.Tasks.Task SendToAllAsync(string contentType, Azure.Core.RequestContent requestBody, System.Collections.Generic.IEnumerable excluded = null, Azure.RequestOptions requestOptions = null) { throw null; } - public virtual System.Threading.Tasks.Task SendToAllAsync(string message, System.Collections.Generic.IEnumerable excluded = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response SendToConnection(string connectionId, string content, Azure.Core.ContentType contentType = default(Azure.Core.ContentType)) { throw null; } public virtual Azure.Response SendToConnection(string connectionId, string contentType, Azure.Core.RequestContent requestBody, Azure.RequestOptions requestOptions = null) { throw null; } - public virtual Azure.Response SendToConnection(string connectionId, string message, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task SendToConnectionAsync(string connectionId, string content, Azure.Core.ContentType contentType = default(Azure.Core.ContentType)) { throw null; } public virtual System.Threading.Tasks.Task SendToConnectionAsync(string connectionId, string contentType, Azure.Core.RequestContent requestBody, Azure.RequestOptions requestOptions = null) { throw null; } - public virtual System.Threading.Tasks.Task SendToConnectionAsync(string connectionId, string message, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response SendToGroup(string group, string content, Azure.Core.ContentType contentType = default(Azure.Core.ContentType)) { throw null; } public virtual Azure.Response SendToGroup(string group, string contentType, Azure.Core.RequestContent requestBody, System.Collections.Generic.IEnumerable excluded = null, Azure.RequestOptions requestOptions = null) { throw null; } - public virtual Azure.Response SendToGroup(string group, string message, System.Collections.Generic.IEnumerable excluded = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task SendToGroupAsync(string group, string content, Azure.Core.ContentType contentType = default(Azure.Core.ContentType)) { throw null; } public virtual System.Threading.Tasks.Task SendToGroupAsync(string group, string contentType, Azure.Core.RequestContent requestBody, System.Collections.Generic.IEnumerable excluded = null, Azure.RequestOptions requestOptions = null) { throw null; } - public virtual System.Threading.Tasks.Task SendToGroupAsync(string group, string message, System.Collections.Generic.IEnumerable excluded = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response SendToUser(string userId, string content, Azure.Core.ContentType contentType = default(Azure.Core.ContentType)) { throw null; } public virtual Azure.Response SendToUser(string userId, string contentType, Azure.Core.RequestContent requestBody, Azure.RequestOptions requestOptions = null) { throw null; } - public virtual Azure.Response SendToUser(string userId, string message, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task SendToUserAsync(string userId, string content, Azure.Core.ContentType contentType = default(Azure.Core.ContentType)) { throw null; } public virtual System.Threading.Tasks.Task SendToUserAsync(string userId, string contentType, Azure.Core.RequestContent requestBody, Azure.RequestOptions requestOptions = null) { throw null; } - public virtual System.Threading.Tasks.Task SendToUserAsync(string userId, string message, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } - public virtual Azure.Response UserExists(string userId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } - public virtual System.Threading.Tasks.Task> UserExistsAsync(string userId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response UserExists(string userId, Azure.RequestOptions options = null) { throw null; } + public virtual System.Threading.Tasks.Task> UserExistsAsync(string userId, Azure.RequestOptions options = null) { throw null; } } public partial class WebPubSubServiceClientOptions : Azure.Core.ClientOptions { diff --git a/sdk/webpubsub/Azure.Messaging.WebPubSub/src/Generated/WebPubSubServiceClient.cs b/sdk/webpubsub/Azure.Messaging.WebPubSub/src/Generated/WebPubSubServiceClient.cs index 2df95503c458..9dae6c00ef54 100644 --- a/sdk/webpubsub/Azure.Messaging.WebPubSub/src/Generated/WebPubSubServiceClient.cs +++ b/sdk/webpubsub/Azure.Messaging.WebPubSub/src/Generated/WebPubSubServiceClient.cs @@ -146,16 +146,16 @@ private HttpMessage CreateSendToAllRequest(string contentType, RequestContent re /// The connection Id. /// The request options. #pragma warning disable AZC0002 - internal virtual async Task ConnectionExistsAsync(string connectionId, RequestOptions requestOptions = null) + internal virtual async Task ConnectionExistsImplAsync(string connectionId, RequestOptions requestOptions = null) #pragma warning restore AZC0002 { requestOptions ??= new RequestOptions(); - HttpMessage message = CreateConnectionExistsRequest(connectionId, requestOptions); + HttpMessage message = CreateConnectionExistsImplRequest(connectionId, requestOptions); if (requestOptions.PerCallPolicy != null) { message.SetProperty("RequestOptionsPerCallPolicyCallback", requestOptions.PerCallPolicy); } - using var scope = _clientDiagnostics.CreateScope("WebPubSubServiceClient.ConnectionExists"); + using var scope = _clientDiagnostics.CreateScope("WebPubSubServiceClient.ConnectionExistsImpl"); scope.Start(); try { @@ -187,16 +187,16 @@ internal virtual async Task ConnectionExistsAsync(string connectionId, /// The connection Id. /// The request options. #pragma warning disable AZC0002 - internal virtual Response ConnectionExists(string connectionId, RequestOptions requestOptions = null) + internal virtual Response ConnectionExistsImpl(string connectionId, RequestOptions requestOptions = null) #pragma warning restore AZC0002 { requestOptions ??= new RequestOptions(); - HttpMessage message = CreateConnectionExistsRequest(connectionId, requestOptions); + HttpMessage message = CreateConnectionExistsImplRequest(connectionId, requestOptions); if (requestOptions.PerCallPolicy != null) { message.SetProperty("RequestOptionsPerCallPolicyCallback", requestOptions.PerCallPolicy); } - using var scope = _clientDiagnostics.CreateScope("WebPubSubServiceClient.ConnectionExists"); + using var scope = _clientDiagnostics.CreateScope("WebPubSubServiceClient.ConnectionExistsImpl"); scope.Start(); try { @@ -224,10 +224,10 @@ internal virtual Response ConnectionExists(string connectionId, RequestOptions r } } - /// Create Request for and operations. + /// Create Request for and operations. /// The connection Id. /// The request options. - private HttpMessage CreateConnectionExistsRequest(string connectionId, RequestOptions requestOptions = null) + private HttpMessage CreateConnectionExistsImplRequest(string connectionId, RequestOptions requestOptions = null) { var message = Pipeline.CreateMessage(); var request = message.Request; @@ -470,16 +470,16 @@ private HttpMessage CreateSendToConnectionRequest(string connectionId, string co /// Target group name, which length should be greater than 0 and less than 1025. /// The request options. #pragma warning disable AZC0002 - internal virtual async Task GroupExistsAsync(string group, RequestOptions requestOptions = null) + internal virtual async Task GroupExistsImplAsync(string group, RequestOptions requestOptions = null) #pragma warning restore AZC0002 { requestOptions ??= new RequestOptions(); - HttpMessage message = CreateGroupExistsRequest(group, requestOptions); + HttpMessage message = CreateGroupExistsImplRequest(group, requestOptions); if (requestOptions.PerCallPolicy != null) { message.SetProperty("RequestOptionsPerCallPolicyCallback", requestOptions.PerCallPolicy); } - using var scope = _clientDiagnostics.CreateScope("WebPubSubServiceClient.GroupExists"); + using var scope = _clientDiagnostics.CreateScope("WebPubSubServiceClient.GroupExistsImpl"); scope.Start(); try { @@ -511,16 +511,16 @@ internal virtual async Task GroupExistsAsync(string group, RequestOpti /// Target group name, which length should be greater than 0 and less than 1025. /// The request options. #pragma warning disable AZC0002 - internal virtual Response GroupExists(string group, RequestOptions requestOptions = null) + internal virtual Response GroupExistsImpl(string group, RequestOptions requestOptions = null) #pragma warning restore AZC0002 { requestOptions ??= new RequestOptions(); - HttpMessage message = CreateGroupExistsRequest(group, requestOptions); + HttpMessage message = CreateGroupExistsImplRequest(group, requestOptions); if (requestOptions.PerCallPolicy != null) { message.SetProperty("RequestOptionsPerCallPolicyCallback", requestOptions.PerCallPolicy); } - using var scope = _clientDiagnostics.CreateScope("WebPubSubServiceClient.GroupExists"); + using var scope = _clientDiagnostics.CreateScope("WebPubSubServiceClient.GroupExistsImpl"); scope.Start(); try { @@ -548,10 +548,10 @@ internal virtual Response GroupExists(string group, RequestOptions requestOption } } - /// Create Request for and operations. + /// Create Request for and operations. /// Target group name, which length should be greater than 0 and less than 1025. /// The request options. - private HttpMessage CreateGroupExistsRequest(string group, RequestOptions requestOptions = null) + private HttpMessage CreateGroupExistsImplRequest(string group, RequestOptions requestOptions = null) { var message = Pipeline.CreateMessage(); var request = message.Request; @@ -908,16 +908,16 @@ private HttpMessage CreateRemoveConnectionFromGroupRequest(string group, string /// Target user Id. /// The request options. #pragma warning disable AZC0002 - internal virtual async Task UserExistsAsync(string userId, RequestOptions requestOptions = null) + internal virtual async Task UserExistsImplAsync(string userId, RequestOptions requestOptions = null) #pragma warning restore AZC0002 { requestOptions ??= new RequestOptions(); - HttpMessage message = CreateUserExistsRequest(userId, requestOptions); + HttpMessage message = CreateUserExistsImplRequest(userId, requestOptions); if (requestOptions.PerCallPolicy != null) { message.SetProperty("RequestOptionsPerCallPolicyCallback", requestOptions.PerCallPolicy); } - using var scope = _clientDiagnostics.CreateScope("WebPubSubServiceClient.UserExists"); + using var scope = _clientDiagnostics.CreateScope("WebPubSubServiceClient.UserExistsImpl"); scope.Start(); try { @@ -949,16 +949,16 @@ internal virtual async Task UserExistsAsync(string userId, RequestOpti /// Target user Id. /// The request options. #pragma warning disable AZC0002 - internal virtual Response UserExists(string userId, RequestOptions requestOptions = null) + internal virtual Response UserExistsImpl(string userId, RequestOptions requestOptions = null) #pragma warning restore AZC0002 { requestOptions ??= new RequestOptions(); - HttpMessage message = CreateUserExistsRequest(userId, requestOptions); + HttpMessage message = CreateUserExistsImplRequest(userId, requestOptions); if (requestOptions.PerCallPolicy != null) { message.SetProperty("RequestOptionsPerCallPolicyCallback", requestOptions.PerCallPolicy); } - using var scope = _clientDiagnostics.CreateScope("WebPubSubServiceClient.UserExists"); + using var scope = _clientDiagnostics.CreateScope("WebPubSubServiceClient.UserExistsImpl"); scope.Start(); try { @@ -986,10 +986,10 @@ internal virtual Response UserExists(string userId, RequestOptions requestOption } } - /// Create Request for and operations. + /// Create Request for and operations. /// Target user Id. /// The request options. - private HttpMessage CreateUserExistsRequest(string userId, RequestOptions requestOptions = null) + private HttpMessage CreateUserExistsImplRequest(string userId, RequestOptions requestOptions = null) { var message = Pipeline.CreateMessage(); var request = message.Request; diff --git a/sdk/webpubsub/Azure.Messaging.WebPubSub/src/GlobalSuppressions.cs b/sdk/webpubsub/Azure.Messaging.WebPubSub/src/GlobalSuppressions.cs new file mode 100644 index 000000000000..b6f456d951a1 --- /dev/null +++ b/sdk/webpubsub/Azure.Messaging.WebPubSub/src/GlobalSuppressions.cs @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Usage", "AZC0002:DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken.", Justification = "CancellationToken can be passed through RequestOptions")] diff --git a/sdk/webpubsub/Azure.Messaging.WebPubSub/src/WebPubSubAuthenticationPolicy.cs b/sdk/webpubsub/Azure.Messaging.WebPubSub/src/WebPubSubAuthenticationPolicy.cs index 148c59bc6b2a..817b32fbd056 100644 --- a/sdk/webpubsub/Azure.Messaging.WebPubSub/src/WebPubSubAuthenticationPolicy.cs +++ b/sdk/webpubsub/Azure.Messaging.WebPubSub/src/WebPubSubAuthenticationPolicy.cs @@ -26,7 +26,9 @@ internal partial class WebPubSubAuthenticationPolicy : HttpPipelineSynchronousPo public override void OnSendingRequest(HttpMessage message) { string audience = message.Request.Uri.ToUri().AbsoluteUri; - string accessToken = JwtUtils.GenerateJwtBearer(audience, claims: null, expiresAfter: TimeSpan.FromMinutes(10), _credential); + var expiresAt = DateTime.UtcNow + TimeSpan.FromMinutes(10); + + string accessToken = JwtUtils.GenerateJwtBearer(audience, claims: null, expiresAt, _credential); var header = new AuthenticationHeaderValue("Bearer", accessToken); message.Request.Headers.SetValue(HttpHeader.Names.Authorization, header.ToString()); diff --git a/sdk/webpubsub/Azure.Messaging.WebPubSub/src/WebPubSubAuthenticationPolicy_token.cs b/sdk/webpubsub/Azure.Messaging.WebPubSub/src/WebPubSubAuthenticationPolicy_token.cs index 1e70fc689e36..9787aa2d7980 100644 --- a/sdk/webpubsub/Azure.Messaging.WebPubSub/src/WebPubSubAuthenticationPolicy_token.cs +++ b/sdk/webpubsub/Azure.Messaging.WebPubSub/src/WebPubSubAuthenticationPolicy_token.cs @@ -26,22 +26,23 @@ internal partial class WebPubSubAuthenticationPolicy : HttpPipelineSynchronousPo /// /// /// - /// + /// DateTime.Kind must be DateTimeKind.Utc. /// SHA512 if true, otherwise SHA256 /// public static string GenerateAccessToken( string audience, IEnumerable claims, AzureKeyCredential key, - TimeSpan expireAfter = default, + DateTime expiresAtUtc = default, bool hmacSha512 = false) { - if (expireAfter == default) expireAfter = TimeSpan.FromMinutes(10); + if (expiresAtUtc.Kind != DateTimeKind.Utc) + throw new ArgumentOutOfRangeException(nameof(expiresAtUtc)); var jwtToken = JwtUtils.GenerateJwtBearer( audience: audience, claims: claims, - expiresAfter: expireAfter, + expiresAt: expiresAtUtc, key: key, hmacSha512: hmacSha512 ); @@ -59,13 +60,11 @@ private static class JwtUtils public static string GenerateJwtBearer( string audience, IEnumerable claims, - TimeSpan expiresAfter, + DateTime expiresAt, AzureKeyCredential key, string issuer = null, bool hmacSha512 = false) { - var expiresAt = DateTime.UtcNow.Add(expiresAfter); - var subject = claims == null ? null : new ClaimsIdentity(claims); SigningCredentials credentials = null; if (key != null) diff --git a/sdk/webpubsub/Azure.Messaging.WebPubSub/src/WebPubSubServiceClient_extensions.cs b/sdk/webpubsub/Azure.Messaging.WebPubSub/src/WebPubSubServiceClient_extensions.cs index 365a0d23eca9..d0078826d588 100644 --- a/sdk/webpubsub/Azure.Messaging.WebPubSub/src/WebPubSubServiceClient_extensions.cs +++ b/sdk/webpubsub/Azure.Messaging.WebPubSub/src/WebPubSubServiceClient_extensions.cs @@ -19,8 +19,6 @@ public partial class WebPubSubServiceClient { private AzureKeyCredential _credential; - private const string JsonContent = "application/json"; - /// /// The hub. /// @@ -98,188 +96,184 @@ private WebPubSubServiceClient((Uri Endpoint, AzureKeyCredential Credential) par } /// Broadcast message to all the connected client connections. - /// - /// Excluded connection Ids. - /// The cancellation token to use. + /// + /// Defaults to ContentType.PlainText. /// A if successful. - public virtual async Task SendToAllAsync(string message, IEnumerable excluded = null, CancellationToken cancellationToken = default) + public virtual async Task SendToAllAsync(string content, ContentType contentType = default) { - RequestOptions options = default; - if (cancellationToken != default) - options = new RequestOptions() { CancellationToken = cancellationToken }; + Argument.AssertNotNull(content, nameof(content)); + + if (contentType == default) contentType = ContentType.TextPlain; - return await SendToAllAsync(JsonContent, RequestContent.Create((object)message), excluded, options).ConfigureAwait(false); + return await SendToAllAsync(contentType.ToString(), RequestContent.Create(content), default, requestOptions: default).ConfigureAwait(false); } /// Broadcast message to all the connected client connections. - /// - /// Excluded connection Ids. - /// The cancellation token to use. + /// + /// Defaults to ContentType.PlainText. /// A if successful. - public virtual Response SendToAll(string message, IEnumerable excluded = null, CancellationToken cancellationToken = default) + public virtual Response SendToAll(string content, ContentType contentType = default) { - RequestOptions options = default; - if (cancellationToken != default) - options = new RequestOptions() { CancellationToken = cancellationToken }; + Argument.AssertNotNull(content, nameof(content)); + + if (contentType == default) contentType = ContentType.TextPlain; - return SendToAll(JsonContent, RequestContent.Create((object)message), excluded, options); + return SendToAll(contentType.ToString(), RequestContent.Create(content), excluded: default, requestOptions: default); } /// /// Send message to the specific user. /// /// The user Id. - /// - /// + /// + /// Defaults to ContentType.PlainText. /// A if successful. - public virtual async Task SendToUserAsync(string userId, string message, CancellationToken cancellationToken = default) + public virtual async Task SendToUserAsync(string userId, string content, ContentType contentType = default) { - RequestOptions options = default; - if (cancellationToken != default) - options = new RequestOptions() { CancellationToken = cancellationToken }; + Argument.AssertNotNull(userId, nameof(userId)); + Argument.AssertNotNull(content, nameof(content)); - return await SendToUserAsync(userId, JsonContent, RequestContent.Create((object)message), options).ConfigureAwait(false); + if (contentType == default) contentType = ContentType.TextPlain; + + return await SendToUserAsync(userId, contentType.ToString(), RequestContent.Create(content), requestOptions: default).ConfigureAwait(false); } /// /// Send message to the specific user. /// /// The user Id. - /// - /// + /// + /// Defaults to ContentType.PlainText. /// A if successful. - public virtual Response SendToUser(string userId, string message, CancellationToken cancellationToken = default) + public virtual Response SendToUser(string userId, string content, ContentType contentType = default) { - RequestOptions options = default; - if (cancellationToken != default) - options = new RequestOptions() { CancellationToken = cancellationToken }; + Argument.AssertNotNull(userId, nameof(userId)); + Argument.AssertNotNull(content, nameof(content)); + + if (contentType == default) contentType = ContentType.TextPlain; - return SendToUser(userId, JsonContent, RequestContent.Create((object)message), options); + return SendToUser(userId, contentType.ToString(), RequestContent.Create(content), requestOptions: default); } /// /// Send message to the specific connection. /// /// The connection Id. - /// - /// + /// + /// Defaults to ContentType.PlainText. /// A if successful. - public virtual async Task SendToConnectionAsync(string connectionId, string message, CancellationToken cancellationToken = default) + public virtual async Task SendToConnectionAsync(string connectionId, string content, ContentType contentType = default) { - RequestOptions options = default; - if (cancellationToken != default) - options = new RequestOptions() { CancellationToken = cancellationToken }; + Argument.AssertNotNull(connectionId, nameof(connectionId)); + Argument.AssertNotNull(content, nameof(content)); + + if (contentType == default) contentType = ContentType.TextPlain; - return await SendToConnectionAsync(connectionId, JsonContent, RequestContent.Create((object)message), options).ConfigureAwait(false); + return await SendToConnectionAsync(connectionId, contentType.ToString(), RequestContent.Create(content), requestOptions: default).ConfigureAwait(false); } /// /// Send message to the specific connection. /// /// The connection Id. - /// - /// + /// + /// Defaults to ContentType.PlainText. /// A if successful. - public virtual Response SendToConnection(string connectionId, string message, CancellationToken cancellationToken = default) + public virtual Response SendToConnection(string connectionId, string content, ContentType contentType = default) { - RequestOptions options = default; - if (cancellationToken != default) - options = new RequestOptions() { CancellationToken = cancellationToken }; + Argument.AssertNotNull(connectionId, nameof(connectionId)); + Argument.AssertNotNull(content, nameof(content)); - return SendToConnection(connectionId, JsonContent, RequestContent.Create((object)message), options); + if (contentType == default) contentType = ContentType.TextPlain; + + return SendToConnection(connectionId, contentType.ToString(), RequestContent.Create(content), requestOptions: default); } /// /// Send message to a group of connections. /// /// Target group name, which length should be greater than 0 and less than 1025. - /// - /// Excluded connection Ids - /// + /// + /// Defaults to ContentType.PlainText. /// A if successful. - public virtual async Task SendToGroupAsync(string group, string message, IEnumerable excluded = null, CancellationToken cancellationToken = default) + public virtual async Task SendToGroupAsync(string group, string content, ContentType contentType = default) { - RequestOptions options = default; - if (cancellationToken != default) - options = new RequestOptions() { CancellationToken = cancellationToken }; + Argument.AssertNotNull(group, nameof(group)); + Argument.AssertNotNull(content, nameof(content)); + + if (contentType == default) contentType = ContentType.TextPlain; - return await SendToGroupAsync(group, JsonContent, RequestContent.Create((object)message), excluded, options).ConfigureAwait(false); + return await SendToGroupAsync(group, contentType.ToString(), RequestContent.Create(content), excluded : default, requestOptions: default).ConfigureAwait(false); } /// /// Send message to a group of connections. /// /// Target group name, which length should be greater than 0 and less than 1025. - /// - /// Excluded connection Ids - /// + /// + /// Defaults to ContentType.PlainText. /// A if successful. - public virtual Response SendToGroup(string group, string message, IEnumerable excluded = null, CancellationToken cancellationToken = default) + public virtual Response SendToGroup(string group, string content, ContentType contentType = default) { - RequestOptions options = default; - if (cancellationToken != default) - options = new RequestOptions() { CancellationToken = cancellationToken }; + Argument.AssertNotNull(group, nameof(group)); + Argument.AssertNotNull(content, nameof(content)); + + if (contentType == default) contentType = ContentType.TextPlain; - return SendToGroup(group, JsonContent, RequestContent.Create((object)message), excluded, options); + return SendToGroup(group, contentType.ToString(), RequestContent.Create(content), excluded : default, requestOptions: default); } /// Check if there are any client connections inside the given group. /// Target group name, which length should be greater than 0 and less than 1025. - /// The cancellation token to use. - public virtual async Task> GroupExistsAsync(string group, CancellationToken cancellationToken = default) + /// Options specifying the cancellation token, controlling error reporting, etc. + public virtual async Task> GroupExistsAsync(string group, RequestOptions options = default) { - var options = new RequestOptions() { StatusOption = ResponseStatusOption.NoThrow, CancellationToken = cancellationToken }; - var response = await GroupExistsAsync(group, options).ConfigureAwait(false); + var response = await GroupExistsImplAsync(group, options).ConfigureAwait(false); return Response.FromValue(response.Status == 200, response); } /// Check if there are any client connections inside the given group. /// Target group name, which length should be greater than 0 and less than 1025. - /// The cancellation token to use. - public virtual Response GroupExists(string group, CancellationToken cancellationToken = default) + /// Options specifying the cancellation token, controlling error reporting, etc. + public virtual Response GroupExists(string group, RequestOptions options = default) { - var options = new RequestOptions() { StatusOption = ResponseStatusOption.NoThrow, CancellationToken = cancellationToken }; - var response = GroupExists(group, options); + var response = GroupExistsImpl(group, options); return Response.FromValue(response.Status == 200, response); } /// Check if there are any client connections connected for the given user. /// Target user Id. - /// The cancellation token to use. - public virtual async Task> UserExistsAsync(string userId, CancellationToken cancellationToken = default) + /// Options specifying the cancellation token, controlling error reporting, etc. + public virtual async Task> UserExistsAsync(string userId, RequestOptions options = default) { - var options = new RequestOptions() { StatusOption = ResponseStatusOption.NoThrow, CancellationToken = cancellationToken }; - var response = await UserExistsAsync(userId, options).ConfigureAwait(false); + var response = await UserExistsImplAsync(userId, options).ConfigureAwait(false); return Response.FromValue(response.Status == 200, response); } /// Check if there are any client connections connected for the given user. /// Target user Id. - /// The cancellation token to use. - public virtual Response UserExists(string userId, CancellationToken cancellationToken = default) + /// Options specifying the cancellation token, controlling error reporting, etc. + public virtual Response UserExists(string userId, RequestOptions options = default) { - var options = new RequestOptions() { StatusOption = ResponseStatusOption.NoThrow, CancellationToken = cancellationToken }; - var response = UserExists(userId, options); + var response = UserExistsImpl(userId, options); return Response.FromValue(response.Status == 200, response); } /// Check if the connection with the given connectionId exists. /// The connection Id. - /// The cancellation token to use. - public virtual async Task> ConnectionExistsAsync(string connectionId, CancellationToken cancellationToken = default) + /// Options specifying the cancellation token, controlling error reporting, etc. + public virtual async Task> ConnectionExistsAsync(string connectionId, RequestOptions options = default) { - var options = new RequestOptions() { StatusOption = ResponseStatusOption.NoThrow, CancellationToken = cancellationToken }; - var response = await ConnectionExistsAsync(connectionId, options).ConfigureAwait(false); + var response = await ConnectionExistsImplAsync(connectionId, options).ConfigureAwait(false); return Response.FromValue(response.Status == 200, response); } /// Check if the connection with the given connectionId exists. /// The connection Id. - /// The cancellation token to use. - public virtual Response ConnectionExists(string connectionId, CancellationToken cancellationToken = default) + /// Options specifying the cancellation token, controlling error reporting, etc. + public virtual Response ConnectionExists(string connectionId, RequestOptions options = default) { - var options = new RequestOptions() { StatusOption = ResponseStatusOption.NoThrow, CancellationToken = cancellationToken }; - var response = ConnectionExists(connectionId, options); + var response = ConnectionExistsImpl(connectionId, options); return Response.FromValue(response.Status == 200, response); } @@ -287,11 +281,10 @@ public virtual Response ConnectionExists(string connectionId, Cancellation /// The permission: current supported actions are joinLeaveGroup and sendToGroup. /// Target connection Id. /// Optional. If not set, grant the permission to all the targets. If set, grant the permission to the specific target. The meaning of the target depends on the specific permission. - /// The cancellation token to use. - public virtual async Task GrantPermissionAsync(WebPubSubPermission permission, string connectionId, string targetName = null, CancellationToken cancellationToken = default) + /// Options specifying the cancellation token, controlling error reporting, etc. + public virtual async Task GrantPermissionAsync(WebPubSubPermission permission, string connectionId, string targetName = null, RequestOptions options = default) { - var options = new RequestOptions() { StatusOption = ResponseStatusOption.NoThrow, CancellationToken = cancellationToken }; - var response = await GrantPermissionAsync(permission.ToString(), connectionId, targetName, options).ConfigureAwait(false); + var response = await GrantPermissionAsync(PermissionToString(permission), connectionId, targetName, options).ConfigureAwait(false); return response; } @@ -299,11 +292,10 @@ public virtual async Task GrantPermissionAsync(WebPubSubPermission per /// The permission: current supported actions are joinLeaveGroup and sendToGroup. /// Target connection Id. /// Optional. If not set, grant the permission to all the targets. If set, grant the permission to the specific target. The meaning of the target depends on the specific permission. - /// The cancellation token to use. - public virtual Response GrantPermission(WebPubSubPermission permission, string connectionId, string targetName = null, CancellationToken cancellationToken = default) + /// Options specifying the cancellation token, controlling error reporting, etc. + public virtual Response GrantPermission(WebPubSubPermission permission, string connectionId, string targetName = null, RequestOptions options = default) { - var options = new RequestOptions() { StatusOption = ResponseStatusOption.NoThrow, CancellationToken = cancellationToken }; - var response = GrantPermission(permission.ToString(), connectionId, targetName, options); + var response = GrantPermission(PermissionToString(permission), connectionId, targetName, options); return response; } @@ -311,11 +303,10 @@ public virtual Response GrantPermission(WebPubSubPermission permission, string c /// The permission: current supported actions are joinLeaveGroup and sendToGroup. /// Target connection Id. /// Optional. If not set, revoke the permission for all targets. If set, revoke the permission for the specific target. The meaning of the target depends on the specific permission. - /// The cancellation token to use. - public virtual async Task RevokePermissionAsync(WebPubSubPermission permission, string connectionId, string targetName = null, CancellationToken cancellationToken = default) + /// Options specifying the cancellation token, controlling error reporting, etc. + public virtual async Task RevokePermissionAsync(WebPubSubPermission permission, string connectionId, string targetName = null, RequestOptions options = default) { - var options = new RequestOptions() { StatusOption = ResponseStatusOption.NoThrow, CancellationToken = cancellationToken }; - var response = await RevokePermissionAsync(permission.ToString(), connectionId, targetName, options).ConfigureAwait(false); + var response = await RevokePermissionAsync(PermissionToString(permission), connectionId, targetName, options).ConfigureAwait(false); return response; } @@ -323,11 +314,10 @@ public virtual async Task RevokePermissionAsync(WebPubSubPermission pe /// The permission: current supported actions are joinLeaveGroup and sendToGroup. /// Target connection Id. /// Optional. If not set, revoke the permission for all targets. If set, revoke the permission for the specific target. The meaning of the target depends on the specific permission. - /// The cancellation token to use. - public virtual Response RevokePermission(WebPubSubPermission permission, string connectionId, string targetName = null, CancellationToken cancellationToken = default) + /// Options specifying the cancellation token, controlling error reporting, etc. + public virtual Response RevokePermission(WebPubSubPermission permission, string connectionId, string targetName = null, RequestOptions options = default) { - var options = new RequestOptions() { StatusOption = ResponseStatusOption.NoThrow, CancellationToken = cancellationToken }; - var response = RevokePermission(permission.ToString(), connectionId, targetName, options); + var response = RevokePermission(PermissionToString(permission), connectionId, targetName, options); return response; } @@ -335,24 +325,22 @@ public virtual Response RevokePermission(WebPubSubPermission permission, string /// The permission: current supported actions are joinLeaveGroup and sendToGroup. /// Target connection Id. /// Optional. If not set, get the permission for all targets. If set, get the permission for the specific target. The meaning of the target depends on the specific permission. - /// The cancellation token to use. - public virtual async Task CheckPermissionAsync(WebPubSubPermission permission, string connectionId, string targetName = null, CancellationToken cancellationToken = default) + /// Options specifying the cancellation token, controlling error reporting, etc. + public virtual async Task> CheckPermissionAsync(WebPubSubPermission permission, string connectionId, string targetName = null, RequestOptions options = default) { - var options = new RequestOptions() { StatusOption = ResponseStatusOption.NoThrow, CancellationToken = cancellationToken }; - var response = await CheckPermissionAsync(permission.ToString(), connectionId, targetName, options).ConfigureAwait(false); - return response; + var response = await CheckPermissionAsync(PermissionToString(permission), connectionId, targetName, options).ConfigureAwait(false); + return Response.FromValue((response.Status == 200), response); } /// Check if a connection has permission to the specified action. /// The permission: current supported actions are joinLeaveGroup and sendToGroup. /// Target connection Id. /// Optional. If not set, get the permission for all targets. If set, get the permission for the specific target. The meaning of the target depends on the specific permission. - /// The cancellation token to use. - public virtual Response CheckPermission(WebPubSubPermission permission, string connectionId, string targetName = null, CancellationToken cancellationToken = default) + /// Options specifying the cancellation token, controlling error reporting, etc. + public virtual Response CheckPermission(WebPubSubPermission permission, string connectionId, string targetName = null, RequestOptions options = default) { - var options = new RequestOptions() { StatusOption = ResponseStatusOption.NoThrow, CancellationToken = cancellationToken }; - var response = CheckPermission(permission.ToString(), connectionId, targetName, options); - return response; + var response = CheckPermission(PermissionToString(permission), connectionId, targetName, options); + return Response.FromValue((response.Status == 200), response); } } } diff --git a/sdk/webpubsub/Azure.Messaging.WebPubSub/src/WebPubSubServiceClient_helpers.cs b/sdk/webpubsub/Azure.Messaging.WebPubSub/src/WebPubSubServiceClient_helpers.cs index cd3702ef8e6d..7e7f87bcd545 100644 --- a/sdk/webpubsub/Azure.Messaging.WebPubSub/src/WebPubSubServiceClient_helpers.cs +++ b/sdk/webpubsub/Azure.Messaging.WebPubSub/src/WebPubSubServiceClient_helpers.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Security.Claims; +using Azure.Core; using Azure.Core.Pipeline; namespace Azure.Messaging.WebPubSub @@ -22,17 +23,12 @@ public partial class WebPubSubServiceClient /// /// Creates a URI with authentication token. /// + /// UTC time when the token expires. /// /// - /// Defaults to one hour, if not specified. /// - public virtual Uri GenerateClientAccessUri(string userId = default, string[] roles = default, TimeSpan expiresAfter = default) + public virtual Uri GenerateClientAccessUri(DateTime expiresAtUtc, string userId = default, params string[] roles) { - if (expiresAfter == default) - { - expiresAfter = TimeSpan.FromHours(1); - } - List claims = new List(); if (userId != default) { @@ -54,7 +50,7 @@ public virtual Uri GenerateClientAccessUri(string userId = default, string[] rol } var audience = $"{endpoint}client/hubs/{hub}"; - string token = WebPubSubAuthenticationPolicy.GenerateAccessToken(audience, claims, _credential, expiresAfter); + string token = WebPubSubAuthenticationPolicy.GenerateAccessToken(audience, claims, _credential, expiresAtUtc); var clientEndpoint = new UriBuilder(endpoint); clientEndpoint.Scheme = this.endpoint.Scheme == "http" ? "ws" : "wss"; @@ -63,12 +59,38 @@ public virtual Uri GenerateClientAccessUri(string userId = default, string[] rol return new Uri(uriString); } + /// + /// Creates a URI with authentication token. + /// + /// Defaults to one hour, if not specified. Must be greater or equal zero. + /// + /// + /// + public virtual Uri GenerateClientAccessUri(TimeSpan expiresAfter = default, string userId = default, params string[] roles) + { + if (expiresAfter.TotalMilliseconds < 0) + throw new ArgumentOutOfRangeException(nameof(expiresAfter)); + + DateTime expiresAt = DateTime.UtcNow; + if (expiresAfter == default) + { + expiresAt += TimeSpan.FromHours(1); + } + else + { + expiresAt += expiresAfter; + } + return GenerateClientAccessUri(expiresAt, userId, roles); + } + /// /// Parse connection string to endpoint and credential /// /// internal static (Uri Endpoint, AzureKeyCredential Credential) ParseConnectionString(string connectionString) { + Argument.AssertNotNull(connectionString, nameof(connectionString)); + var properties = connectionString.Split(PropertySeparator, StringSplitOptions.RemoveEmptyEntries); var dict = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -119,5 +141,18 @@ internal static (Uri Endpoint, AzureKeyCredential Credential) ParseConnectionStr return (uriBuilder.Uri, new AzureKeyCredential(accessKey)); } + + internal static string PermissionToString(WebPubSubPermission permission) + { + switch (permission) + { + case WebPubSubPermission.SendToGroup: + return "sendToGroup"; + case WebPubSubPermission.JoinLeaveGroup: + return "joinLeaveGroup"; + default: + throw new ArgumentOutOfRangeException(nameof(permission)); + } + } } } diff --git a/sdk/webpubsub/Azure.Messaging.WebPubSub/src/swagger/WebPubSub.json b/sdk/webpubsub/Azure.Messaging.WebPubSub/src/swagger/WebPubSub.json index ded8d9684bdd..eabfa10aa84d 100644 --- a/sdk/webpubsub/Azure.Messaging.WebPubSub/src/swagger/WebPubSub.json +++ b/sdk/webpubsub/Azure.Messaging.WebPubSub/src/swagger/WebPubSub.json @@ -99,7 +99,7 @@ "webpubsub" ], "summary": "Check if the connection with the given connectionId exists.", - "operationId": "WebPubSubService_ConnectionExists", + "operationId": "WebPubSubService_ConnectionExistsImpl", "x-accessibility": "internal", "parameters": [ { @@ -254,7 +254,7 @@ "webpubsub" ], "summary": "Check if there are any client connections inside the given group", - "operationId": "WebPubSubService_GroupExists", + "operationId": "WebPubSubService_GroupExistsImpl", "x-accessibility": "internal", "parameters": [ { @@ -480,7 +480,7 @@ "webpubsub" ], "summary": "Check if there are any client connections connected for the given user.", - "operationId": "WebPubSubService_UserExists", + "operationId": "WebPubSubService_UserExistsImpl", "x-accessibility": "internal", "parameters": [ { diff --git a/sdk/webpubsub/Azure.Messaging.WebPubSub/tests/Samples/WebPubSubSamples.HelloWorld.cs b/sdk/webpubsub/Azure.Messaging.WebPubSub/tests/Samples/WebPubSubSamples.HelloWorld.cs index 03f95c389a58..2897f766d7ee 100644 --- a/sdk/webpubsub/Azure.Messaging.WebPubSub/tests/Samples/WebPubSubSamples.HelloWorld.cs +++ b/sdk/webpubsub/Azure.Messaging.WebPubSub/tests/Samples/WebPubSubSamples.HelloWorld.cs @@ -90,7 +90,7 @@ public void AddUserToGroup() client.AddUserToGroup("some_group", "some_user"); // Avoid sending messages to users who do not exist. - if (client.UserExists("some_user", CancellationToken.None).Value) + if (client.UserExists("some_user").Value) { client.SendToUser("some_user", "Hi, I am glad you exist!"); } diff --git a/sdk/webpubsub/Azure.Messaging.WebPubSub/tests/WebPubSubParseConnectionStringTests.cs b/sdk/webpubsub/Azure.Messaging.WebPubSub/tests/WebPubSubParseConnectionStringTests.cs index 6e83d0e62d20..d2e38677f68c 100644 --- a/sdk/webpubsub/Azure.Messaging.WebPubSub/tests/WebPubSubParseConnectionStringTests.cs +++ b/sdk/webpubsub/Azure.Messaging.WebPubSub/tests/WebPubSubParseConnectionStringTests.cs @@ -36,7 +36,7 @@ public void ParseConnectionStringTests(string connectionString, string url) public void TestGenerateUriContainsExpectedPayloads(string userId, string[] roles) { var serviceClient = new WebPubSubServiceClient(string.Format("Endpoint=http://localhost;Port=8080;AccessKey={0};Version=1.0;", FakeAccessKey), "hub"); - var uri = serviceClient.GenerateClientAccessUri(userId, roles, TimeSpan.FromMinutes(5)); + var uri = serviceClient.GenerateClientAccessUri(TimeSpan.FromMinutes(5), userId, roles); var token = HttpUtility.ParseQueryString(uri.Query).Get("access_token"); Assert.NotNull(token); var jwt = JwtTokenHandler.ReadJwtToken(token);