Skip to content

Commit

Permalink
feat(bindings): add amqp bindings (#153)
Browse files Browse the repository at this point in the history
  • Loading branch information
VisualBean authored Mar 25, 2024
1 parent 9291da6 commit 8d128db
Show file tree
Hide file tree
Showing 13 changed files with 596 additions and 12 deletions.
86 changes: 86 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/AMQP/AMQPChannelBinding.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (c) The LEGO Group. All rights reserved.

namespace LEGO.AsyncAPI.Bindings.AMQP
{
using System;
using LEGO.AsyncAPI.Models;
using LEGO.AsyncAPI.Readers.ParseNodes;
using LEGO.AsyncAPI.Writers;

/// <summary>
/// Binding class for AMQP channel settings.
/// </summary>
public class AMQPChannelBinding : ChannelBinding<AMQPChannelBinding>
{
/// <summary>
/// Defines what type of channel is it. Can be either queue or routingKey.
/// </summary>
public ChannelType Is { get; set; }

/// <summary>
/// When is=routingKey, this object defines the exchange properties.
/// </summary>
public Exchange Exchange { get; set; }

/// <summary>
/// When is=queue, this object defines the queue properties.
/// </summary>
public Queue Queue { get; set; }

public override string BindingKey => "amqp";

protected override FixedFieldMap<AMQPChannelBinding> FixedFieldMap => new ()
{
{ "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
{ "is", (a, n) => { a.Is = n.GetScalarValue().GetEnumFromDisplayName<ChannelType>(); } },
{ "exchange", (a, n) => { a.Exchange = n.ParseMap(ExchangeFixedFields); } },
{ "queue", (a, n) => { a.Queue = n.ParseMap(QueueFixedFields); } },
};

private static FixedFieldMap<Exchange> ExchangeFixedFields = new ()
{
{ "name", (a, n) => { a.Name = n.GetScalarValue(); } },
{ "durable", (a, n) => { a.Durable = n.GetBooleanValue(); } },
{ "type", (a, n) => { a.Type = n.GetScalarValue().GetEnumFromDisplayName<ExchangeType>(); } },
{ "autoDelete", (a, n) => { a.AutoDelete = n.GetBooleanValue(); } },
{ "vhost", (a, n) => { a.Vhost = n.GetScalarValue(); } },
};

private static FixedFieldMap<Queue> QueueFixedFields = new()
{
{ "name", (a, n) => { a.Name = n.GetScalarValue(); } },
{ "durable", (a, n) => { a.Durable = n.GetBooleanValue(); } },
{ "exclusive", (a, n) => { a.Exclusive = n.GetBooleanValue(); } },
{ "autoDelete", (a, n) => { a.AutoDelete = n.GetBooleanValue(); } },
{ "vhost", (a, n) => { a.Vhost = n.GetScalarValue(); } },
};

/// <summary>
/// Serialize to AsyncAPI V2 document without using reference.
/// </summary>
public override void SerializeProperties(IAsyncApiWriter writer)
{
if (writer is null)
{
throw new ArgumentNullException(nameof(writer));
}

writer.WriteStartObject();
writer.WriteRequiredProperty("is", this.Is.GetDisplayName());
switch (this.Is)
{
case ChannelType.RoutingKey:
writer.WriteOptionalObject("exchange", this.Exchange, (w, t) => t.Serialize(w));
break;
case ChannelType.Queue:
writer.WriteOptionalObject("queue", this.Queue, (w, t) => t.Serialize(w));
break;
}

writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
writer.WriteExtensions(this.Extensions);

writer.WriteEndObject();
}
}
}
51 changes: 51 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/AMQP/AMQPMessageBinding.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) The LEGO Group. All rights reserved.

namespace LEGO.AsyncAPI.Bindings.AMQP
{
using System;
using LEGO.AsyncAPI.Models;
using LEGO.AsyncAPI.Readers.ParseNodes;
using LEGO.AsyncAPI.Writers;

/// <summary>
/// Binding class for AMQP messages.
/// </summary>
public class AMQPMessageBinding : MessageBinding<AMQPMessageBinding>
{
/// <summary>
/// A MIME encoding for the message content.
/// </summary>
public string ContentEncoding { get; set; }

/// <summary>
/// Application-specific message type.
/// </summary>
public string MessageType { get; set; }

public override void SerializeProperties(IAsyncApiWriter writer)
{
if (writer is null)
{
throw new ArgumentNullException(nameof(writer));
}

writer.WriteStartObject();

writer.WriteOptionalProperty("contentEncoding", this.ContentEncoding);
writer.WriteOptionalProperty("messageType", this.MessageType);
writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
writer.WriteExtensions(this.Extensions);

writer.WriteEndObject();
}

public override string BindingKey => "amqp";

protected override FixedFieldMap<AMQPMessageBinding> FixedFieldMap => new ()
{
{ "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
{ "contentEncoding", (a, n) => { a.ContentEncoding = n.GetScalarValue(); } },
{ "messageType", (a, n) => { a.MessageType = n.GetScalarValue(); } },
};
}
}
103 changes: 103 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/AMQP/AMQPOperationBinding.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright (c) The LEGO Group. All rights reserved.

namespace LEGO.AsyncAPI.Bindings.AMQP
{
using System;
using System.Collections.Generic;
using LEGO.AsyncAPI.Models;
using LEGO.AsyncAPI.Readers;
using LEGO.AsyncAPI.Readers.ParseNodes;
using LEGO.AsyncAPI.Writers;

/// <summary>
/// Binding class for AMQP operations.
/// </summary>
public class AMQPOperationBinding : OperationBinding<AMQPOperationBinding>
{
/// <summary>
/// TTL (Time-To-Live) for the message. It MUST be greater than or equal to zero.
/// </summary>
public uint? Expiration { get; set; }

/// <summary>
/// Identifies the user who has sent the message.
/// </summary>
public string UserId { get; set; }

/// <summary>
/// The routing keys the message should be routed to at the time of publishing.
/// </summary>
public List<string> Cc { get; set; } = new List<string>();

/// <summary>
/// A priority for the message.
/// </summary>
public int? Priority { get; set; }

/// <summary>
/// Delivery mode of the message. Its value MUST be either 1 (transient) or 2 (persistent).
/// </summary>
public DeliveryMode? DeliveryMode { get; set; }

/// <summary>
/// Whether the message is mandatory or not.
/// </summary>
public bool? Mandatory { get; set; }

/// <summary>
/// Like cc but consumers will not receive this information.
/// </summary>
public List<string> Bcc { get; set; } = new List<string>();

/// <summary>
/// Whether the message should include a timestamp or not.
/// </summary>
public bool? Timestamp { get; set; }

/// <summary>
/// Whether the consumer should ack the message or not.
/// </summary>
public bool? Ack { get; set; }

public override string BindingKey => "amqp";

protected override FixedFieldMap<AMQPOperationBinding> FixedFieldMap => new()
{
{ "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
{ "expiration", (a, n) => { a.Expiration = (uint?)n.GetIntegerValueOrDefault(); } },
{ "userId", (a, n) => { a.UserId = n.GetScalarValueOrDefault(); } },
{ "cc", (a, n) => { a.Cc = n.CreateSimpleList(s => s.GetScalarValue()); } },
{ "priority", (a, n) => { a.Priority = n.GetIntegerValueOrDefault(); } },
{ "deliveryMode", (a, n) => { a.DeliveryMode = (DeliveryMode?)n.GetIntegerValueOrDefault(); } },
{ "mandatory", (a, n) => { a.Mandatory = n.GetBooleanValueOrDefault(); } },
{ "bcc", (a, n) => { a.Bcc = n.CreateSimpleList(s => s.GetScalarValue()); } },
{ "timestamp", (a, n) => { a.Timestamp = n.GetBooleanValueOrDefault(); } },
{ "ack", (a, n) => { a.Ack = n.GetBooleanValueOrDefault(); } },
};

/// <summary>
/// Serialize to AsyncAPI V2 document without using reference.
/// </summary>
public override void SerializeProperties(IAsyncApiWriter writer)
{
if (writer is null)
{
throw new ArgumentNullException(nameof(writer));
}

writer.WriteStartObject();
writer.WriteOptionalProperty<int>("expiration", (int)this.Expiration);
writer.WriteOptionalProperty("userId", this.UserId);
writer.WriteOptionalCollection("cc", this.Cc, (w, s) => w.WriteValue(s));
writer.WriteOptionalProperty("priority", this.Priority);
writer.WriteOptionalProperty("deliveryMode", (int?)this.DeliveryMode);
writer.WriteOptionalProperty("mandatory", this.Mandatory);
writer.WriteOptionalCollection("bcc", this.Bcc, (w, s) => w.WriteValue(s));
writer.WriteOptionalProperty("timestamp", this.Timestamp);
writer.WriteOptionalProperty("ack", this.Ack);
writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
writer.WriteExtensions(this.Extensions);
writer.WriteEndObject();
}
}
}
15 changes: 15 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/AMQP/ChannelType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) The LEGO Group. All rights reserved.

namespace LEGO.AsyncAPI.Bindings.AMQP
{
using LEGO.AsyncAPI.Attributes;

public enum ChannelType
{
[Display("routingKey")]
RoutingKey = 0,

[Display("queue")]
Queue,
}
}
15 changes: 15 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/AMQP/DeliveryMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) The LEGO Group. All rights reserved.

namespace LEGO.AsyncAPI.Bindings.AMQP
{
using LEGO.AsyncAPI.Attributes;

public enum DeliveryMode
{
[Display("transient")]
Transient = 1,

[Display("persistent")]
Persistent = 2,
}
}
50 changes: 50 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/AMQP/Exchange.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) The LEGO Group. All rights reserved.

