A src/PacketLogger/Models/Packets/FilePacketProvider.cs => src/PacketLogger/Models/Packets/FilePacketProvider.cs +98 -0
@@ 0,0 1,98 @@
+//
+// FilePacketProvider.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.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using DynamicData;
+using NosSmooth.PacketSerializer.Abstractions.Attributes;
+using PacketLogger.Models.Filters;
+using Remora.Results;
+
+namespace PacketLogger.Models.Packets;
+
+/// <summary>
+/// Provides packets using a file from the file system.
+/// </summary>
+public class FilePacketProvider : IPacketProvider
+{
+ private readonly string _fileName;
+ private IReadOnlyList<PacketInfo>? _packets;
+ private ObservableCollection<PacketInfo>? _filteredPackets;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="FilePacketProvider"/> class.
+ /// </summary>
+ /// <param name="fileName">The name of the file.</param>
+ public FilePacketProvider(string fileName)
+ {
+ _fileName = fileName;
+ }
+
+ /// <inheritdoc />
+ public bool IsOpen => false;
+
+ /// <inheritdoc />
+ public SourceList<PacketInfo> Packets => throw new InvalidOperationException("File client not initialized yet.");
+
+ /// <inheritdoc/>
+ public async Task<Result> Open()
+ {
+ if (!File.Exists(_fileName))
+ {
+ return new NotFoundError($"Could not find file {_fileName}");
+ }
+
+ var packets = new List<PacketInfo>();
+ var index = 0;
+ foreach (var line in await File.ReadAllLinesAsync(_fileName))
+ {
+ if (line.Length <= 1)
+ {
+ continue;
+ }
+
+ var splitted = line.Split('\t', 3);
+ if (splitted.Length != 3)
+ {
+ continue;
+ }
+
+ packets.Add
+ (
+ new PacketInfo
+ (
+ index++,
+ DateTime.Parse(splitted[0].Trim('[', ']')),
+ splitted[1] == "[Recv]" ? PacketSource.Server : PacketSource.Client,
+ splitted[2]
+ )
+ );
+ }
+
+ _packets = packets.AsReadOnly();
+ _filteredPackets = new ObservableCollection<PacketInfo>(_packets);
+ return Result.FromSuccess();
+ }
+
+ /// <inheritdoc/>
+ public Task<Result> Close()
+ => Task.FromResult(Result.FromSuccess());
+
+ /// <inheritdoc />
+ public void Clear()
+ {
+ // Clearing packets from file does not make any sense...
+ }
+
+ /// <inheritdoc />
+ public event PropertyChangedEventHandler? PropertyChanged;
+}<
\ No newline at end of file
A src/PacketLogger/Models/Packets/IPacketProvider.cs => src/PacketLogger/Models/Packets/IPacketProvider.cs +48 -0
@@ 0,0 1,48 @@
+//
+// IPacketProvider.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.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Threading.Tasks;
+using DynamicData;
+using PacketLogger.Models.Filters;
+using Remora.Results;
+
+namespace PacketLogger.Models.Packets;
+
+/// <summary>
+/// Provides packets from some kind of a source.
+/// </summary>
+public interface IPacketProvider : INotifyPropertyChanged
+{
+ /// <summary>
+ /// Gets whether <see cref="Open"/> was called and successfully finished.
+ /// </summary>
+ public bool IsOpen { get; }
+
+ /// <summary>
+ /// Gets the filtered packets from this provider.
+ /// </summary>
+ public SourceList<PacketInfo> Packets { get; }
+
+ /// <summary>
+ /// Open the provider/connection, load etc.
+ /// </summary>
+ /// <returns>A result that may or may not have succeeded.</returns>
+ public Task<Result> Open();
+
+ /// <summary>
+ /// Close the connection, dispose.
+ /// </summary>
+ /// <returns>A result that may or may not have succeeded.</returns>
+ public Task<Result> Close();
+
+ /// <summary>
+ /// Clear all packets.
+ /// </summary>
+ public void Clear();
+}<
\ No newline at end of file
A src/PacketLogger/Models/Packets/IPacketSender.cs => src/PacketLogger/Models/Packets/IPacketSender.cs +34 -0
@@ 0,0 1,34 @@
+//
+// IPacketSender.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.Threading;
+using System.Threading.Tasks;
+using Avalonia.Controls;
+using Remora.Results;
+
+namespace PacketLogger.Models.Packets;
+
+/// <summary>
+/// A provider that may as well send or receive packets.
+/// </summary>
+public interface IPacketSender : IPacketProvider
+{
+ /// <summary>
+ /// Send the given packets.
+ /// </summary>
+ /// <param name="packetString">The packet to send.</param>
+ /// <param name="ct">The cancellation token used for cancelling the operation.</param>
+ /// <returns>A result that may or may not have succeeded.</returns>
+ Task<Result> SendPacket(string packetString, CancellationToken ct = default);
+
+ /// <summary>
+ /// Receive the given packet.
+ /// </summary>
+ /// <param name="packetString">The packet to send.</param>
+ /// <param name="ct">The cancellation token used for cancelling the operation.</param>
+ /// <returns>A result that may or may not have succeeded.</returns>
+ Task<Result> ReceivePacket(string packetString, CancellationToken ct = default);
+}<
\ No newline at end of file
A src/PacketLogger/Models/Packets/PacketInfo.cs => src/PacketLogger/Models/Packets/PacketInfo.cs +12 -0
@@ 0,0 1,12 @@
+//
+// PacketInfo.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 NosSmooth.PacketSerializer.Abstractions.Attributes;
+
+namespace PacketLogger.Models.Packets;
+
+public record PacketInfo(long PacketIndex, DateTime Date, PacketSource Source, string PacketString);<
\ No newline at end of file