//
// PacketProcessor.cs
//
// Copyright (c) František Boháček. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Diagnostics;
using Anonymizer.Filters;
using Anonymizer.Movers;
using Anonymizer.Sinks;
using Microsoft.Extensions.Options;
using NosSmooth.Packets;
using NosSmooth.PacketSerializer;
using NosSmooth.PacketSerializer.Abstractions.Attributes;
using Remora.Results;
namespace Anonymizer;
///
/// Processes packets, anonymizes or filters them.
///
public class PacketProcessor
{
private readonly IPacketSerializer _packetSerializer;
private readonly IAnonymizer _anonymizer;
private readonly RegisteredMovers _registeredMovers;
private readonly IReadOnlyList _filters;
private readonly IReadOnlyList _movers;
///
/// Initializes a new instance of the class.
///
/// The packet serializer.
/// The anonymizer.
/// The filters.
/// The movers.
/// The registered movers.
public PacketProcessor
(
IPacketSerializer packetSerializer,
IAnonymizer anonymizer,
IEnumerable filters,
IEnumerable movers,
IOptions registeredMovers
)
{
_packetSerializer = packetSerializer;
_anonymizer = anonymizer;
_registeredMovers = registeredMovers.Value;
_filters = filters.ToList();
_movers = movers.ToList();
}
///
/// Process one packet, anonymize it.
///
/// The packet to anonymize.
/// The processed packet.
public Result ProcessPacket(PacketInfo packetInfo)
{
foreach (var filter in _filters)
{
if (!filter.Filter(packetInfo))
{
return new ProcessedPacket(packetInfo.Packet, packetInfo.Packet, false);
}
}
var header = packetInfo.Packet.Split(' ')[0];
if (!_registeredMovers.ShouldMove(header))
{
return new ProcessedPacket(packetInfo.Packet, packetInfo.Packet, true);
}
var packetResult = _packetSerializer.Deserialize(packetInfo.Packet, packetInfo.Source);
if (!packetResult.IsDefined(out var packet))
{
return Result.FromError(packetResult);
}
foreach (var mover in _movers)
{
if (mover.ShouldHandle(packet))
{
var movedPacket = mover.Move(_anonymizer, packet);
var serializedResult = _packetSerializer.Serialize(movedPacket);
if (!serializedResult.IsDefined(out var serialized))
{
return Result.FromError(serializedResult);
}
return new ProcessedPacket(packetInfo.Packet, serialized, true);
}
}
return new ProcessedPacket(packetInfo.Packet, packetInfo.Packet, true);
}
///
/// Process the whole source and put the processed packets into the given destination.
///
/// The source to get packets from.
/// The destination to put processed packets into.
/// The cancellation token for cancelling the operation.
/// A representing the asynchronous operation.
public async Task ProcessSourceDestination
(IPacketSource source, IPacketDestination destination, CancellationToken ct = default)
{
var errors = new List();
PacketInfo? packetInfo;
while ((packetInfo = await source.TryGetNextPacketAsync(ct)) != null)
{
var processedPacketResult = ProcessPacket(packetInfo);
if (!processedPacketResult.IsDefined(out var processedPacket))
{
errors.Add(Result.FromError(processedPacketResult));
continue;
}
if (processedPacket.Keep)
{
await destination.WritePacketAsync
(
packetInfo with
{
Packet = processedPacket.NewPacketString
},
ct
);
}
}
return errors.Count switch
{
0 => Result.FromSuccess(),
1 => (Result)errors[0],
_ => new AggregateError(errors)
};
}
}