Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(bindings): add amqp bindings #153

Merged
merged 1 commit into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading