in src/Google.Cloud.Functions.Framework/GcfEvents/GcfConverters.cs [159:221]
private static string ValidateNotNullOrEmpty(string? value, string name) =>
string.IsNullOrEmpty(value)
? throw new ConversionException($"Event contained no {name}")
: value;
/// <summary>
/// An event-specific adapter, picked based on the event type from the GCF event.
/// This class provides seams for event-specific changes to the data and the source/subject,
/// but the defult implementations of the seams are reasonable for most events.
/// </summary>
private class EventAdapter
{
private readonly string _cloudEventType;
private readonly string _defaultService;
internal EventAdapter(string cloudEventType, string defaultService) =>
(_cloudEventType, _defaultService) = (cloudEventType, defaultService);
internal CloudEvent ConvertToCloudEvent(Request request, CloudEventFormatter formatter)
{
MaybeReshapeData(request);
var context = request.Context;
var resource = context.Resource;
// Default the service name if necessary
resource.Service = ValidateNotNullOrEmpty(resource.Service ?? _defaultService, "service");
ValidateNotNullOrEmpty(resource.Name, "resource name");
var evt = new CloudEvent
{
Type = _cloudEventType,
Id = context.Id,
Time = context.Timestamp,
DataContentType = JsonContentType
};
PopulateAttributes(request, evt);
var bytes = JsonSerializer.SerializeToUtf8Bytes(request.Data);
formatter.DecodeBinaryModeEventData(bytes, evt);
return evt;
}
protected virtual void MaybeReshapeData(Request request) { }
/// <summary>
/// Populate the attributes in the CloudEvent that can't always be determined directly.
/// In particular, this method must populate the Source context attribute,
/// should populate the Subject context attribute if it's defined for this event type,
/// and should populate any additional extension attributes to be compatible with Eventarc.
/// The resource within context of the request will definitely have its Service and Name properties populated.
/// This base implementation populates the Source based on the service and resource.
/// </summary>
/// <param name="request">The incoming request. The request's context always has a resource, and the service and name
/// are always populated by the time this method is called.</param>
/// <param name="evt">The event to populate</param>
protected virtual void PopulateAttributes(Request request, CloudEvent evt)
{
var service = request.Context.Resource.Service!;
var resource = request.Context.Resource.Name!;
evt.Source = FormatSource(service, resource);
}
protected Uri FormatSource(string service, string resource) => new Uri($"//{service}/{resource}", UriKind.RelativeOrAbsolute);
}