~ruther/NosTale-PacketLogger

a86fc3866056908d4ac1b67786be05d6bc2764dc — František Boháček 2 years ago 4d6087e
feat: add packet filters
A src/PacketLogger/Models/Filters/CompoundFilter.cs => src/PacketLogger/Models/Filters/CompoundFilter.cs +46 -0
@@ 0,0 1,46 @@
//
//  CompoundFilter.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 PacketLogger.Models.Packets;

namespace PacketLogger.Models.Filters;

/// <summary>
/// A filter created from multiple filters joined by "OR".
/// </summary>
public class CompoundFilter : IFilter
{
    private readonly bool _negate;
    private readonly IFilter[] _filters;

    /// <summary>
    /// Initializes a new instance of the <see cref="CompoundFilter"/> class.
    /// </summary>
    /// <param name="negate">Whether to negate the result (false - whitelist, true - blacklist).</param>
    /// <param name="filters">The filters to use.</param>
    public CompoundFilter(bool negate, params IFilter[] filters)
    {
        _negate = negate;
        _filters = filters;
    }

    /// <inheritdoc />
    public string FilterString => "Many";

    /// <inheritdoc />
    public bool Match(PacketInfo packet)
    {
        foreach (var filter in _filters)
        {
            if (filter.Match(packet))
            {
                return !_negate;
            }
        }

        return _negate;
    }
}
\ No newline at end of file

A src/PacketLogger/Models/Filters/ContainsFilter.cs => src/PacketLogger/Models/Filters/ContainsFilter.cs +36 -0
@@ 0,0 1,36 @@
//
//  ContainsFilter.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;
using PacketLogger.Models.Packets;

namespace PacketLogger.Models.Filters;

/// <summary>
/// Filters packets that contain the given string.
/// </summary>
public class ContainsFilter : IFilter
{
    private readonly string _contains;

    /// <summary>
    /// Initializes a new instance of the <see cref="ContainsFilter"/> class.
    /// </summary>
    /// <param name="contains">The string to filter.</param>
    public ContainsFilter(string contains)
    {
        _contains = contains;
    }

    /// <inheritdoc />
    public string FilterString => _contains;

    /// <inheritdoc />
    public bool Match(PacketInfo packet)
    {
        return packet.PacketString.Contains(_contains, StringComparison.OrdinalIgnoreCase);
    }
}
\ No newline at end of file

A src/PacketLogger/Models/Filters/FilterCreator.cs => src/PacketLogger/Models/Filters/FilterCreator.cs +64 -0
@@ 0,0 1,64 @@
//
//  FilterCreator.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;

namespace PacketLogger.Models.Filters;

/// <summary>
/// A builder/creator of <see cref="IFilter"/>.
/// </summary>
public static class FilterCreator
{
    /// <summary>
    /// A type of a filter.
    /// </summary>
    public enum FilterType
    {
        /// <summary>
        /// <see cref="PacketHeaderFilter"/>.
        /// </summary>
        PacketHeader,

        /// <summary>
        /// <see cref="ContainsFilter"/>.
        /// </summary>
        Contains,

        /// <summary>
        /// <see cref="StartsWithFilter"/>.
        /// </summary>
        StartsWith
    }

    /// <summary>
    /// Information about a filter to create.
    /// </summary>
    /// <param name="Type">The type of the filter.</param>
    /// <param name="Value">The value.</param>
    public record FilterData(FilterType Type, string Value);

    /// <summary>
    /// Build a filter of the given type and value.
    /// </summary>
    /// <param name="type">The type of the filter to build.</param>
    /// <param name="value">The value of the filter.</param>
    /// <returns>A filter.</returns>
    public static IFilter BuildFilter(FilterType type, string value)
    {
        switch (type)
        {
            case FilterType.Contains:
                return new ContainsFilter(value);
            case FilterType.PacketHeader:
                return new PacketHeaderFilter(value);
            case FilterType.StartsWith:
                return new StartsWithFilter(value);
        }

        throw new UnreachableException();
    }
}
\ No newline at end of file

A src/PacketLogger/Models/Filters/IFilter.cs => src/PacketLogger/Models/Filters/IFilter.cs +27 -0
@@ 0,0 1,27 @@
//
//  IFilter.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 PacketLogger.Models.Packets;