namespace LEGO.AsyncAPI.Bindings.AMQP
{
using LEGO.AsyncAPI.Models;
using LEGO.AsyncAPI.Models.Interfaces;
using LEGO.AsyncAPI.Writers;

/// <summary>
/// Represents an exchange configuration.
/// </summary>
public class Exchange : IAsyncApiElement
{
/// <summary>
/// The name of the exchange. It MUST NOT exceed 255 characters long.
/// </summary>
public string Name { get; set; }

/// <summary>
/// The type of the exchange. Can be either topic, direct, fanout, default, or headers.
/// </summary>
public ExchangeType Type { get; set; }

/// <summary>
/// Whether the exchange should survive broker restarts or not.
/// </summary>
public bool Durable { get; set; }

/// <summary>
/// Whether the exchange should be deleted when the last queue is unbound from it.
/// </summary>
public bool AutoDelete { get; set; }

/// <summary>
/// The virtual host of the exchange. Defaults to /.
/// </summary>
public string Vhost { get; set; } = "/";

public void Serialize(IAsyncApiWriter writer)
{
writer.WriteStartObject();
writer.WriteRequiredProperty(AsyncApiConstants.Name, this.Name);
writer.WriteRequiredProperty(AsyncApiConstants.Type, this.Type.GetDisplayName());
writer.WriteRequiredProperty("durable", this.Durable);
writer.WriteRequiredProperty("autoDelete", this.AutoDelete);
writer.WriteRequiredProperty("vhost", this.Vhost);
writer.WriteEndObject();
}
}
}
24 changes: 24 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/AMQP/ExchangeType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) The LEGO Group. All rights reserved.

namespace LEGO.AsyncAPI.Bindings.AMQP
{
using LEGO.AsyncAPI.Attributes;

public enum ExchangeType
{
[Display("default")]
Default = 0,

[Display("topic")]
Topic,

[Display("direct")]
Direct,

[Display("fanout")]
Fanout,

[Display("headers")]
Headers,
}
}
Loading

0 comments on commit 8d128db

Please sign in to comment.