/* Copyright 2020 The Knative Authors 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 System; using System.Net; using System.Net.Http; using System.Net.Mime; using System.Text.Json; using System.Threading.Tasks; using CloudEventsSample.Models; using Microsoft.AspNetCore.Mvc; using CloudNative.CloudEvents; using Microsoft.Extensions.Logging; namespace CloudEventsSample.Controllers { [ApiController] [Route("")] public class CloudEventsController : ControllerBase { private const string CloudEventResponseType = "dev.knative.docs.sample"; private const string CloudEventResponseUri = "https://github.com/knative/docs/code-samples/serving/cloudevents/cloudevents-dotnet"; private static readonly Lazy SinkUri = new Lazy(() => Environment.GetEnvironmentVariable("K_SINK")); private readonly ILogger logger; public CloudEventsController(ILogger logger) { this.logger = logger; } /// /// Responds to the post request by calling ReceiveAndReply if K_SINK is not set, /// or by calling ReceiveAndSend if K_SINK is set. /// [HttpPost] public async Task Post([FromBody] CloudEvent receivedEvent) { try { if (string.IsNullOrEmpty(SinkUri.Value)) { return this.ReceiveAndReply(receivedEvent); } else { return await this.ReceiveAndSend(receivedEvent); } } catch (JsonException) { return this.BadRequest("Failed to read the JSON data."); } } /// /// This is called whenever an event is received if K_SINK environment variable is NOT set. /// Replies with a new event. /// private IActionResult ReceiveAndReply(CloudEvent receivedEvent) { this.logger?.LogInformation($"Received event {JsonSerializer.Serialize(receivedEvent)}"); var content = GetResponseForEvent(receivedEvent); this.HttpContext.Response.RegisterForDispose(content); return new CloudEventActionResult(HttpStatusCode.OK, content); } /// /// This is called whenever an event is received if K_SINK environment variable is set. /// Sends a new event to the url in K_SINK. /// private async Task ReceiveAndSend(CloudEvent receivedEvent) { this.logger?.LogInformation($"Received event {JsonSerializer.Serialize(receivedEvent)}"); using var content = GetResponseForEvent(receivedEvent); using var client = new HttpClient(); using var result = await client.PostAsync(SinkUri.Value, content); return this.StatusCode((int)result.StatusCode, await result.Content.ReadAsStringAsync()); } /// /// Respond back with the JSON serialized request. /// [HttpPost, Route("echo")] public ActionResult Echo([FromBody] CloudEvent receivedEvent) { this.logger.LogInformation($"Echo: {JsonSerializer.Serialize(receivedEvent)}"); return this.Ok(JsonSerializer.Serialize(receivedEvent)); } private static CloudEventContent GetResponseForEvent(CloudEvent receivedEvent) { var input = JsonSerializer.Deserialize(receivedEvent.Data.ToString()); var content = new CloudEventContent ( new CloudEvent(CloudEventResponseType, new Uri(CloudEventResponseUri)) { DataContentType = new ContentType(MediaTypeNames.Application.Json), Data = new SampleOutput {Message = $"Hello, {input.Name}"}, }, ContentMode.Structured, new JsonEventFormatter() ); return content; } } }