Skip to content

Commit e613231

Browse files
committed
feat(Api): Added a new EventsController - and related clients -, used to publish CloudEvents
fix(Runner): Fixed the EmitTaskExecutor to use the Events API instead of relying on an ICloudEventBus implementation Fixes #371
1 parent 715c44f commit e613231

23 files changed

+295
-28
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright © 2024-Present The Synapse Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License"),
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
using Microsoft.Extensions.Logging;
15+
using Microsoft.Extensions.Options;
16+
using Neuroglia.Eventing.CloudEvents;
17+
using Neuroglia.Serialization;
18+
using Synapse.Api.Application.Configuration;
19+
using System.Text;
20+
21+
namespace Synapse.Api.Application.Commands.Events;
22+
23+
/// <summary>
24+
/// Represents the <see cref="ICommand"/> used to publish a <see cref="Neuroglia.Eventing.CloudEvents.CloudEvent"/> to the configured sink
25+
/// </summary>
26+
/// <param name="e">The <see cref="Neuroglia.Eventing.CloudEvents.CloudEvent"/> to publish</param>
27+
public class PublishCloudEventCommand(CloudEvent e)
28+
: Command
29+
{
30+
31+
/// <summary>
32+
/// Gets the <see cref="Neuroglia.Eventing.CloudEvents.CloudEvent"/> to publish
33+
/// </summary>
34+
public virtual CloudEvent CloudEvent { get; } = e;
35+
36+
}
37+
38+
/// <summary>
39+
/// Represents the service used to handle <see cref="PublishCloudEventCommand"/>s
40+
/// </summary>
41+
/// <param name="logger">The service used to perform logging</param>
42+
/// <param name="options">The service used to access the current <see cref="ApiServerOptions"/></param>
43+
/// <param name="jsonSerializer">The service used to serialize/deserialize data to/from JSON</param>
44+
/// <param name="httpClient">The service used to perform HTTP requests</param>
45+
public class PublishCloudEventCommandHandler(ILogger<PublishCloudEventCommandHandler> logger, IOptions<ApiServerOptions> options, IJsonSerializer jsonSerializer, HttpClient httpClient)
46+
: ICommandHandler<PublishCloudEventCommand>
47+
{
48+
49+
/// <inheritdoc/>
50+
public virtual async Task<IOperationResult> HandleAsync(PublishCloudEventCommand command, CancellationToken cancellationToken = default)
51+
{
52+
if (options.Value.Events?.Endpoint == null) return this.Ok();
53+
var json = jsonSerializer.SerializeToText(command.CloudEvent);
54+
using var content = new StringContent(json, Encoding.UTF8, CloudEventContentType.Json);
55+
using var request = new HttpRequestMessage(HttpMethod.Post, options.Value.Events.Endpoint) { Content = content };
56+
using var response = await httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
57+
json = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
58+
if (!response.IsSuccessStatusCode)
59+
{
60+
logger.LogError("An error occurred while publishing the cloud event with id '{eventId}' to the configure endpoint '{endpoint}': {ex}", command.CloudEvent.Id, options.Value.Events.Endpoint, json);
61+
response.EnsureSuccessStatusCode();
62+
}
63+
return this.Ok();
64+
}
65+
66+
}

src/api/Synapse.Api.Server/Configuration/ApiServerOptions.cs renamed to src/api/Synapse.Api.Application/Configuration/ApiServerOptions.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
// See the License for the specific language governing permissions and
1212
// limitations under the License.
1313

14-
namespace Synapse.Api.Server.Configuration;
14+
namespace Synapse.Api.Application.Configuration;
1515

1616
/// <summary>
1717
/// Represents the options used to configure a Synapse API server
@@ -31,11 +31,16 @@ public ApiServerOptions()
3131
/// <summary>
3232
/// Gets/sets a boolean indicating whether or not to serve the Synapse Dashboard
3333
/// </summary>
34-
public bool ServeDashboard { get; set; } = true;
34+
public virtual bool ServeDashboard { get; set; } = true;
3535

3636
/// <summary>
3737
/// Gets/sets the application's authentication policy
3838
/// </summary>
39-
public AuthenticationPolicyOptions Authentication { get; set; } = new();
39+
public virtual AuthenticationPolicyOptions Authentication { get; set; } = new();
40+
41+
/// <summary>
42+
/// Gets/sets the options used to configure the cloud events published by the Synapse API Server
43+
/// </summary>
44+
public virtual CloudEventOptions? Events { get; set; }
4045

4146
}

src/api/Synapse.Api.Server/Configuration/AuthenticationPolicyOptions.cs renamed to src/api/Synapse.Api.Application/Configuration/AuthenticationPolicyOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
using Neuroglia.Serialization.Yaml;
1515

16-
namespace Synapse.Api.Server.Configuration;
16+
namespace Synapse.Api.Application.Configuration;
1717

