A src/Samples/ConsolePacketLogger/ClientService.cs => src/Samples/ConsolePacketLogger/ClientService.cs +97 -0
@@ 0,0 1,97 @@
+//
+// ClientService.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 Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using NosSmooth.Comms.Core;
+using NosSmooth.Comms.Data.Messages;
+using NosSmooth.Comms.Local;
+using NosSmooth.Core.Contracts;
+using NosSmooth.Core.Extensions;
+using NosSmooth.PacketSerializer.Extensions;
+using NosSmooth.PacketSerializer.Packets;
+
+namespace ConsolePacketLogger;
+
+/// <inheritdoc />
+public class ClientService : BackgroundService
+{
+ private readonly IPacketTypesRepository _packetTypesRepository;
+ private readonly CommsInjector _injector;
+ private readonly IHostApplicationLifetime _lifetime;
+ private readonly ILogger<ClientService> _logger;
+ private readonly PacketLoggerOptions _options;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ClientService"/> class.
+ /// </summary>
+ /// <param name="packetTypesRepository">The packet types repository.</param>
+ /// <param name="injector">The injector.</param>
+ /// <param name="lifetime">The lifetime.</param>
+ /// <param name="logger">The logger.</param>
+ /// <param name="options">The options.</param>
+ public ClientService
+ (
+ IPacketTypesRepository packetTypesRepository,
+ CommsInjector injector,
+ IHostApplicationLifetime lifetime,
+ ILogger<ClientService> logger,
+ IOptions<PacketLoggerOptions> options
+ )
+ {
+ _packetTypesRepository = packetTypesRepository;
+ _injector = injector;
+ _lifetime = lifetime;
+ _logger = logger;
+ _options = options.Value;
+ }
+
+ /// <inheritdoc />
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+ {
+ var packetsResult = _packetTypesRepository.AddDefaultPackets();
+ if (!packetsResult.IsSuccess)
+ {
+ _logger.LogResultError(packetsResult);
+ }
+
+ var process = Process.GetProcessById(_options.ProcessId);
+ var connectionResult = await _injector.EstablishNamedPipesConnectionAsync
+ (process, stoppingToken, stoppingToken);
+ if (!connectionResult.IsDefined(out var connection))
+ {
+ _logger.LogResultError(connectionResult);
+ _lifetime.StopApplication();
+ return;
+ }
+
+ var handshakeResponseResult = await connection.Connection
+ .ContractHanshake(new HandshakeRequest("ConsolePacketLogger example", true, false))
+ .WaitForAsync(DefaultStates.ResponseObtained, ct: stoppingToken);
+
+ if (!handshakeResponseResult.IsDefined(out var handshakeResponse))
+ {
+ _logger.LogResultError(handshakeResponseResult);
+ _lifetime.StopApplication();
+ return;
+ }
+
+ _logger.LogInformation
+ (
+ $"Connected to {handshakeResponse.CharacterName ?? "Not in game"} ({handshakeResponse.CharacterId?.ToString() ?? "Not in game"})"
+ );
+
+ var runResult = await connection.Connection.RunHandlerAsync(stoppingToken);
+ if (!runResult.IsSuccess)
+ {
+ _logger.LogResultError(runResult);
+ }
+
+ _lifetime.StopApplication();
+ }
+}<
\ No newline at end of file
A src/Samples/ConsolePacketLogger/ConsolePacketLogger.csproj => src/Samples/ConsolePacketLogger/ConsolePacketLogger.csproj +29 -0
@@ 0,0 1,29 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <TargetFramework>net7.0</TargetFramework>
+ <ImplicitUsings>enable</ImplicitUsings>
+ <Nullable>enable</Nullable>
+ <ApplicationManifest>app.manifest</ApplicationManifest>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="MessagePack" Version="2.4.59" />
+ <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
+ <PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
+ <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
+ <PackageReference Include="Spectre.Console" Version="0.46.0" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\..\Core\NosSmooth.Comms.Abstractions\NosSmooth.Comms.Abstractions.csproj" />
+ <ProjectReference Include="..\..\Core\NosSmooth.Comms.Core\NosSmooth.Comms.Core.csproj" />
+ <ProjectReference Include="..\..\Core\NosSmooth.Comms.NamedPipes\NosSmooth.Comms.NamedPipes.csproj" />
+ <ProjectReference Include="..\..\Core\NosSmooth.Comms.Tcp\NosSmooth.Comms.Tcp.csproj" />
+ <ProjectReference Include="..\..\Local\NosSmooth.Comms.Inject\NosSmooth.Comms.Inject.csproj" />
+ <ProjectReference Include="..\..\Local\NosSmooth.Comms.LocalData\NosSmooth.Comms.LocalData.csproj" />
+ <ProjectReference Include="..\..\Local\NosSmooth.Comms.Local\NosSmooth.Comms.Local.csproj" />
+ </ItemGroup>
+
+</Project>
A src/Samples/ConsolePacketLogger/EveryPacketResponder.cs => src/Samples/ConsolePacketLogger/EveryPacketResponder.cs +24 -0
@@ 0,0 1,24 @@
+//
+// EveryPacketResponder.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.Core.Packets;
+using NosSmooth.Packets;
+using NosSmooth.PacketSerializer.Abstractions.Attributes;
+using Remora.Results;
+
+namespace ConsolePacketLogger;
+
+/// <inheritdoc />
+public class EveryPacketResponder : IEveryPacketResponder
+{
+ /// <inheritdoc />
+ public Task<Result> Respond<TPacket>(PacketEventArgs<TPacket> packetArgs, CancellationToken ct = default)
+ where TPacket : IPacket
+ {
+ Console.WriteLine((packetArgs.Source == PacketSource.Server ? "[Recv]\t" : "[Sent]\t") + packetArgs.PacketString);
+ return Task.FromResult(Result.FromSuccess());
+ }
+}<
\ No newline at end of file
A src/Samples/ConsolePacketLogger/PacketLoggerOptions.cs => src/Samples/ConsolePacketLogger/PacketLoggerOptions.cs +18 -0
@@ 0,0 1,18 @@
+//
+// PacketLoggerOptions.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.
+
+namespace ConsolePacketLogger;
+
+/// <summary>
+/// Options telling the process to inject into.
+/// </summary>
+public class PacketLoggerOptions
+{
+ /// <summary>
+ /// Gets or sets the id of the process to connect to.
+ /// </summary>
+ public int ProcessId { get; set; }
+}<
\ No newline at end of file
A src/Samples/ConsolePacketLogger/Program.cs => src/Samples/ConsolePacketLogger/Program.cs +75 -0
@@ 0,0 1,75 @@
+//
+// Program.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 ConsolePacketLogger;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using NosSmooth.Comms.Core.Extensions;
+using NosSmooth.Comms.Local;
+using NosSmooth.Comms.Local.Extensions;
+using NosSmooth.Core.Extensions;
+using NosSmooth.Data.Abstractions;
+using NosSmooth.LocalBinding;
+using Spectre.Console;
+
+/// <summary>
+/// A class with main.
+/// </summary>
+public static class Program
+{
+ /// <summary>
+ /// A main.
+ /// </summary>
+ /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
+ public static async Task Main()
+ {
+ var processInitResults = CommsInjector.CreateNostaleProcesssesBrowsers().ToArray();
+
+ if (processInitResults.Length == 0)
+ {
+ Console.WriteLine("Could not find any NosTale processes.");
+ return;
+ }
+
+ foreach (var initResult in processInitResults.Where(x => !x.IsSuccess))
+ {
+ Console.WriteLine($"There was an error initializing browser manager for a process.");
+ Console.WriteLine(initResult.ToFullString());
+ }
+
+ var nostaleProcesses = processInitResults.Where(x => x.IsSuccess).Select(x => x.Entity);
+
+ var selectedProcess = AnsiConsole.Prompt
+ (
+ new SelectionPrompt<NosBrowserManager>()
+ .Title("Choose NosTale process to log packets from.")
+ .UseConverter
+ (
+ x => x.IsInGame
+ ? $"{x.PlayerManager.Player.Name} ({x.Process.ProcessName} - {x.Process.Id})"
+ : $"Not in game ({x.Process.ProcessName} - {x.Process.Id})"
+ )
+ .AddChoices(nostaleProcesses)
+ );
+
+ var host = new HostBuilder()
+ .ConfigureLogging(b => b.ClearProviders().AddConsole())
+ .ConfigureServices
+ (
+ s => s
+ .Configure<PacketLoggerOptions>(o => o.ProcessId = selectedProcess.Process.Id)
+ .AddNostaleCore()
+ .AddSingleClientHandling()
+ .AddLocalComms()
+ .AddHostedService<ClientService>()
+ .AddPacketResponder<EveryPacketResponder>()
+ )
+ .Build();
+
+ await host.RunAsync();
+ }
+}<
\ No newline at end of file
A src/Samples/ConsolePacketLogger/app.manifest => src/Samples/ConsolePacketLogger/app.manifest +11 -0
@@ 0,0 1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
+ <assemblyIdentity version="1.0.0.0" name="ConsolePacketLogger.app"/>
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+ <security>
+ <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
+ <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+</assembly><
\ No newline at end of file