122 lines
4.6 KiB
C#
122 lines
4.6 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Text;
|
|
using CommandLine;
|
|
using RabbitMQ.Client;
|
|
using Tapeti.Cmd.ASCII;
|
|
using Tapeti.Cmd.Serialization;
|
|
|
|
namespace Tapeti.Cmd.Verbs
|
|
{
|
|
[Verb("export", HelpText = "Fetch messages from a queue and write it to disk.")]
|
|
[ExecutableVerb(typeof(ExportVerb))]
|
|
public class ExportOptions : BaseMessageSerializerOptions
|
|
{
|
|
[Option('q', "queue", Required = true, HelpText = "The queue to read the messages from.")]
|
|
public string QueueName { get; set; }
|
|
|
|
[Option('o', "output", Required = true, HelpText = "Path or filename (depending on the chosen serialization method) where the messages will be output to.")]
|
|
public string OutputPath { get; set; }
|
|
|
|
[Option('r', "remove", HelpText = "If specified messages are acknowledged and removed from the queue. If not messages are kept.")]
|
|
public bool RemoveMessages { get; set; }
|
|
|
|
[Option('n', "maxcount", HelpText = "(Default: all) Maximum number of messages to retrieve from the queue.")]
|
|
public int? MaxCount { get; set; }
|
|
}
|
|
|
|
|
|
public class ExportVerb : IVerbExecuter
|
|
{
|
|
private readonly ExportOptions options;
|
|
|
|
|
|
public ExportVerb(ExportOptions options)
|
|
{
|
|
this.options = options;
|
|
}
|
|
|
|
|
|
public void Execute()
|
|
{
|
|
var factory = new ConnectionFactory
|
|
{
|
|
HostName = options.Host,
|
|
Port = options.Port,
|
|
VirtualHost = options.VirtualHost,
|
|
UserName = options.Username,
|
|
Password = options.Password
|
|
};
|
|
|
|
using var messageSerializer = GetMessageSerializer(options);
|
|
using var connection = factory.CreateConnection();
|
|
using var channel = connection.CreateModel();
|
|
|
|
var totalCount = (int)channel.MessageCount(options.QueueName);
|
|
if (options.MaxCount.HasValue && options.MaxCount.Value < totalCount)
|
|
totalCount = options.MaxCount.Value;
|
|
|
|
Console.WriteLine($"Exporting {totalCount} message{(totalCount != 1 ? "s" : "")} (actual number may differ if queue has active consumers or publishers)");
|
|
var messageCount = 0;
|
|
var cancelled = false;
|
|
|
|
Console.CancelKeyPress += (_, args) =>
|
|
{
|
|
args.Cancel = true;
|
|
cancelled = true;
|
|
};
|
|
|
|
using (var progressBar = new ProgressBar(totalCount))
|
|
{
|
|
while (!cancelled && (!options.MaxCount.HasValue || messageCount < options.MaxCount.Value))
|
|
{
|
|
var result = channel.BasicGet(options.QueueName, false);
|
|
if (result == null)
|
|
// No more messages on the queue
|
|
break;
|
|
|
|
messageCount++;
|
|
|
|
messageSerializer.Serialize(new Message
|
|
{
|
|
DeliveryTag = result.DeliveryTag,
|
|
Redelivered = result.Redelivered,
|
|
Exchange = result.Exchange,
|
|
RoutingKey = result.RoutingKey,
|
|
Queue = options.QueueName,
|
|
Properties = result.BasicProperties,
|
|
Body = result.Body.ToArray()
|
|
});
|
|
|
|
if (options.RemoveMessages)
|
|
channel.BasicAck(result.DeliveryTag, false);
|
|
|
|
|
|
progressBar.Report(messageCount);
|
|
}
|
|
}
|
|
|
|
Console.WriteLine($"{messageCount} message{(messageCount != 1 ? "s" : "")} exported.");
|
|
}
|
|
|
|
|
|
private static IMessageSerializer GetMessageSerializer(ExportOptions options)
|
|
{
|
|
switch (options.SerializationMethod)
|
|
{
|
|
case SerializationMethod.SingleFileJSON:
|
|
return new SingleFileJSONMessageSerializer(new FileStream(options.OutputPath, FileMode.Create, FileAccess.Write, FileShare.Read), true, Encoding.UTF8);
|
|
|
|
case SerializationMethod.EasyNetQHosepipe:
|
|
if (string.IsNullOrEmpty(options.OutputPath))
|
|
throw new ArgumentException("An output path must be provided when using EasyNetQHosepipe serialization");
|
|
|
|
return new EasyNetQMessageSerializer(options.OutputPath);
|
|
|
|
default:
|
|
throw new ArgumentOutOfRangeException(nameof(options.SerializationMethod), options.SerializationMethod, "Invalid SerializationMethod");
|
|
}
|
|
}
|
|
}
|
|
}
|