diff --git a/extra-examples/CustomPayload1/CustomPayload1.csproj b/extra-examples/CustomPayload1/CustomPayload1.csproj new file mode 100644 index 00000000..f376f2e8 --- /dev/null +++ b/extra-examples/CustomPayload1/CustomPayload1.csproj @@ -0,0 +1,11 @@ + + + Exe + netcoreapp3.1 + + + + + + + diff --git a/extra-examples/CustomPayload1/Function.cs b/extra-examples/CustomPayload1/Function.cs new file mode 100644 index 00000000..721945da --- /dev/null +++ b/extra-examples/CustomPayload1/Function.cs @@ -0,0 +1,33 @@ +// Copyright 2021, 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 Google.Cloud.Functions.Framework; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace CustomPayload1 +{ + public class Function : ICloudEventFunction + { + public Task HandleAsync(CloudEvent cloudEvent, Payload data, CancellationToken cancellationToken) + { + Console.WriteLine($"ID: {cloudEvent.Id}"); + Console.WriteLine($"Text: {data.Text}"); + Console.WriteLine($"Number: {data.Number}"); + return Task.CompletedTask; + } + } +} diff --git a/extra-examples/CustomPayload1/Payload.cs b/extra-examples/CustomPayload1/Payload.cs new file mode 100644 index 00000000..7670d8d2 --- /dev/null +++ b/extra-examples/CustomPayload1/Payload.cs @@ -0,0 +1,33 @@ +// Copyright 2021, 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.SystemTextJson; +using System.Text.Json.Serialization; + +namespace CustomPayload1 +{ + [CloudEventFormatter(typeof(JsonEventFormatter))] + public class Payload + { + // Note: System.Text.Json is case-sensitive. The Newtonsoft.Json + // deserializer wouldn't require the attributes. (Or if the JSON + // matched the property name casing, we wouldn't need them then either.) + [JsonPropertyName("text")] + public string Text { get; set; } + + [JsonPropertyName("number")] + public double Number { get; set; } + } +} diff --git a/extra-examples/CustomPayload2/CustomPayload2.csproj b/extra-examples/CustomPayload2/CustomPayload2.csproj new file mode 100644 index 00000000..a53bc36d --- /dev/null +++ b/extra-examples/CustomPayload2/CustomPayload2.csproj @@ -0,0 +1,12 @@ + + + Exe + netcoreapp3.1 + + + + + + + + diff --git a/extra-examples/CustomPayload2/Function.cs b/extra-examples/CustomPayload2/Function.cs new file mode 100644 index 00000000..81811941 --- /dev/null +++ b/extra-examples/CustomPayload2/Function.cs @@ -0,0 +1,45 @@ +// Copyright 2021, 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.NewtonsoftJson; +using Google.Cloud.Functions.Framework; +using Google.Cloud.Functions.Hosting; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Threading; +using System.Threading.Tasks; +using ThirdPartyPackage; + +namespace CustomPayload2 +{ + public class Startup : FunctionsStartup + { + public override void ConfigureServices(WebHostBuilderContext context, IServiceCollection services) => + services.AddSingleton>(); + } + + [FunctionsStartup(typeof(Startup))] + public class Function : ICloudEventFunction + { + public Task HandleAsync(CloudEvent cloudEvent, Payload data, CancellationToken cancellationToken) + { + Console.WriteLine($"ID: {cloudEvent.Id}"); + Console.WriteLine($"Text: {data.Text}"); + Console.WriteLine($"Number: {data.Number}"); + return Task.CompletedTask; + } + } +} diff --git a/extra-examples/CustomPayload2/Payload.cs b/extra-examples/CustomPayload2/Payload.cs new file mode 100644 index 00000000..ae80f671 --- /dev/null +++ b/extra-examples/CustomPayload2/Payload.cs @@ -0,0 +1,24 @@ +// Copyright 2021, 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. + +namespace ThirdPartyPackage +{ + // The event payload, as defined by a third-party. The third-party + // doesn't depend on the CloudEvents SDK at all. + public class Payload + { + public string Text { get; set; } + public double Number { get; set; } + } +} diff --git a/extra-examples/CustomPayload3/CloudEventFormatterStartup.cs b/extra-examples/CustomPayload3/CloudEventFormatterStartup.cs new file mode 100644 index 00000000..ed29bb79 --- /dev/null +++ b/extra-examples/CustomPayload3/CloudEventFormatterStartup.cs @@ -0,0 +1,29 @@ +// Copyright 2021, 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.NewtonsoftJson; +using Google.Cloud.Functions.Hosting; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using ThirdPartyPackage1; + +namespace ThirdPartyPackage2 +{ + public class CloudEventFormatterStartup : FunctionsStartup + { + public override void ConfigureServices(WebHostBuilderContext context, IServiceCollection services) => + services.AddSingleton>(); + } +} diff --git a/extra-examples/CustomPayload3/CustomPayload3.csproj b/extra-examples/CustomPayload3/CustomPayload3.csproj new file mode 100644 index 00000000..a53bc36d --- /dev/null +++ b/extra-examples/CustomPayload3/CustomPayload3.csproj @@ -0,0 +1,12 @@ + + + Exe + netcoreapp3.1 + + + + + + + + diff --git a/extra-examples/CustomPayload3/Function.cs b/extra-examples/CustomPayload3/Function.cs new file mode 100644 index 00000000..353be7bb --- /dev/null +++ b/extra-examples/CustomPayload3/Function.cs @@ -0,0 +1,37 @@ +// Copyright 2021, 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 Google.Cloud.Functions.Framework; +using Google.Cloud.Functions.Hosting; +using System; +using System.Threading; +using System.Threading.Tasks; +using ThirdPartyPackage1; +using ThirdPartyPackage2; + +namespace CustomPayload3 +{ + [FunctionsStartup(typeof(CloudEventFormatterStartup))] + public class Function : ICloudEventFunction + { + public Task HandleAsync(CloudEvent cloudEvent, Payload data, CancellationToken cancellationToken) + { + Console.WriteLine($"ID: {cloudEvent.Id}"); + Console.WriteLine($"Text: {data.Text}"); + Console.WriteLine($"Number: {data.Number}"); + return Task.CompletedTask; + } + } +} diff --git a/extra-examples/CustomPayload3/Payload.cs b/extra-examples/CustomPayload3/Payload.cs new file mode 100644 index 00000000..e28e164b --- /dev/null +++ b/extra-examples/CustomPayload3/Payload.cs @@ -0,0 +1,24 @@ +// Copyright 2021, 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. + +namespace ThirdPartyPackage1 +{ + // The event payload, as defined by a third-party. The package + // defining the payload doesn't depend on the CloudEvents SDK. + public class Payload + { + public string Text { get; set; } + public double Number { get; set; } + } +} diff --git a/extra-examples/GoogleTypeDetection/Function.cs b/extra-examples/GoogleTypeDetection/Function.cs new file mode 100644 index 00000000..65dd76a8 --- /dev/null +++ b/extra-examples/GoogleTypeDetection/Function.cs @@ -0,0 +1,55 @@ +// Copyright 2021, 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 Google.Cloud.Functions.Framework; +using Google.Cloud.Functions.Hosting; +using Google.Events.Protobuf.Cloud.PubSub.V1; +using Google.Events.Protobuf.Cloud.Storage.V1; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace GoogleTypeDetection +{ + public class Startup : FunctionsStartup + { + public override void ConfigureServices(WebHostBuilderContext context, IServiceCollection services) => + services.AddSingleton(); + } + + [FunctionsStartup(typeof(Startup))] + public class Function : ICloudEventFunction + { + public Task HandleAsync(CloudEvent cloudEvent, CancellationToken cancellationToken) + { + Console.WriteLine($"ID: {cloudEvent.Id}"); + switch (cloudEvent.Data) + { + case StorageObjectData storage: + Console.WriteLine($"Storage Bucket: {storage.Bucket}"); + break; + case MessagePublishedData pubsub: + Console.WriteLine($"PubSub subscription: {pubsub.Subscription}"); + break; + default: + Console.WriteLine($"Unhandled event type {cloudEvent.Type}"); + break; + } + return Task.CompletedTask; + } + } +} diff --git a/extra-examples/GoogleTypeDetection/GoogleEventFormatter.cs b/extra-examples/GoogleTypeDetection/GoogleEventFormatter.cs new file mode 100644 index 00000000..3278bb24 --- /dev/null +++ b/extra-examples/GoogleTypeDetection/GoogleEventFormatter.cs @@ -0,0 +1,138 @@ +// Copyright 2021, 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.Core; +using CloudNative.CloudEvents.SystemTextJson; +using Google.Events.Protobuf.Cloud.Firestore.V1; +using Google.Events.Protobuf.Cloud.PubSub.V1; +using Google.Events.Protobuf.Cloud.Storage.V1; +using Google.Events.Protobuf.Firebase.Database.V1; +using Google.Protobuf; +using Google.Protobuf.Reflection; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Mime; +using System.Text; +using System.Text.Json; + +namespace GoogleTypeDetection +{ + /// + /// A CloudEvent formatter that knows about all the events in the Google.Events.Protobuf package. + /// This would be in that package. + /// + public class GoogleEventFormatter : CloudEventFormatter + { + private static Dictionary s_eventTypeToPayloadType = new Dictionary + { + { StorageObjectData.ArchivedCloudEventType, StorageObjectData.Descriptor }, + { StorageObjectData.DeletedCloudEventType, StorageObjectData.Descriptor }, + { StorageObjectData.FinalizedCloudEventType, StorageObjectData.Descriptor }, + { StorageObjectData.MetadataUpdatedCloudEventType, StorageObjectData.Descriptor }, + + { MessagePublishedData.MessagePublishedCloudEventType, MessagePublishedData.Descriptor }, + + { DocumentEventData.CreatedCloudEventType, DocumentEventData.Descriptor }, + { DocumentEventData.DeletedCloudEventType, DocumentEventData.Descriptor }, + + { ReferenceEventData.CreatedCloudEventType, ReferenceEventData.Descriptor }, + { ReferenceEventData.DeletedCloudEventType, ReferenceEventData.Descriptor }, + { ReferenceEventData.WrittenCloudEventType, ReferenceEventData.Descriptor }, + { ReferenceEventData.UpdatedCloudEventType, ReferenceEventData.Descriptor }, + + // Etc... this would all be generated. + }; + + private static readonly JsonParser s_jsonParser = new JsonParser(JsonParser.Settings.Default.WithIgnoreUnknownFields(true)); + + // Note: although we delegate to a JsonEventFormatter (via StructuredEventFormatter) and *could* just derive from JsonEventFormatter, + // that would provide less flexibility for the future. + private static readonly CloudEventFormatter s_structuredEventFormatter = new StructuredEventFormatter(); + + /// + public override void DecodeBinaryModeEventData(ReadOnlyMemory body, CloudEvent cloudEvent) + { + if (cloudEvent.Type is string eventType && s_eventTypeToPayloadType.TryGetValue(eventType, out var descriptor)) + { + cloudEvent.Data = body.Length == 0 + ? null + : s_jsonParser.Parse(new StreamReader(BinaryDataUtilities.AsStream(body)), descriptor); + return; + } + throw new ArgumentException("Unknown CloudEvent type: " + cloudEvent.Type); + } + + /// + public override CloudEvent DecodeStructuredModeMessage(ReadOnlyMemory body, ContentType contentType, IEnumerable extensionAttributes) => + s_structuredEventFormatter.DecodeStructuredModeMessage(body, contentType, extensionAttributes); + + /// + public override IReadOnlyList DecodeBatchModeMessage(ReadOnlyMemory body, ContentType contentType, IEnumerable extensionAttributes) => + s_structuredEventFormatter.DecodeBatchModeMessage(body, contentType, extensionAttributes); + + /// + public override ReadOnlyMemory EncodeBinaryModeEventData(CloudEvent cloudEvent) + { + var data = (IMessage) cloudEvent.Data; + if (data is null) + { + return Array.Empty(); + } + var json = data.ToString(); + return Encoding.UTF8.GetBytes(json); + } + + /// + public override ReadOnlyMemory EncodeStructuredModeMessage(CloudEvent cloudEvent, out ContentType contentType) => + s_structuredEventFormatter.EncodeStructuredModeMessage(cloudEvent, out contentType); + + /// + public override ReadOnlyMemory EncodeBatchModeMessage(IEnumerable cloudEvents, out ContentType contentType) => + s_structuredEventFormatter.EncodeBatchModeMessage(cloudEvents, out contentType); + + // This is basically a slightly-modified copy of the code within ProtobufJsonCloudEventFormatter. + private class StructuredEventFormatter : JsonEventFormatter + { + protected override void EncodeStructuredModeData(CloudEvent cloudEvent, Utf8JsonWriter writer) + { + writer.WritePropertyName("data"); + // TODO: Try to make this cleaner. It's annoying that we have to convert to a JSON string, + // reparse, then reserialize. + using var document = JsonDocument.Parse(cloudEvent.Data!.ToString()); + document.WriteTo(writer); + } + + protected override void DecodeStructuredModeDataProperty(JsonElement dataElement, CloudEvent cloudEvent) + { + if (dataElement.ValueKind != JsonValueKind.Object) + { + throw new InvalidOperationException("Expected Data property to have an object value"); + } + if (cloudEvent.Type is string eventType && s_eventTypeToPayloadType.TryGetValue(eventType, out var descriptor)) + { + string json = dataElement.GetRawText(); + cloudEvent.Data = s_jsonParser.Parse(json, descriptor); + return; + } + } + + protected override void DecodeStructuredModeDataBase64Property(JsonElement dataBase64Element, CloudEvent cloudEvent) + { + throw new InvalidOperationException("Expected Data property to be set"); + } + } + } +} diff --git a/extra-examples/GoogleTypeDetection/GoogleTypeDetection.csproj b/extra-examples/GoogleTypeDetection/GoogleTypeDetection.csproj new file mode 100644 index 00000000..5242316e --- /dev/null +++ b/extra-examples/GoogleTypeDetection/GoogleTypeDetection.csproj @@ -0,0 +1,12 @@ + + + Exe + netcoreapp3.1 + + + + + + + + diff --git a/extra-examples/LoggingFunction/Function.cs b/extra-examples/LoggingFunction/Function.cs new file mode 100644 index 00000000..a40035d5 --- /dev/null +++ b/extra-examples/LoggingFunction/Function.cs @@ -0,0 +1,47 @@ +// Copyright 2021, 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 Google.Cloud.Functions.Framework; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using System; +using System.IO; +using System.Threading.Tasks; + +namespace LoggingFunction +{ + public class Function : IHttpFunction + { + private readonly ILogger _logger; + + public Function(ILogger logger) => _logger = logger; + + public async Task HandleAsync(HttpContext context) + { + _logger.LogInformation("Start of request"); + var request = context.Request; + _logger.LogInformation("HTTP method: {method}", request.Method); + _logger.LogInformation("Headers:"); + foreach (var header in request.Headers) + { + _logger.LogInformation("{key}: {values}", header.Key, string.Join(",", header.Value)); + } + using var reader = new StreamReader(request.Body); + string text = await reader.ReadToEndAsync(); + _logger.LogInformation("Body:"); + _logger.LogInformation("{body}", text); + _logger.LogInformation("End of request"); + } + } +} diff --git a/extra-examples/LoggingFunction/LoggingFunction.csproj b/extra-examples/LoggingFunction/LoggingFunction.csproj new file mode 100644 index 00000000..f376f2e8 --- /dev/null +++ b/extra-examples/LoggingFunction/LoggingFunction.csproj @@ -0,0 +1,11 @@ + + + Exe + netcoreapp3.1 + + + + + + + diff --git a/extra-examples/README.md b/extra-examples/README.md new file mode 100644 index 00000000..ed3274f7 --- /dev/null +++ b/extra-examples/README.md @@ -0,0 +1,96 @@ +These are extra examples to see if the existing Functions Framework +and CloudEvent integration paths can easily meet the use cases we +want to support, or if additional functionality is required. + +## Testing the functions + +Start the desired function (e.g. set it as the startup project and +hit Run in Visual Studio, or cd into the directory and run `dotnet +run`) then use curl to fire requests. There are sample requests in +this directory: + +- `custom-payload-request.json` for all the custom payload examples +- Google payloads for the GoogleTypeDetection example: + - `google-storage-request.json` + - `google-pubsub-request.json` + - `google-firestore-request.json` + +Sample curl command: + +```sh +curl -X POST -H 'Content-Type:application/cloudevents' http://localhost:8080 -d @custom-payload-request.json +``` + +## Examples in this directory + +### CustomPayload1 + +This is for a customer-defined payload, where the customer is able +and willing to add the `[CloudEventFormatter]` attribute which +enables the Functions Framework (and anything else using the SDK) to +"know" how to deserialize. + +In this case, we use +CloudNative.CloudEvents.SystemTextJson.JsonEventFormatter, which +uses System.Text.Json to deserialize. We need to add attributes to +the payload properties as System.Text.Json is case-sensitive, but +that's not CloudEvent-specific at all. + +### CustomPayload2 + +This is for a third-party-defined payload, where the customer is +unable or unwilling to add the `[CloudEventFormatter]` attribute. +Instead, they specify a startup class (see [the repo +docs](../docs/customization.md) for more info) to inject a +`CloudEventFormatter` for the Functions Framework to use. + +In this case, we've added a reference to +CloudNative.CloudEvents.NewtonsoftJson and used the +JsonEventFormatter from that package. That's case-insensitive, so +the payload class is really just a POCO with no extra attributes. + +Note that although the payload is in the same project in the example +(just for simplicity), it could easily be in a third-party package. + +### CustomPayload3 + +This is for a third-party-defined payload where the third-party +doesn't want to add a CloudEvents reference in their main package +for whatever reason, but is happy to have a separate package to +enable simple integration with the Functions Framework. This +separate package depends on the Functions Framework, and provides +the same kind of startup class as in CustomPayload2 - the customer +just needs to refer to that startup class rather than writing it +themselves. + +(The code in this example would be spread across three separate +packages in reality.) + +### GoogleTypeDetection + +This is an example of a function intended to handle any Google event +type, with automatic deserializing to the "right" kind of object. + +The GoogleEventFormatter code would be added to +Google.Events.Protobuf, with the dictionary part being generated (C# +makes this easy via partial classes). + +The customer code requiring a startup class isn't ideal, although +it's really not very much code. We can't add that class to either +the Functions Framework or the Google.Events.Protobuf package as +they don't know about each other (at the moment). We *could* create +an additional package just to contain that startup code... or we +could try to work out another approach. + +(One possible option would be to create a "marker" IGoogleEvent +interface, make all the Google event classes implement it. That +could be decorated with the CloudEventFormatter attribute to let it +all just work. I'm not sure how I feel about that idea, but we could +test it.) + +## Supporting code + +### LoggingFunction: used to log requests + +This is just an HTTP function that logs the headers and body of a +request. \ No newline at end of file diff --git a/extra-examples/custom-payload-request.json b/extra-examples/custom-payload-request.json new file mode 100644 index 00000000..2143c541 --- /dev/null +++ b/extra-examples/custom-payload-request.json @@ -0,0 +1,11 @@ +{ + "specversion": "1.0", + "id": "event-id", + "datacontenttype": "application/json", + "source": "//local", + "type": "example", + "data": { + "text":"Some text", + "number":20 + } +} \ No newline at end of file diff --git a/extra-examples/extra-examples.sln b/extra-examples/extra-examples.sln new file mode 100644 index 00000000..165e7f74 --- /dev/null +++ b/extra-examples/extra-examples.sln @@ -0,0 +1,93 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31424.327 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CustomPayload1", "CustomPayload1\CustomPayload1.csproj", "{D783AF8C-5998-48FC-8CCD-8EF122802C9C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LoggingFunction", "LoggingFunction\LoggingFunction.csproj", "{12F37179-ABE2-4EA1-9118-2D1709D86C42}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomPayload2", "CustomPayload2\CustomPayload2.csproj", "{A44CB536-4BBB-4BD3-8A56-AB972BE86D07}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomPayload3", "CustomPayload3\CustomPayload3.csproj", "{3D7844C3-557B-45AF-86E7-85F6F1D85C02}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GoogleTypeDetection", "GoogleTypeDetection\GoogleTypeDetection.csproj", "{D326FE7F-8D5A-4F92-8090-E58A2B983668}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D783AF8C-5998-48FC-8CCD-8EF122802C9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D783AF8C-5998-48FC-8CCD-8EF122802C9C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D783AF8C-5998-48FC-8CCD-8EF122802C9C}.Debug|x64.ActiveCfg = Debug|Any CPU + {D783AF8C-5998-48FC-8CCD-8EF122802C9C}.Debug|x64.Build.0 = Debug|Any CPU + {D783AF8C-5998-48FC-8CCD-8EF122802C9C}.Debug|x86.ActiveCfg = Debug|Any CPU + {D783AF8C-5998-48FC-8CCD-8EF122802C9C}.Debug|x86.Build.0 = Debug|Any CPU + {D783AF8C-5998-48FC-8CCD-8EF122802C9C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D783AF8C-5998-48FC-8CCD-8EF122802C9C}.Release|Any CPU.Build.0 = Release|Any CPU + {D783AF8C-5998-48FC-8CCD-8EF122802C9C}.Release|x64.ActiveCfg = Release|Any CPU + {D783AF8C-5998-48FC-8CCD-8EF122802C9C}.Release|x64.Build.0 = Release|Any CPU + {D783AF8C-5998-48FC-8CCD-8EF122802C9C}.Release|x86.ActiveCfg = Release|Any CPU + {D783AF8C-5998-48FC-8CCD-8EF122802C9C}.Release|x86.Build.0 = Release|Any CPU + {12F37179-ABE2-4EA1-9118-2D1709D86C42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {12F37179-ABE2-4EA1-9118-2D1709D86C42}.Debug|Any CPU.Build.0 = Debug|Any CPU + {12F37179-ABE2-4EA1-9118-2D1709D86C42}.Debug|x64.ActiveCfg = Debug|Any CPU + {12F37179-ABE2-4EA1-9118-2D1709D86C42}.Debug|x64.Build.0 = Debug|Any CPU + {12F37179-ABE2-4EA1-9118-2D1709D86C42}.Debug|x86.ActiveCfg = Debug|Any CPU + {12F37179-ABE2-4EA1-9118-2D1709D86C42}.Debug|x86.Build.0 = Debug|Any CPU + {12F37179-ABE2-4EA1-9118-2D1709D86C42}.Release|Any CPU.ActiveCfg = Release|Any CPU + {12F37179-ABE2-4EA1-9118-2D1709D86C42}.Release|Any CPU.Build.0 = Release|Any CPU + {12F37179-ABE2-4EA1-9118-2D1709D86C42}.Release|x64.ActiveCfg = Release|Any CPU + {12F37179-ABE2-4EA1-9118-2D1709D86C42}.Release|x64.Build.0 = Release|Any CPU + {12F37179-ABE2-4EA1-9118-2D1709D86C42}.Release|x86.ActiveCfg = Release|Any CPU + {12F37179-ABE2-4EA1-9118-2D1709D86C42}.Release|x86.Build.0 = Release|Any CPU + {A44CB536-4BBB-4BD3-8A56-AB972BE86D07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A44CB536-4BBB-4BD3-8A56-AB972BE86D07}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A44CB536-4BBB-4BD3-8A56-AB972BE86D07}.Debug|x64.ActiveCfg = Debug|Any CPU + {A44CB536-4BBB-4BD3-8A56-AB972BE86D07}.Debug|x64.Build.0 = Debug|Any CPU + {A44CB536-4BBB-4BD3-8A56-AB972BE86D07}.Debug|x86.ActiveCfg = Debug|Any CPU + {A44CB536-4BBB-4BD3-8A56-AB972BE86D07}.Debug|x86.Build.0 = Debug|Any CPU + {A44CB536-4BBB-4BD3-8A56-AB972BE86D07}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A44CB536-4BBB-4BD3-8A56-AB972BE86D07}.Release|Any CPU.Build.0 = Release|Any CPU + {A44CB536-4BBB-4BD3-8A56-AB972BE86D07}.Release|x64.ActiveCfg = Release|Any CPU + {A44CB536-4BBB-4BD3-8A56-AB972BE86D07}.Release|x64.Build.0 = Release|Any CPU + {A44CB536-4BBB-4BD3-8A56-AB972BE86D07}.Release|x86.ActiveCfg = Release|Any CPU + {A44CB536-4BBB-4BD3-8A56-AB972BE86D07}.Release|x86.Build.0 = Release|Any CPU + {3D7844C3-557B-45AF-86E7-85F6F1D85C02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D7844C3-557B-45AF-86E7-85F6F1D85C02}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D7844C3-557B-45AF-86E7-85F6F1D85C02}.Debug|x64.ActiveCfg = Debug|Any CPU + {3D7844C3-557B-45AF-86E7-85F6F1D85C02}.Debug|x64.Build.0 = Debug|Any CPU + {3D7844C3-557B-45AF-86E7-85F6F1D85C02}.Debug|x86.ActiveCfg = Debug|Any CPU + {3D7844C3-557B-45AF-86E7-85F6F1D85C02}.Debug|x86.Build.0 = Debug|Any CPU + {3D7844C3-557B-45AF-86E7-85F6F1D85C02}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D7844C3-557B-45AF-86E7-85F6F1D85C02}.Release|Any CPU.Build.0 = Release|Any CPU + {3D7844C3-557B-45AF-86E7-85F6F1D85C02}.Release|x64.ActiveCfg = Release|Any CPU + {3D7844C3-557B-45AF-86E7-85F6F1D85C02}.Release|x64.Build.0 = Release|Any CPU + {3D7844C3-557B-45AF-86E7-85F6F1D85C02}.Release|x86.ActiveCfg = Release|Any CPU + {3D7844C3-557B-45AF-86E7-85F6F1D85C02}.Release|x86.Build.0 = Release|Any CPU + {D326FE7F-8D5A-4F92-8090-E58A2B983668}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D326FE7F-8D5A-4F92-8090-E58A2B983668}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D326FE7F-8D5A-4F92-8090-E58A2B983668}.Debug|x64.ActiveCfg = Debug|Any CPU + {D326FE7F-8D5A-4F92-8090-E58A2B983668}.Debug|x64.Build.0 = Debug|Any CPU + {D326FE7F-8D5A-4F92-8090-E58A2B983668}.Debug|x86.ActiveCfg = Debug|Any CPU + {D326FE7F-8D5A-4F92-8090-E58A2B983668}.Debug|x86.Build.0 = Debug|Any CPU + {D326FE7F-8D5A-4F92-8090-E58A2B983668}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D326FE7F-8D5A-4F92-8090-E58A2B983668}.Release|Any CPU.Build.0 = Release|Any CPU + {D326FE7F-8D5A-4F92-8090-E58A2B983668}.Release|x64.ActiveCfg = Release|Any CPU + {D326FE7F-8D5A-4F92-8090-E58A2B983668}.Release|x64.Build.0 = Release|Any CPU + {D326FE7F-8D5A-4F92-8090-E58A2B983668}.Release|x86.ActiveCfg = Release|Any CPU + {D326FE7F-8D5A-4F92-8090-E58A2B983668}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AFEF0FCE-1771-40CE-A2C6-25477479B0CA} + EndGlobalSection +EndGlobal diff --git a/extra-examples/google-firestore-request.json b/extra-examples/google-firestore-request.json new file mode 100644 index 00000000..d5967caa --- /dev/null +++ b/extra-examples/google-firestore-request.json @@ -0,0 +1,46 @@ +{ + "specversion": "1.0", + "id": "firestore-event-id", + "datacontenttype": "application/json", + "source": "//local", + "type": "google.cloud.firestore.document.v1.updated", + "data": { + "oldValue":{ + "createTime":"2020-04-23T09:58:53.211035Z", + "fields":{ + "another test":{ + "stringValue":"asd" + }, + "count":{ + "integerValue":"3" + }, + "foo":{ + "stringValue":"bar" + } + }, + "name":"projects/project-id/databases/(default)/documents/gcf-test/2Vm2mI1d0wIaK2Waj5to", + "updateTime":"2020-04-23T12:00:27.247187Z" + }, + "updateMask":{ + "fieldPaths":[ + "count" + ] + }, + "value":{ + "createTime":"2020-04-23T09:58:53.211035Z", + "fields":{ + "another test":{ + "stringValue":"asd" + }, + "count":{ + "integerValue":"4" + }, + "foo":{ + "stringValue":"bar" + } + }, + "name":"projects/project-id/databases/(default)/documents/gcf-test/2Vm2mI1d0wIaK2Waj5to", + "updateTime":"2020-04-23T12:00:27.247187Z" + } + } +} \ No newline at end of file diff --git a/extra-examples/google-pubsub-request.json b/extra-examples/google-pubsub-request.json new file mode 100644 index 00000000..14e4600e --- /dev/null +++ b/extra-examples/google-pubsub-request.json @@ -0,0 +1,19 @@ +{ + "specversion": "1.0", + "id": "pubsub-event-id", + "datacontenttype": "application/json", + "source": "//local", + "type": "google.cloud.pubsub.topic.v1.messagePublished", + "data": { + "subscription": "projects/my-project/subscriptions/my-subscription", + "message": { + "@type": "type.googleapis.com/google.pubsub.v1.PubsubMessage", + "attributes": { + "attr1":"attr1-value" + }, + "data": "dGVzdCBtZXNzYWdlIDM=", + "messageId": "message-id", + "publishTime":"2021-02-05T04:06:14.109Z" + } + } +} \ No newline at end of file diff --git a/extra-examples/google-storage-request.json b/extra-examples/google-storage-request.json new file mode 100644 index 00000000..cb43e19d --- /dev/null +++ b/extra-examples/google-storage-request.json @@ -0,0 +1,11 @@ +{ + "specversion": "1.0", + "id": "storage-event-id", + "datacontenttype": "application/json", + "source": "//local", + "type": "google.cloud.storage.object.v1.finalized", + "data": { + "bucket": "some-bucket", + "name": "folder/Test.cs" + } +} \ No newline at end of file