// // 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) }; } }