namespace PacketLogger.Models.Filters;

/// <summary>
/// Filter a packet.
/// </summary>
public interface IFilter
{
    /// <summary>
    /// The string to filter.
    /// </summary>
    public string FilterString { get; }

    /// <summary>
    /// Match the given packet.
    /// </summary>
    /// <param name="packet">The packet info.</param>
    /// <returns>Whether to keep the packet.</returns>
    public bool Match(PacketInfo packet);
}
\ No newline at end of file

A src/PacketLogger/Models/Filters/PacketHeaderFilter.cs => src/PacketLogger/Models/Filters/PacketHeaderFilter.cs +54 -0
@@ 0,0 1,54 @@
//
//  PacketHeaderFilter.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;
using System.Reflection.Emit;
using System.Reflection.PortableExecutable;
using PacketLogger.Models.Packets;

namespace PacketLogger.Models.Filters;

/// <summary>
/// Filters packets that start with the given header.
/// </summary>
public class PacketHeaderFilter : IFilter
{
    private readonly string _header;

    /// <summary>
    /// Initializes a new instance of the <see cref="PacketHeaderFilter"/> class.
    /// </summary>
    /// <param name="header">The header to filter.</param>
    public PacketHeaderFilter(string header)
    {
        _header = header.Trim();
    }

    /// <inheritdoc />
    public string FilterString => _header;

    /// <inheritdoc/>
    public bool Match(PacketInfo packet)
    {
        var packetString = packet.PacketString;

        var split = ' ';
        if (packetString.StartsWith('#'))
        {
            packetString = packetString.Substring(1);
            split = '^';
        }

        var splitted = packetString.Split(split, 2);

        if (splitted.Length >= 1)
        {
            return string.Compare(splitted[0], _header, StringComparison.OrdinalIgnoreCase) == 0;
        }

        return false;
    }
}
\ No newline at end of file

A src/PacketLogger/Models/Filters/SendRecvFilter.cs => src/PacketLogger/Models/Filters/SendRecvFilter.cs +44 -0
@@ 0,0 1,44 @@
//
//  SendRecvFilter.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 NosSmooth.PacketSerializer.Abstractions.Attributes;
using PacketLogger.Models.Packets;

namespace PacketLogger.Models.Filters;

/// <summary>
/// Filter using different matches for sent and received packets.
/// </summary>
public class SendRecvFilter : IFilter
{
    private readonly IFilter _sendFilter;
    private readonly IFilter _recvFilter;

    /// <summary>
    /// Initializes a new instance of the <see cref="SendRecvFilter"/> class.
    /// </summary>
    /// <param name="sendFilter">The filter for sent packets.</param>
    /// <param name="recvFilter">The filter for received packets.</param>
    public SendRecvFilter(IFilter sendFilter, IFilter recvFilter)
    {
        _sendFilter = sendFilter;
        _recvFilter = recvFilter;
    }

    /// <inheritdoc />
    public string FilterString => "SendRecv";

    /// <inheritdoc />
    public bool Match(PacketInfo packet)
    {
        if (packet.Source == PacketSource.Server)
        {
            return _recvFilter.Match(packet);
        }

        return _sendFilter.Match(packet);
    }
}
\ No newline at end of file

A src/PacketLogger/Models/Filters/StartsWithFilter.cs => src/PacketLogger/Models/Filters/StartsWithFilter.cs +35 -0
@@ 0,0 1,35 @@
//
//  StartsWithFilter.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 PacketLogger.Models.Packets;

namespace PacketLogger.Models.Filters;

/// <summary>
/// Filters packets that start with the given string.
/// </summary>
public class StartsWithFilter : IFilter
{
    private string _startsWith;

    /// <summary>
    /// Initializes a new instance of the <see cref="StartsWithFilter"/> class.
    /// </summary>
    /// <param name="startsWith">The string to filter.</param>
    public StartsWithFilter(string startsWith)
    {
        _startsWith = startsWith;
    }

    /// <inheritdoc />
    public string FilterString => _startsWith;

    /// <inheritdoc />
    public bool Match(PacketInfo packet)
    {
        return packet.PacketString.StartsWith(_startsWith);
    }
}
\ No newline at end of file

Do not follow this link