1818
/// <summary>
1919
/// Represents the options used to configure the authentication policy of a Synapse API server
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright © 2024-Present The Synapse Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License"),
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
using Neuroglia.Eventing.CloudEvents;
15+
16+
namespace Synapse.Api.Application.Configuration;
17+
18+
/// <summary>
19+
/// Represents the options used to configure the Cloud Events published by the Synapse API server
20+
/// </summary>
21+
public class CloudEventOptions
22+
{
23+
24+
/// <summary>
25+
/// Gets/sets the uri, if any, to which to publish <see cref="CloudEvent"/>s
26+
/// </summary>
27+
public virtual Uri? Endpoint { get; set; }
28+
29+
}

src/api/Synapse.Api.Server/Configuration/JwtBearerAuthenticationOptions.cs renamed to src/api/Synapse.Api.Application/Configuration/JwtBearerAuthenticationOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
using Microsoft.IdentityModel.Tokens;
1515
using System.Security.Cryptography;
1616

17-
namespace Synapse.Api.Server.Configuration;
17+
namespace Synapse.Api.Application.Configuration;
1818

1919
/// <summary>
2020
/// Represents the options used to configure the application's JWT authentication

src/api/Synapse.Api.Server/Configuration/OidcAuthenticationOptions.cs renamed to src/api/Synapse.Api.Application/Configuration/OidcAuthenticationOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
using Microsoft.IdentityModel.Tokens;
1515
using System.Security.Cryptography;
1616

17-
namespace Synapse.Api.Server.Configuration;
17+
namespace Synapse.Api.Application.Configuration;
1818

1919
/// <summary>
2020
/// Represents the options used to configure the OIDC authentication of a Synapse API server

src/api/Synapse.Api.Server/Configuration/StaticBearerAuthenticationOptions.cs renamed to src/api/Synapse.Api.Application/Configuration/StaticBearerAuthenticationOptions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
// See the License for the specific language governing permissions and
1212
// limitations under the License.
1313

14+
using Microsoft.AspNetCore.Authentication;
1415
using Microsoft.IdentityModel.Tokens;
1516
using System.IdentityModel.Tokens.Jwt;
17+
using System.Security.Claims;
1618

17-
namespace Synapse.Api.Server.Configuration;
19+
namespace Synapse.Api.Application.Configuration;
1820

1921
/// <summary>
2022
/// Represents the <see cref="AuthenticationSchemeOptions"/> used to configure the application's static token based authentication

src/api/Synapse.Api.Application/Extensions/IServiceCollectionExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using Neuroglia.Data.Infrastructure;
1616
using Neuroglia.Security;
1717
using Synapse.Api.Application.Commands.Documents;
18+
using Synapse.Api.Application.Commands.Events;
1819
using Synapse.Api.Application.Commands.Resources.Generic;
1920
using Synapse.Api.Application.Queries.Documents;
2021
using Synapse.Api.Application.Queries.Resources.Generic;
@@ -100,6 +101,7 @@ public static IServiceCollection AddApiQueries(this IServiceCollection services)
100101
services.AddScoped<IRequestHandler<GetDocumentQuery, IOperationResult<Document>>, GetDocumentQueryHandler>();
101102
services.AddScoped<IRequestHandler<ReadWorkflowInstanceLogsQuery, IOperationResult<string>>, ReadWorkflowInstanceLogsQueryHandler>();
102103
services.AddScoped<IRequestHandler<WatchWorkflowInstanceLogsQuery, IOperationResult<IAsyncEnumerable<ITextDocumentWatchEvent>>>, WatchWorkflowInstanceLogsQueryHandler>();
104+
services.AddScoped<IRequestHandler<PublishCloudEventCommand, IOperationResult>, PublishCloudEventCommandHandler>();
103105
return services;
104106
}
105107

src/api/Synapse.Api.Server/Services/StaticBearerAuthenticationHandler.cs renamed to src/api/Synapse.Api.Application/Services/StaticBearerAuthenticationHandler.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,14 @@
1111
// See the License for the specific language governing permissions and
1212
// limitations under the License.
1313

14-
namespace Synapse.Api.Server.Services;
14+
using Microsoft.AspNetCore.Authentication;
15+
using Microsoft.Extensions.Logging;
16+
using Microsoft.Extensions.Options;
17+
using Synapse.Api.Application.Configuration;
18+
using System.Security.Claims;
19+
using System.Text.Encodings.Web;
20+
21+
namespace Synapse.Api.Application.Services;
1522

1623
/// <summary>
1724
/// Represents the service used to handle the application's static token authentication
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright © 2024-Present The Synapse Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License"),
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
using Neuroglia.Eventing.CloudEvents;
15+
16+
namespace Synapse.Api.Client.Services;
17+
18+
/// <summary>
19+
/// Defines the fundamentals of the Synapse API used to publish <see cref="CloudEvent"/>s
20+
/// </summary>
21+
public interface ICloudEventApiClient
22+
{
23+
24+
/// <summary>
25+
/// Publishes the specified <see cref="CloudEvent"/>
26+
/// </summary>
27+
/// <param name="e">The <see cref="CloudEvent"/> to publish</param>
28+
/// <param name="cancellationToken">A <see cref="CancellationToken"/></param>
29+
/// <returns>A new awaitable <see cref="Task"/></returns>
30+
Task PublishAsync(CloudEvent e, CancellationToken cancellationToken = default);
31+
32+
}

0 commit comments

Comments
 (0)