src/Google.Cloud.Functions.Framework/CloudEventAdapter.cs (43 lines of code) (raw):
// Copyright 2020, Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using CloudNative.CloudEvents;
using CloudNative.CloudEvents.AspNetCore;
using CloudNative.CloudEvents.Http;
using Google.Cloud.Functions.Framework.GcfEvents;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;
namespace Google.Cloud.Functions.Framework
{
/// <summary>
/// An adapter to implement an HTTP Function based on a CloudEvent Function.
/// </summary>
public sealed class CloudEventAdapter : IHttpFunction
{
private readonly ICloudEventFunction _function;
private readonly CloudEventFormatter _formatter;
private readonly ILogger _logger;
/// <summary>
/// Constructs a new instance based on the given CloudEvent Function.
/// </summary>
/// <param name="function">The CloudEvent Function to invoke.</param>
/// <param name="formatter">The CloudEvent formatter to use when deserializing requests.</param>
/// <param name="logger">The logger to use to report errors.</param>
public CloudEventAdapter(ICloudEventFunction function, CloudEventFormatter formatter, ILogger<CloudEventAdapter> logger)
{
_function = Preconditions.CheckNotNull(function, nameof(function));
_formatter = Preconditions.CheckNotNull(formatter, nameof(formatter));
_logger = Preconditions.CheckNotNull(logger, nameof(logger));
}
/// <summary>
/// Handles an HTTP request by extracting the CloudEvent from it and passing it to the
/// original CloudEvent Function. The request fails if it does not contain a CloudEvent.
/// </summary>
/// <param name="context">The HTTP context containing the request and response.</param>
/// <returns>A task representing the asynchronous operation.</returns>
public async Task HandleAsync(HttpContext context)
{
CloudEvent cloudEvent;
try
{
cloudEvent = await ConvertRequestAsync(context.Request, _formatter, _logger);
}
catch (Exception e)
{
context.Response.StatusCode = 400;
_logger.LogError(e.Message);
return;
}
await _function.HandleAsync(cloudEvent, context.RequestAborted);
}
/// <summary>
/// Converts an HTTP request into a CloudEvent, either using regular CloudEvent parsing,
/// or GCF event conversion if necessary.
/// </summary>
/// <param name="request">The request to convert.</param>
/// <param name="formatter">The formatter to use for conversion.</param>
/// <param name="logger">The logger to use to report any warnings.</param>
/// <returns>A valid CloudEvent</returns>
internal static Task<CloudEvent> ConvertRequestAsync(HttpRequest request, CloudEventFormatter formatter, ILogger logger) =>
request.IsCloudEvent()
? request.ToCloudEventAsync(formatter)
: GcfConverters.ConvertGcfEventToCloudEvent(request, formatter, logger);
}
}