using System.Text;
using RabbitMQ.Client;
using StellaOps.Router.Common.Enums;
using StellaOps.Router.Common.Models;
namespace StellaOps.Router.Transport.RabbitMq;
///
/// Handles serialization and deserialization of frames for RabbitMQ transport.
///
public static class RabbitMqFrameProtocol
{
///
/// Parses a frame from a RabbitMQ message.
///
/// The message body.
/// The message properties.
/// The parsed frame.
public static Frame ParseFrame(ReadOnlyMemory body, IReadOnlyBasicProperties properties)
{
var frameType = ParseFrameType(properties.Type);
var correlationId = properties.CorrelationId;
return new Frame
{
Type = frameType,
CorrelationId = correlationId,
Payload = body
};
}
///
/// Creates BasicProperties for a frame.
///
/// The frame to serialize.
/// The reply queue name.
/// Optional timeout for the message.
/// The basic properties.
public static BasicProperties CreateProperties(Frame frame, string? replyTo, TimeSpan? timeout = null)
{
var props = new BasicProperties
{
Type = frame.Type.ToString(),
Timestamp = new AmqpTimestamp(DateTimeOffset.UtcNow.ToUnixTimeSeconds()),
DeliveryMode = DeliveryModes.Transient // Non-persistent (1)
};
if (!string.IsNullOrEmpty(frame.CorrelationId))
{
props.CorrelationId = frame.CorrelationId;
}
if (!string.IsNullOrEmpty(replyTo))
{
props.ReplyTo = replyTo;
}
if (timeout.HasValue)
{
props.Expiration = ((int)timeout.Value.TotalMilliseconds).ToString();
}
return props;
}
///
/// Parses a FrameType from the message Type property.
///
private static FrameType ParseFrameType(string? type)
{
if (string.IsNullOrEmpty(type))
{
return FrameType.Request;
}
if (Enum.TryParse(type, ignoreCase: true, out var result))
{
return result;
}
return FrameType.Request;
}
///
/// Extracts the connection ID from message properties.
///
/// The message properties.
/// The connection ID.
public static string ExtractConnectionId(IReadOnlyBasicProperties properties)
{
// Use ReplyTo as the basis for connection ID (identifies the instance)
if (!string.IsNullOrEmpty(properties.ReplyTo))
{
// Extract instance ID from queue name like "stella.svc.{instanceId}"
var parts = properties.ReplyTo.Split('.');
if (parts.Length >= 3)
{
return $"rmq-{parts[^1]}";
}
return $"rmq-{properties.ReplyTo}";
}
// Fallback to correlation ID
if (!string.IsNullOrEmpty(properties.CorrelationId))
{
return $"rmq-{properties.CorrelationId[..Math.Min(16, properties.CorrelationId.Length)]}";
}
return $"rmq-{Guid.NewGuid():N}"[..32];
}
}