2016-06-20 10:30:03 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2016-06-20 21:22:20 +00:00
|
|
|
|
using System.Globalization;
|
2016-06-20 10:30:03 +00:00
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
2016-06-20 21:22:20 +00:00
|
|
|
|
using PettingZoo.Properties;
|
|
|
|
|
using RabbitMQ.Client;
|
|
|
|
|
using RabbitMQ.Client.Events;
|
2016-06-20 10:30:03 +00:00
|
|
|
|
|
2016-07-12 14:57:24 +00:00
|
|
|
|
namespace PettingZoo.Connection
|
2016-06-18 14:50:32 +00:00
|
|
|
|
{
|
|
|
|
|
public class RabbitMQClientConnection : IConnection
|
|
|
|
|
{
|
2016-06-21 09:43:51 +00:00
|
|
|
|
private const int ConnectRetryDelay = 5000;
|
|
|
|
|
|
2016-06-20 21:22:20 +00:00
|
|
|
|
private readonly CancellationTokenSource connectionTaskToken;
|
|
|
|
|
private RabbitMQ.Client.IConnection connection;
|
|
|
|
|
private IModel model;
|
|
|
|
|
|
|
|
|
|
|
2016-06-21 09:43:51 +00:00
|
|
|
|
public event EventHandler<StatusChangedEventArgs> StatusChanged;
|
2016-06-20 21:22:20 +00:00
|
|
|
|
public event EventHandler<MessageReceivedEventArgs> MessageReceived;
|
|
|
|
|
|
2016-06-20 10:30:03 +00:00
|
|
|
|
|
2016-06-18 14:50:32 +00:00
|
|
|
|
public RabbitMQClientConnection(ConnectionInfo connectionInfo)
|
|
|
|
|
{
|
2016-06-20 21:22:20 +00:00
|
|
|
|
connectionTaskToken = new CancellationTokenSource();
|
|
|
|
|
var connectionToken = connectionTaskToken.Token;
|
|
|
|
|
|
|
|
|
|
Task.Factory.StartNew(() => TryConnection(connectionInfo, connectionToken), connectionToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
connectionTaskToken.Cancel();
|
2016-06-20 10:30:03 +00:00
|
|
|
|
|
2016-06-20 21:22:20 +00:00
|
|
|
|
if (model != null)
|
2016-06-20 10:30:03 +00:00
|
|
|
|
{
|
2016-06-20 21:22:20 +00:00
|
|
|
|
model.Dispose();
|
|
|
|
|
model = null;
|
|
|
|
|
}
|
2016-06-20 10:30:03 +00:00
|
|
|
|
|
2016-06-20 21:22:20 +00:00
|
|
|
|
if (connection != null)
|
|
|
|
|
{
|
|
|
|
|
connection.Dispose();
|
|
|
|
|
connection = null;
|
|
|
|
|
}
|
2016-06-21 09:43:51 +00:00
|
|
|
|
|
|
|
|
|
StatusChanged = null;
|
|
|
|
|
MessageReceived = null;
|
2016-06-18 14:50:32 +00:00
|
|
|
|
}
|
2016-06-18 18:30:12 +00:00
|
|
|
|
|
|
|
|
|
|
2016-06-20 21:22:20 +00:00
|
|
|
|
private void TryConnection(ConnectionInfo connectionInfo, CancellationToken cancellationToken)
|
2016-06-18 18:30:12 +00:00
|
|
|
|
{
|
2016-06-20 21:22:20 +00:00
|
|
|
|
var factory = new ConnectionFactory
|
|
|
|
|
{
|
|
|
|
|
HostName = connectionInfo.Host,
|
|
|
|
|
Port = connectionInfo.Port,
|
|
|
|
|
VirtualHost = connectionInfo.VirtualHost,
|
|
|
|
|
UserName = connectionInfo.Username,
|
|
|
|
|
Password = connectionInfo.Password
|
|
|
|
|
};
|
|
|
|
|
|
2016-06-21 15:05:14 +00:00
|
|
|
|
var statusContext = String.Format("{0}:{1}{2}", connectionInfo.Host, connectionInfo.Port, connectionInfo.VirtualHost);
|
2016-06-20 21:22:20 +00:00
|
|
|
|
|
2016-06-21 09:43:51 +00:00
|
|
|
|
while (!cancellationToken.IsCancellationRequested)
|
|
|
|
|
{
|
|
|
|
|
DoStatusChanged(ConnectionStatus.Connecting, statusContext);
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
connection = factory.CreateConnection();
|
|
|
|
|
model = connection.CreateModel();
|
2016-06-20 21:22:20 +00:00
|
|
|
|
|
2016-06-21 09:43:51 +00:00
|
|
|
|
var queueName = model.QueueDeclare().QueueName;
|
|
|
|
|
model.QueueBind(queueName, connectionInfo.Exchange, connectionInfo.RoutingKey);
|
2016-06-20 21:22:20 +00:00
|
|
|
|
|
|
|
|
|
|
2016-06-21 09:43:51 +00:00
|
|
|
|
var consumer = new EventingBasicConsumer(model);
|
|
|
|
|
consumer.Received += ClientReceived;
|
|
|
|
|
|
|
|
|
|
model.BasicConsume(queueName, true, consumer);
|
|
|
|
|
DoStatusChanged(ConnectionStatus.Connected, statusContext);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
DoStatusChanged(ConnectionStatus.Error, e.Message);
|
|
|
|
|
Task.Delay(ConnectRetryDelay, cancellationToken).Wait(cancellationToken);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-06-18 18:30:12 +00:00
|
|
|
|
}
|
2016-06-20 10:30:03 +00:00
|
|
|
|
|
|
|
|
|
|
2016-06-20 21:22:20 +00:00
|
|
|
|
private void ClientReceived(object sender, BasicDeliverEventArgs args)
|
|
|
|
|
{
|
|
|
|
|
if (MessageReceived == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
MessageReceived(this, new MessageReceivedEventArgs(
|
|
|
|
|
new MessageInfo
|
|
|
|
|
{
|
|
|
|
|
Exchange = args.Exchange,
|
|
|
|
|
RoutingKey = args.RoutingKey,
|
|
|
|
|
Body = args.Body,
|
|
|
|
|
Properties = ConvertProperties(args.BasicProperties)
|
|
|
|
|
}
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-06-21 09:43:51 +00:00
|
|
|
|
private void DoStatusChanged(ConnectionStatus status, string context = null)
|
|
|
|
|
{
|
|
|
|
|
if (StatusChanged != null)
|
|
|
|
|
StatusChanged(this, new StatusChangedEventArgs(status, context));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-06-20 21:22:20 +00:00
|
|
|
|
private static Dictionary<string, string> ConvertProperties(IBasicProperties basicProperties)
|
|
|
|
|
{
|
|
|
|
|
var properties = new Dictionary<string, string>();
|
|
|
|
|
|
|
|
|
|
if (basicProperties.IsDeliveryModePresent())
|
|
|
|
|
{
|
|
|
|
|
string deliveryMode;
|
|
|
|
|
|
|
|
|
|
switch (basicProperties.DeliveryMode)
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
|
|
|
|
deliveryMode = Resources.DeliveryModeNonPersistent;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
|
deliveryMode = Resources.DeliveryModePersistent;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
deliveryMode = basicProperties.DeliveryMode.ToString(CultureInfo.InvariantCulture);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
properties.Add(RabbitMQProperties.DeliveryMode, deliveryMode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (basicProperties.IsContentTypePresent())
|
|
|
|
|
properties.Add(RabbitMQProperties.ContentType, basicProperties.ContentType);
|
|
|
|
|
|
|
|
|
|
if (basicProperties.IsContentEncodingPresent())
|
|
|
|
|
properties.Add(RabbitMQProperties.ContentEncoding, basicProperties.ContentEncoding);
|
|
|
|
|
|
|
|
|
|
if (basicProperties.IsPriorityPresent())
|
|
|
|
|
properties.Add(RabbitMQProperties.Priority, basicProperties.Priority.ToString(CultureInfo.InvariantCulture));
|
|
|
|
|
|
|
|
|
|
if (basicProperties.IsCorrelationIdPresent())
|
|
|
|
|
properties.Add(RabbitMQProperties.Priority, basicProperties.CorrelationId);
|
|
|
|
|
|
|
|
|
|
if (basicProperties.IsReplyToPresent())
|
|
|
|
|
properties.Add(RabbitMQProperties.ReplyTo, basicProperties.ReplyTo);
|
|
|
|
|
|
|
|
|
|
if (basicProperties.IsExpirationPresent())
|
|
|
|
|
properties.Add(RabbitMQProperties.Expiration, basicProperties.Expiration);
|
|
|
|
|
|
|
|
|
|
if (basicProperties.IsMessageIdPresent())
|
|
|
|
|
properties.Add(RabbitMQProperties.MessageId, basicProperties.MessageId);
|
|
|
|
|
|
|
|
|
|
if (basicProperties.IsTimestampPresent())
|
|
|
|
|
properties.Add(RabbitMQProperties.Timestamp, basicProperties.Timestamp.UnixTime.ToString(CultureInfo.InvariantCulture));
|
|
|
|
|
|
|
|
|
|
if (basicProperties.IsTypePresent())
|
|
|
|
|
properties.Add(RabbitMQProperties.Type, basicProperties.Type);
|
|
|
|
|
|
|
|
|
|
if (basicProperties.IsUserIdPresent())
|
|
|
|
|
properties.Add(RabbitMQProperties.UserId, basicProperties.UserId);
|
|
|
|
|
|
|
|
|
|
if (basicProperties.IsAppIdPresent())
|
|
|
|
|
properties.Add(RabbitMQProperties.UserId, basicProperties.AppId);
|
|
|
|
|
|
|
|
|
|
if (basicProperties.IsClusterIdPresent())
|
|
|
|
|
properties.Add(RabbitMQProperties.ClusterId, basicProperties.ClusterId);
|
|
|
|
|
|
|
|
|
|
foreach (var header in basicProperties.Headers)
|
|
|
|
|
properties.Add(header.Key, Encoding.UTF8.GetString((byte[])header.Value));
|
|
|
|
|
|
|
|
|
|
return properties;
|
|
|
|
|
}
|
2016-06-18 14:50:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|