M Core/NosSmooth.Core/Client/BaseNostaleClient.cs => Core/NosSmooth.Core/Client/BaseNostaleClient.cs +1 -25
@@ 22,53 22,29 @@ namespace NosSmooth.Core.Client;
public abstract class BaseNostaleClient : INostaleClient
{
private readonly CommandProcessor _commandProcessor;
- private readonly IPacketSerializer _packetSerializer;
/// <summary>
/// Initializes a new instance of the <see cref="BaseNostaleClient"/> class.
/// </summary>
/// <param name="commandProcessor">The command processor.</param>
- /// <param name="packetSerializer">The packet serializer.</param>
protected BaseNostaleClient
(
- CommandProcessor commandProcessor,
- IPacketSerializer packetSerializer
+ CommandProcessor commandProcessor
)
{
_commandProcessor = commandProcessor;
- _packetSerializer = packetSerializer;
}
/// <inheritdoc />
public abstract Task<Result> RunAsync(CancellationToken stopRequested = default);
/// <inheritdoc />
- public virtual Task<Result> SendPacketAsync(IPacket packet, CancellationToken ct = default)
- {
- var serialized = _packetSerializer.Serialize(packet);
-
- return serialized.IsSuccess
- ? SendPacketAsync(serialized.Entity, ct)
- : Task.FromResult(Result.FromError(serialized));
- }
-
- /// <inheritdoc />
public abstract Task<Result> SendPacketAsync(string packetString, CancellationToken ct = default);
/// <inheritdoc />
public abstract Task<Result> ReceivePacketAsync(string packetString, CancellationToken ct = default);
/// <inheritdoc />
- public virtual Task<Result> ReceivePacketAsync(IPacket packet, CancellationToken ct = default)
- {
- var serialized = _packetSerializer.Serialize(packet);
-
- return serialized.IsSuccess
- ? ReceivePacketAsync(serialized.Entity, ct)
- : Task.FromResult(Result.FromError(serialized));
- }
-
- /// <inheritdoc />
public Task<Result> SendCommandAsync(ICommand command, CancellationToken ct = default)
=> _commandProcessor.ProcessCommand(this, command, ct);
}
M Core/NosSmooth.Core/Client/INostaleClient.cs => Core/NosSmooth.Core/Client/INostaleClient.cs +0 -16
@@ 25,14 25,6 @@ public interface INostaleClient
public Task<Result> RunAsync(CancellationToken stopRequested = default);
/// <summary>
- /// Sends the given packet to the server.
- /// </summary>
- /// <param name="packet">The packet to send.</param>
- /// <param name="ct">The cancellation token for cancelling the operation.</param>
- /// <returns>A result that may or may not have succeeded.</returns>
- public Task<Result> SendPacketAsync(IPacket packet, CancellationToken ct = default);
-
- /// <summary>
/// Sends the given raw packet string.
/// </summary>
/// <param name="packetString">The packed string to send in plain text.</param>
@@ 49,14 41,6 @@ public interface INostaleClient
public Task<Result> ReceivePacketAsync(string packetString, CancellationToken ct = default);
/// <summary>
- /// Receives the given packet.
- /// </summary>
- /// <param name="packet">The packet to receive.</param>
- /// <param name="ct">The cancellation token for cancelling the operation.</param>
- /// <returns>A result that may or may not have succeeded.</returns>
- public Task<Result> ReceivePacketAsync(IPacket packet, CancellationToken ct = default);
-
- /// <summary>
/// Sends the given command to the client.
/// </summary>
/// <remarks>
A Core/NosSmooth.Core/Client/ManagedNostaleClient.cs => Core/NosSmooth.Core/Client/ManagedNostaleClient.cs +84 -0
@@ 0,0 1,84 @@
+//
+// ManagedNostaleClient.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 NosSmooth.Core.Commands;
+using NosSmooth.Packets;
+using NosSmooth.PacketSerializer;
+using Remora.Results;
+
+namespace NosSmooth.Core.Client;
+
+/// <summary>
+/// A NosTale client that supports sending and receiving packets using .
+/// </summary>
+public class ManagedNostaleClient : INostaleClient
+{
+ private readonly INostaleClient _rawClient;
+ private readonly IPacketSerializer _packetSerializer;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ManagedNostaleClient"/> class.
+ /// </summary>
+ /// <param name="rawClient">The raw nostale client.</param>
+ /// <param name="packetSerializer">The packet serializer.</param>
+ protected ManagedNostaleClient
+ (
+ INostaleClient rawClient,
+ IPacketSerializer packetSerializer
+ )
+ {
+ _rawClient = rawClient;
+ _packetSerializer = packetSerializer;
+ }
+
+ /// <summary>
+ /// Receives the given packet.
+ /// </summary>
+ /// <param name="packet">The packet to receive.</param>
+ /// <param name="ct">The cancellation token for cancelling the operation.</param>
+ /// <returns>A result that may or may not have succeeded.</returns>
+ public Task<Result> ReceivePacketAsync(IPacket packet, CancellationToken ct = default)
+ {
+ var serialized = _packetSerializer.Serialize(packet);
+
+ return serialized.IsSuccess
+ ? ReceivePacketAsync(serialized.Entity, ct)
+ : Task.FromResult(Result.FromError(serialized));
+ }
+
+ /// <summary>
+ /// Sends the given packet to the server.
+ /// </summary>
+ /// <param name="packet">The packet to send.</param>
+ /// <param name="ct">The cancellation token for cancelling the operation.</param>
+ /// <returns>A result that may or may not have succeeded.</returns>
+ public Task<Result> SendPacketAsync(IPacket packet, CancellationToken ct = default)
+ {
+ var serialized = _packetSerializer.Serialize(packet);
+
+ return serialized.IsSuccess
+ ? SendPacketAsync(serialized.Entity, ct)
+ : Task.FromResult(Result.FromError(serialized));
+ }
+
+ /// <inheritdoc />
+ public Task<Result> RunAsync(CancellationToken stopRequested = default)
+ => _rawClient.RunAsync(stopRequested);
+
+ /// <inheritdoc />
+ public Task<Result> SendPacketAsync(string packetString, CancellationToken ct = default)
+ => _rawClient.SendPacketAsync(packetString, ct);
+
+ /// <inheritdoc />
+ public Task<Result> ReceivePacketAsync(string packetString, CancellationToken ct = default)
+ => _rawClient.ReceivePacketAsync(packetString, ct);
+
+ /// <inheritdoc />
+ public Task<Result> SendCommandAsync(ICommand command, CancellationToken ct = default)
+ => _rawClient.SendCommandAsync(command, ct);
+}<
\ No newline at end of file
M Core/NosSmooth.Core/Extensions/ServiceCollectionExtensions.cs => Core/NosSmooth.Core/Extensions/ServiceCollectionExtensions.cs +23 -3
@@ 26,7 26,7 @@ namespace NosSmooth.Core.Extensions;
public static class ServiceCollectionExtensions
{
/// <summary>
- /// Adds base packet and command handling for nostale client.
+ /// Adds base packet (raw packets) and command handling for nostale client.
/// </summary>
/// <param name="serviceCollection">The service collection to register the responder to.</param>
/// <returns>The collection.</returns>
@@ 36,10 36,30 @@ public static class ServiceCollectionExtensions
)
{
serviceCollection
- .TryAddSingleton<PacketHandler>();
+ .TryAddSingleton<IPacketHandler, RawPacketHandler>();
+ serviceCollection.AddSingleton<CommandProcessor>();
+
+ return serviceCollection;
+ }
+ /// <summary>
+ /// Add managed packet handling for nostale client.
+ /// </summary>
+ /// <remarks>
+ /// Adds a managed packet handler that calls managed packet responders.
+ /// Adds contractor and contract packet responder.
+ /// </remarks>
+ /// <param name="serviceCollection">The service collection to register the responder to.</param>
+ /// <returns>The collection.</returns>
+ public static IServiceCollection AddManagedNostaleCore
+ (
+ this IServiceCollection serviceCollection
+ )
+ {
+ serviceCollection.AddNostaleCore();
+ serviceCollection.Replace(ServiceDescriptor.Singleton<IPacketHandler, ManagedPacketHandler>());
serviceCollection.AddPacketSerialization();
- serviceCollection.AddSingleton<CommandProcessor>();
+ serviceCollection.AddTransient<ManagedNostaleClient>();
serviceCollection
.AddSingleton<Contractor>()
A Core/NosSmooth.Core/Packets/IPacketHandler.cs => Core/NosSmooth.Core/Packets/IPacketHandler.cs +36 -0
@@ 0,0 1,36 @@
+//
+// IPacketHandler.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 NosSmooth.Core.Client;
+using NosSmooth.Packets;
+using NosSmooth.PacketSerializer.Abstractions.Attributes;
+using Remora.Results;
+
+namespace NosSmooth.Core.Packets;
+
+/// <summary>
+/// Calls registered responders for the packet that should be handled.
+/// </summary>
+public interface IPacketHandler
+{
+ /// <summary>
+ /// Calls a responder for the given packet.
+ /// </summary>
+ /// <param name="client">The current NosTale client.</param>
+ /// <param name="packetType">The source of the packet.</param>
+ /// <param name="packetString">The string of the packet.</param>
+ /// <param name="ct">The cancellation token for cancelling the operation.</param>
+ /// <returns>A result that may or may not have succeeded.</returns>
+ public Task<Result> HandlePacketAsync
+ (
+ INostaleClient client,
+ PacketSource packetType,
+ string packetString,
+ CancellationToken ct = default
+ );
+}<
\ No newline at end of file
M Core/NosSmooth.Core/Packets/IPostExecutionEvent.cs => Core/NosSmooth.Core/Packets/IPostExecutionEvent.cs +16 -0
@@ 35,4 35,20 @@ public interface IPostExecutionEvent
CancellationToken ct = default
)
where TPacket : IPacket;
+
+ /// <summary>
+ /// Execute the post execution event.
+ /// </summary>
+ /// <param name="client">The NosTale client.</param>
+ /// <param name="packetArgs">The packet arguments.</param>
+ /// <param name="executionResults">The results from the packet responders.</param>
+ /// <param name="ct">The cancellation token for cancelling the operation.</param>
+ /// <returns>A result that may or may not succeed.</returns>
+ public Task<Result> ExecuteAfterExecutionAsync
+ (
+ INostaleClient client,
+ PacketEventArgs packetArgs,
+ IReadOnlyList<Result> executionResults,
+ CancellationToken ct = default
+ );
}=
\ No newline at end of file
M Core/NosSmooth.Core/Packets/IPreExecutionEvent.cs => Core/NosSmooth.Core/Packets/IPreExecutionEvent.cs +17 -0
@@ 35,4 35,21 @@ public interface IPreExecutionEvent
CancellationToken ct = default
)
where TPacket : IPacket;
+
+ /// <summary>
+ /// Execute the pre execution event.
+ /// </summary>
+ /// <remarks>
+ /// If an error is retuned, the packet responders won't be called.
+ /// </remarks>
+ /// <param name="client">The NosTale client.</param>
+ /// <param name="packetArgs">The packet arguments.</param>
+ /// <param name="ct">The cancellation token for cancelling the operation.</param>
+ /// <returns>A result that may or may not succeed.</returns>
+ public Task<Result> ExecuteBeforeExecutionAsync
+ (
+ INostaleClient client,
+ PacketEventArgs packetArgs,
+ CancellationToken ct = default
+ );
}=
\ No newline at end of file
A Core/NosSmooth.Core/Packets/IRawPacketResponder.cs => Core/NosSmooth.Core/Packets/IRawPacketResponder.cs +26 -0
@@ 0,0 1,26 @@
+//
+// IRawPacketResponder.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 Remora.Results;
+
+namespace NosSmooth.Core.Packets;
+
+/// <summary>
+/// Represents interface for classes that respond to packets.
+/// Responds to a raw packet string.
+/// </summary>
+public interface IRawPacketResponder
+{
+ /// <summary>
+ /// Respond to the given packet.
+ /// </summary>
+ /// <param name="packetArgs">The packet to respond to.</param>
+ /// <param name="ct">The cancellation token for cancelling the operation.</param>
+ /// <returns>A result that may or may not have succeeded.</returns>
+ public Task<Result> Respond(PacketEventArgs packetArgs, CancellationToken ct = default);
+}<
\ No newline at end of file
A Core/NosSmooth.Core/Packets/ManagedPacketHandler.cs => Core/NosSmooth.Core/Packets/ManagedPacketHandler.cs +309 -0
@@ 0,0 1,309 @@
+//
+// ManagedPacketHandler.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.Linq;
+using System.Reflection;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using NosSmooth.Core.Client;
+using NosSmooth.Core.Extensions;
+using NosSmooth.Packets;
+using NosSmooth.PacketSerializer;
+using NosSmooth.PacketSerializer.Abstractions.Attributes;
+using NosSmooth.PacketSerializer.Errors;
+using Remora.Results;
+
+namespace NosSmooth.Core.Packets;
+
+/// <summary>
+/// Calls IRawPacketResponder and IPacketResponder{T}.
+/// </summary>
+public class ManagedPacketHandler : IPacketHandler
+{
+ private readonly IServiceProvider _services;
+ private readonly IPacketSerializer _packetSerializer;
+ private readonly ILogger<ManagedPacketHandler> _logger;
+ private readonly IPacketHandler _rawPacketHandler;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ManagedPacketHandler"/> class.
+ /// </summary>
+ /// <param name="services">The service provider.</param>
+ /// <param name="packetSerializer">The packet serializer.</param>
+ /// <param name="logger">The logger.</param>
+ public ManagedPacketHandler
+ (IServiceProvider services, IPacketSerializer packetSerializer, ILogger<ManagedPacketHandler> logger)
+ {
+ _rawPacketHandler = new RawPacketHandler(services);
+ _services = services;
+ _packetSerializer = packetSerializer;
+ _logger = logger;
+ }
+
+ /// <inheritdoc />
+ public async Task<Result> HandlePacketAsync
+ (
+ INostaleClient client,
+ PacketSource packetType,
+ string packetString,
+ CancellationToken ct = default
+ )
+ {
+ var rawResult = await _rawPacketHandler.HandlePacketAsync(client, packetType, packetString, ct);
+
+ IPacket packet;
+ var deserializedResult = _packetSerializer.Deserialize(packetString, packetType);
+ if (!deserializedResult.IsDefined(out var _))
+ {
+ if (deserializedResult.Error is not PacketConverterNotFoundError)
+ {
+ _logger.LogWarning("Could not parse {Packet}. Reason:", packetString);
+ _logger.LogResultError(deserializedResult);
+ packet = new ParsingFailedPacket(deserializedResult, packetString);
+ }
+ else
+ {
+ packet = new UnresolvedPacket(packetString.Split(' ')[0], packetString);
+ }
+ }
+ else
+ {
+ packet = deserializedResult.Entity;
+ }
+
+ var managedResult = await HandlePacketAsync
+ (
+ client,
+ packetType,
+ packet,
+ packetString,
+ ct
+ );
+
+ if (!rawResult.IsSuccess && !managedResult.IsSuccess)
+ {
+ return new AggregateError(rawResult, managedResult);
+ }
+
+ if (!rawResult.IsSuccess)
+ {
+ return rawResult;
+ }
+
+ if (!managedResult.IsSuccess)
+ {
+ return managedResult;
+ }
+
+ return Result.FromSuccess();
+ }
+
+ /// <summary>
+ /// Calls a responder for the given packet.
+ /// </summary>
+ /// <param name="client">The current NosTale client.</param>
+ /// <param name="packetType">The source of the packet.</param>
+ /// <param name="packet">The packet.</param>
+ /// <param name="packetString">The string of the packet.</param>
+ /// <param name="ct">The cancellation token for cancelling the operation.</param>
+ /// <returns>A result that may or may not have succeeded.</returns>
+ private Task<Result> HandlePacketAsync
+ (
+ INostaleClient client,
+ PacketSource packetType,
+ IPacket packet,
+ string packetString,
+ CancellationToken ct = default
+ )
+ {
+ var processMethod = GetType().GetMethod
+ (
+ nameof(DispatchResponder),
+ BindingFlags.NonPublic | BindingFlags.Instance
+ );
+
+ if (processMethod is null)
+ {
+ throw new InvalidOperationException("Could not find process command generic method in command processor.");
+ }
+
+ var boundProcessMethod = processMethod.MakeGenericMethod(packet.GetType());
+ return (Task<Result>)boundProcessMethod.Invoke
+ (
+ this,
+ new object[]
+ {
+ client,
+ packetType,
+ packet,
+ packetString,
+ ct
+ }
+ )!;
+ }
+
+ private async Task<Result> DispatchResponder<TPacket>
+ (
+ INostaleClient client,
+ PacketSource packetType,
+ TPacket packet,
+ string packetString,
+ CancellationToken ct
+ )
+ where TPacket : class, IPacket
+ {
+ using var scope = _services.CreateScope();
+ var packetEventArgs = new PacketEventArgs<TPacket>(packetType, packet, packetString);
+
+ var preExecutionResult = await ExecuteBeforeExecutionAsync(scope.ServiceProvider, client, packetEventArgs, ct);
+ if (!preExecutionResult.IsSuccess)
+ {
+ return preExecutionResult;
+ }
+
+ var packetResponders = scope.ServiceProvider.GetServices<IPacketResponder<TPacket>>();
+ var genericPacketResponders = scope.ServiceProvider.GetServices<IEveryPacketResponder>();
+
+ Result[] results;
+ try
+ {
+ var tasks = packetResponders.Select
+ (responder => SafeCall(() => responder.Respond(packetEventArgs, ct))).ToList();
+ tasks.AddRange
+ (genericPacketResponders.Select(responder => SafeCall(() => responder.Respond(packetEventArgs, ct))));
+
+ results = await Task.WhenAll(tasks);
+ }
+ catch (Exception e)
+ {
+ results = new Result[] { e };
+ }
+
+ var errors = new List<Result>();
+ foreach (var result in results)
+ {
+ if (!result.IsSuccess)
+ {
+ errors.Add(result);
+ }
+ }
+
+ var postExecutionResult = await ExecuteAfterExecutionAsync
+ (
+ scope.ServiceProvider,
+ client,
+ packetEventArgs,
+ results,
+ ct
+ );
+ if (!postExecutionResult.IsSuccess)
+ {
+ errors.Add(postExecutionResult);
+ }
+
+ return errors.Count switch
+ {
+ 0 => Result.FromSuccess(),
+ 1 => errors[0],
+ _ => new AggregateError(errors.Cast<IResult>().ToArray())
+ };
+ }
+
+ private async Task<Result> ExecuteBeforeExecutionAsync<TPacket>
+ (
+ IServiceProvider services,
+ INostaleClient client,
+ PacketEventArgs<TPacket> eventArgs,
+ CancellationToken ct
+ )
+ where TPacket : IPacket
+ {
+ try
+ {
+ var results = await Task.WhenAll
+ (
+ services.GetServices<IPreExecutionEvent>()
+ .Select(x => SafeCall(() => x.ExecuteBeforeExecutionAsync(client, eventArgs, ct)))
+ );
+
+ var errorResults = new List<Result>();
+ foreach (var result in results)
+ {
+ if (!result.IsSuccess)
+ {
+ errorResults.Add(result);
+ }
+ }
+
+ return errorResults.Count switch
+ {
+ 1 => errorResults[0],
+ 0 => Result.FromSuccess(),
+ _ => new AggregateError(errorResults.Cast<IResult>().ToArray())
+ };
+ }
+ catch (Exception e)
+ {
+ return e;
+ }
+ }
+
+ private async Task<Result> ExecuteAfterExecutionAsync<TPacket>
+ (
+ IServiceProvider services,
+ INostaleClient client,
+ PacketEventArgs<TPacket> eventArgs,
+ IReadOnlyList<Result> executionResults,
+ CancellationToken ct
+ )
+ where TPacket : IPacket
+ {
+ try
+ {
+ var results = await Task.WhenAll
+ (
+ services.GetServices<IPostExecutionEvent>()
+ .Select(x => SafeCall(() => x.ExecuteAfterExecutionAsync(client, eventArgs, executionResults, ct)))
+ );
+
+ var errorResults = new List<Result>();
+ foreach (var result in results)
+ {
+ if (!result.IsSuccess)
+ {
+ errorResults.Add(result);
+ }
+ }
+
+ return errorResults.Count switch
+ {
+ 1 => errorResults[0],
+ 0 => Result.FromSuccess(),
+ _ => new AggregateError(errorResults.Cast<IResult>().ToArray())
+ };
+ }
+ catch (Exception e)
+ {
+ return e;
+ }
+ }
+
+ private async Task<Result> SafeCall(Func<Task<Result>> task)
+ {
+ try
+ {
+ return await task();
+ }
+ catch (Exception e)
+ {
+ return e;
+ }
+ }
+}<
\ No newline at end of file
M Core/NosSmooth.Core/Packets/PacketEventArgs.cs => Core/NosSmooth.Core/Packets/PacketEventArgs.cs +7 -0
@@ 9,6 9,13 @@ using NosSmooth.PacketSerializer.Abstractions.Attributes;
namespace NosSmooth.Core.Packets;
/// <summary>
+/// Arguments for <see cref="IPacketResponder{TPacket}"/>, <see cref="IRawPacketResponder"/>.
+/// </summary>
+/// <param name="Source">The source of the packet.</param>
+/// <param name="PacketString">The packet string.</param>
+public record PacketEventArgs(PacketSource Source, string PacketString);
+
+/// <summary>
/// Arguments for <see cref="IPacketResponder{TPacket}"/>
/// </summary>
/// <param name="Source">The source of the packet.</param>
R Core/NosSmooth.Core/Packets/PacketHandler.cs => Core/NosSmooth.Core/Packets/RawPacketHandler.cs +35 -71
@@ 1,5 1,5 @@
-//
-// PacketHandler.cs
+//
+// RawPacketHandler.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.
@@ 7,7 7,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
@@ 19,77 18,33 @@ using Remora.Results;
namespace NosSmooth.Core.Packets;
/// <summary>
-/// Calls registered responders for the packet that should be handled.
+/// Calls IRawPacketResponder.
/// </summary>
-public class PacketHandler
+public class RawPacketHandler : IPacketHandler
{
- private readonly IServiceProvider _provider;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="PacketHandler"/> class.
- /// </summary>
- /// <param name="provider">The dependency injection provider.</param>
- public PacketHandler(IServiceProvider provider)
- {
- _provider = provider;
- }
+ private readonly IServiceProvider _services;
/// <summary>
- /// Calls a responder for the given packet.
+ /// Initializes a new instance of the <see cref="RawPacketHandler"/> class.
/// </summary>
- /// <param name="client">The current NosTale client.</param>
- /// <param name="packetType">The source of the packet.</param>
- /// <param name="packet">The packet.</param>
- /// <param name="packetString">The string of the packet.</param>
- /// <param name="ct">The cancellation token for cancelling the operation.</param>
- /// <returns>A result that may or may not have succeeded.</returns>
- public Task<Result> HandlePacketAsync
- (
- INostaleClient client,
- PacketSource packetType,
- IPacket packet,
- string packetString,
- CancellationToken ct = default
- )
+ /// <param name="services">The serivce provider.</param>
+ public RawPacketHandler(IServiceProvider services)
{
- var processMethod = GetType().GetMethod
- (
- nameof(DispatchResponder),
- BindingFlags.NonPublic | BindingFlags.Instance
- );
-
- if (processMethod is null)
- {
- throw new InvalidOperationException("Could not find process command generic method in command processor.");
- }
+ _services = services;
- var boundProcessMethod = processMethod.MakeGenericMethod(packet.GetType());
- return (Task<Result>)boundProcessMethod.Invoke
- (
- this,
- new object[]
- {
- client,
- packetType,
- packet,
- packetString,
- ct
- }
- )!;
}
- private async Task<Result> DispatchResponder<TPacket>
+ /// <inheritdoc />
+ public async Task<Result> HandlePacketAsync
(
INostaleClient client,
PacketSource packetType,
- TPacket packet,
string packetString,
- CancellationToken ct
+ CancellationToken ct = default
)
- where TPacket : class, IPacket
{
- using var scope = _provider.CreateScope();
- var packetEventArgs = new PacketEventArgs<TPacket>(packetType, packet, packetString);
+ using var scope = _services.CreateScope();
+ var packetEventArgs = new PacketEventArgs(packetType, packetString);
var preExecutionResult = await ExecuteBeforeExecutionAsync(scope.ServiceProvider, client, packetEventArgs, ct);
if (!preExecutionResult.IsSuccess)
@@ 97,14 52,13 @@ public class PacketHandler
return preExecutionResult;
}
- var packetResponders = scope.ServiceProvider.GetServices<IPacketResponder<TPacket>>();
- var genericPacketResponders = scope.ServiceProvider.GetServices<IEveryPacketResponder>();
+ var packetResponders = scope.ServiceProvider.GetServices<IRawPacketResponder>();
Result[] results;
try
{
- var tasks = packetResponders.Select(responder => responder.Respond(packetEventArgs, ct)).ToList();
- tasks.AddRange(genericPacketResponders.Select(responder => responder.Respond(packetEventArgs, ct)));
+ var tasks = packetResponders.Select
+ (responder => SafeCall(() => responder.Respond(packetEventArgs, ct))).ToList();
results = await Task.WhenAll(tasks);
}
@@ 143,21 97,20 @@ public class PacketHandler
};
}
- private async Task<Result> ExecuteBeforeExecutionAsync<TPacket>
+ private async Task<Result> ExecuteBeforeExecutionAsync
(
IServiceProvider services,
INostaleClient client,
- PacketEventArgs<TPacket> eventArgs,
+ PacketEventArgs eventArgs,
CancellationToken ct
)
- where TPacket : IPacket
{
try
{
var results = await Task.WhenAll
(
services.GetServices<IPreExecutionEvent>()
- .Select(x => x.ExecuteBeforeExecutionAsync(client, eventArgs, ct))
+ .Select(x => SafeCall(() => x.ExecuteBeforeExecutionAsync(client, eventArgs, ct)))
);
var errorResults = new List<Result>();
@@ 182,22 135,21 @@ public class PacketHandler
}
}
- private async Task<Result> ExecuteAfterExecutionAsync<TPacket>
+ private async Task<Result> ExecuteAfterExecutionAsync
(
IServiceProvider services,
INostaleClient client,
- PacketEventArgs<TPacket> eventArgs,
+ PacketEventArgs eventArgs,
IReadOnlyList<Result> executionResults,
CancellationToken ct
)
- where TPacket : IPacket
{
try
{
var results = await Task.WhenAll
(
services.GetServices<IPostExecutionEvent>()
- .Select(x => x.ExecuteAfterExecutionAsync(client, eventArgs, executionResults, ct))
+ .Select(x => SafeCall(() => x.ExecuteAfterExecutionAsync(client, eventArgs, executionResults, ct)))
);
var errorResults = new List<Result>();
@@ 221,4 173,16 @@ public class PacketHandler
return e;
}
}
+
+ private async Task<Result> SafeCall(Func<Task<Result>> task)
+ {
+ try
+ {
+ return await task();
+ }
+ catch (Exception e)
+ {
+ return e;
+ }
+ }
}=
\ No newline at end of file
M Core/NosSmooth.Core/Stateful/StatefulPreExecutionEvent.cs => Core/NosSmooth.Core/Stateful/StatefulPreExecutionEvent.cs +10 -1
@@ 41,8 41,17 @@ internal class StatefulPreExecutionEvent : IPreExecutionEvent, IPreCommandExecut
return Task.FromResult(Result.FromSuccess());
}
+ /// <inheritdoc/>
+ public Task<Result> ExecuteBeforeExecutionAsync
+ (INostaleClient client, PacketEventArgs packetArgs, CancellationToken ct = default)
+ {
+ _injector.Client = client;
+ return Task.FromResult(Result.FromSuccess());
+ }
+
/// <inheritdoc />
- public Task<Result> ExecuteBeforeCommandAsync<TCommand>(INostaleClient client, TCommand command, CancellationToken ct = default)
+ public Task<Result> ExecuteBeforeCommandAsync<TCommand>
+ (INostaleClient client, TCommand command, CancellationToken ct = default)
where TCommand : ICommand
{
_injector.Client = client;
M Core/NosSmooth.Game/Apis/Safe/NostaleChatApi.cs => Core/NosSmooth.Game/Apis/Safe/NostaleChatApi.cs +2 -2
@@ 18,13 18,13 @@ namespace NosSmooth.Game.Apis.Safe;
public class NostaleChatApi
{
// TODO: check length of the messages
- private readonly INostaleClient _client;
+ private readonly ManagedNostaleClient _client;
/// <summary>
/// Initializes a new instance of the <see cref="NostaleChatApi"/> class.
/// </summary>
/// <param name="client">The nostale client.</param>
- public NostaleChatApi(INostaleClient client)
+ public NostaleChatApi(ManagedNostaleClient client)
{
_client = client;
}
M Core/NosSmooth.Game/Apis/Safe/NostaleSkillsApi.cs => Core/NosSmooth.Game/Apis/Safe/NostaleSkillsApi.cs +2 -2
@@ 25,7 25,7 @@ namespace NosSmooth.Game.Apis.Safe;
public class NostaleSkillsApi
{
private readonly Game _game;
- private readonly INostaleClient _client;
+ private readonly ManagedNostaleClient _client;
private readonly Contractor _contractor;
/// <summary>
@@ 34,7 34,7 @@ public class NostaleSkillsApi
/// <param name="game">The game.</param>
/// <param name="client">The NosTale client.</param>
/// <param name="contractor">The contractor.</param>
- public NostaleSkillsApi(Game game, INostaleClient client, Contractor contractor)
+ public NostaleSkillsApi(Game game, ManagedNostaleClient client, Contractor contractor)
{
_game = game;
_client = client;
M Core/NosSmooth.Game/Apis/Unsafe/UnsafeInventoryApi.cs => Core/NosSmooth.Game/Apis/Unsafe/UnsafeInventoryApi.cs +2 -2
@@ 23,7 23,7 @@ namespace NosSmooth.Game.Apis.Unsafe;
/// </summary>
public class UnsafeInventoryApi
{
- private readonly INostaleClient _client;
+ private readonly ManagedNostaleClient _client;
private readonly Contractor _contractor;
/// <summary>
@@ 31,7 31,7 @@ public class UnsafeInventoryApi
/// </summary>
/// <param name="client">The nostale client.</param>
/// <param name="contractor">The contractor.</param>
- public UnsafeInventoryApi(INostaleClient client, Contractor contractor)
+ public UnsafeInventoryApi(ManagedNostaleClient client, Contractor contractor)
{
_client = client;
_contractor = contractor;
M Core/NosSmooth.Game/Apis/Unsafe/UnsafeMapApi.cs => Core/NosSmooth.Game/Apis/Unsafe/UnsafeMapApi.cs +2 -2
@@ 19,14 19,14 @@ namespace NosSmooth.Game.Apis.Unsafe;
public class UnsafeMapApi
{
private readonly Game _game;
- private readonly INostaleClient _client;
+ private readonly ManagedNostaleClient _client;
/// <summary>
/// Initializes a new instance of the <see cref="UnsafeMapApi"/> class.
/// </summary>
/// <param name="game">The game.</param>
/// <param name="client">The client.</param>
- public UnsafeMapApi(Game game, INostaleClient client)
+ public UnsafeMapApi(Game game, ManagedNostaleClient client)
{
_game = game;
_client = client;
M Core/NosSmooth.Game/Apis/Unsafe/UnsafeMateApi.cs => Core/NosSmooth.Game/Apis/Unsafe/UnsafeMateApi.cs +2 -2
@@ 17,13 17,13 @@ namespace NosSmooth.Game.Apis.Unsafe;
/// </summary>
public class UnsafeMateApi
{
- private readonly INostaleClient _client;
+ private readonly ManagedNostaleClient _client;
/// <summary>
/// Initializes a new instance of the <see cref="UnsafeMateApi"/> class.
/// </summary>
/// <param name="client">The client.</param>
- public UnsafeMateApi(INostaleClient client)
+ public UnsafeMateApi(ManagedNostaleClient client)
{
_client = client;
}
M Core/NosSmooth.Game/Apis/Unsafe/UnsafeMateSkillsApi.cs => Core/NosSmooth.Game/Apis/Unsafe/UnsafeMateSkillsApi.cs +2 -2
@@ 16,13 16,13 @@ namespace NosSmooth.Game.Apis.Unsafe;
/// </summary>
public class UnsafeMateSkillsApi
{
- private readonly INostaleClient _client;
+ private readonly ManagedNostaleClient _client;
/// <summary>
/// Initializes a new instance of the <see cref="UnsafeMateSkillsApi"/> class.
/// </summary>
/// <param name="client">The client.</param>
- public UnsafeMateSkillsApi(INostaleClient client)
+ public UnsafeMateSkillsApi(ManagedNostaleClient client)
{
_client = client;
}
M Core/NosSmooth.Game/Apis/Unsafe/UnsafeSkillsApi.cs => Core/NosSmooth.Game/Apis/Unsafe/UnsafeSkillsApi.cs +2 -2
@@ 23,7 23,7 @@ namespace NosSmooth.Game.Apis.Unsafe;
/// </summary>
public class UnsafeSkillsApi
{
- private readonly INostaleClient _client;
+ private readonly ManagedNostaleClient _client;
private readonly Game _game;
private readonly Contractor _contractor;
@@ 33,7 33,7 @@ public class UnsafeSkillsApi
/// <param name="client">The nostale client.</param>
/// <param name="game">The game.</param>
/// <param name="contractor">The contractor.</param>
- public UnsafeSkillsApi(INostaleClient client, Game game, Contractor contractor)
+ public UnsafeSkillsApi(ManagedNostaleClient client, Game game, Contractor contractor)
{
_client = client;
_game = game;
M Core/NosSmooth.Game/Extensions/ServiceCollectionExtensions.cs => Core/NosSmooth.Game/Extensions/ServiceCollectionExtensions.cs +1 -1
@@ 41,7 41,7 @@ public static class ServiceCollectionExtensions
public static IServiceCollection AddNostaleGame(this IServiceCollection serviceCollection)
{
serviceCollection
- .AddNostaleCore()
+ .AddManagedNostaleCore()
.AddMemoryCache()
.TryAddScoped<EventDispatcher>();
serviceCollection.TryAddSingleton<Game>();
M Extensions/NosSmooth.Extensions.Combat/CombatManager.cs => Extensions/NosSmooth.Extensions.Combat/CombatManager.cs +2 -2
@@ 20,7 20,7 @@ namespace NosSmooth.Extensions.Combat;
/// </summary>
public class CombatManager : IStatefulEntity
{
- private readonly INostaleClient _client;
+ private readonly ManagedNostaleClient _client;
private readonly Game.Game _game;
/// <summary>
@@ 28,7 28,7 @@ public class CombatManager : IStatefulEntity
/// </summary>
/// <param name="client">The NosTale client.</param>
/// <param name="game">The game.</param>
- public CombatManager(INostaleClient client, Game.Game game)
+ public CombatManager(ManagedNostaleClient client, Game.Game game)
{
_client = client;
_game = game;
M Extensions/NosSmooth.Extensions.Combat/CombatState.cs => Extensions/NosSmooth.Extensions.Combat/CombatState.cs +2 -2
@@ 22,7 22,7 @@ internal class CombatState : ICombatState
/// <param name="client">The NosTale client.</param>
/// <param name="game">The game.</param>
/// <param name="combatManager">The combat manager.</param>
- public CombatState(INostaleClient client, Game.Game game, CombatManager combatManager)
+ public CombatState(ManagedNostaleClient client, Game.Game game, CombatManager combatManager)
{
Client = client;
Game = game;
@@ 43,7 43,7 @@ internal class CombatState : ICombatState
public Game.Game Game { get; }
/// <inheritdoc/>
- public INostaleClient Client { get; }
+ public ManagedNostaleClient Client { get; }
/// <summary>
/// Gets whether the manager may currently quit.
M Extensions/NosSmooth.Extensions.Combat/ICombatState.cs => Extensions/NosSmooth.Extensions.Combat/ICombatState.cs +1 -1
@@ 29,7 29,7 @@ public interface ICombatState
/// <summary>
/// Gets the NosTale client.
/// </summary>
- public INostaleClient Client { get; }
+ public ManagedNostaleClient Client { get; }
/// <summary>
/// Gets whether there is an operation that cannot be used
M Samples/FileClient/Client.cs => Samples/FileClient/Client.cs +3 -27
@@ 24,8 24,7 @@ namespace FileClient;
public class Client : BaseNostaleClient
{
private const string LineRegex = ".*\\[(Recv|Send)\\]\t(.*)";
- private readonly PacketHandler _packetHandler;
- private readonly IPacketSerializer _packetSerializer;
+ private readonly IPacketHandler _packetHandler;
private readonly ILogger<Client> _logger;
private readonly Stream _stream;
@@ 35,21 34,18 @@ public class Client : BaseNostaleClient
/// <param name="stream">The stream with packets.</param>
/// <param name="packetHandler">The packet handler.</param>
/// <param name="commandProcessor">The command processor.</param>
- /// <param name="packetSerializer">The packet serializer.</param>
/// <param name="logger">The logger.</param>
public Client
(
Stream stream,
- PacketHandler packetHandler,
+ IPacketHandler packetHandler,
CommandProcessor commandProcessor,
- IPacketSerializer packetSerializer,
ILogger<Client> logger
)
- : base(commandProcessor, packetSerializer)
+ : base(commandProcessor)
{
_stream = stream;
_packetHandler = packetHandler;
- _packetSerializer = packetSerializer;
_logger = logger;
}
@@ 78,12 74,10 @@ public class Client : BaseNostaleClient
var packetStr = match.Groups[2].Value;
var source = type == "Recv" ? PacketSource.Server : PacketSource.Client;
- var packet = CreatePacket(packetStr, source);
Result result = await _packetHandler.HandlePacketAsync
(
this,
source,
- packet,
packetStr,
stopRequested
);
@@ 103,7 97,6 @@ public class Client : BaseNostaleClient
(
this,
PacketSource.Client,
- CreatePacket(packetString, PacketSource.Client),
packetString,
ct
);
@@ 116,25 109,8 @@ public class Client : BaseNostaleClient
(
this,
PacketSource.Server,
- CreatePacket(packetString, PacketSource.Server),
packetString,
ct
);
}
-
- private IPacket CreatePacket(string packetStr, PacketSource source)
- {
- var packetResult = _packetSerializer.Deserialize(packetStr, source);
- if (!packetResult.IsSuccess)
- {
- if (packetResult.Error is PacketConverterNotFoundError err)
- {
- return new UnresolvedPacket(err.Header, packetStr);
- }
-
- return new ParsingFailedPacket(packetResult, packetStr);
- }
-
- return packetResult.Entity;
- }
}=
\ No newline at end of file
M Samples/FileClient/Program.cs => Samples/FileClient/Program.cs +2 -3
@@ 46,7 46,7 @@ public static class Program
{
coll.AddHostedService<App>();
- coll.AddNostaleCore()
+ coll.AddManagedNostaleCore()
.AddNostaleGame()
.AddNostaleDataFiles()
.AddPacketResponder<PacketNotFoundResponder>()
@@ 57,9 57,8 @@ public static class Program
});
coll.AddSingleton<INostaleClient>(p => new Client(
fileStream,
- p.GetRequiredService<PacketHandler>(),
+ p.GetRequiredService<IPacketHandler>(),
p.GetRequiredService<CommandProcessor>(),
- p.GetRequiredService<IPacketSerializer>(),
p.GetRequiredService<ILogger<Client>>()
));
})
M Tests/NosSmooth.Core.Tests/Fakes/FakeEmptyNostaleClient.cs => Tests/NosSmooth.Core.Tests/Fakes/FakeEmptyNostaleClient.cs +0 -12
@@ 24,12 24,6 @@ public class FakeEmptyNostaleClient : INostaleClient
}
/// <inheritdoc />
- public Task<Result> SendPacketAsync(IPacket packet, CancellationToken ct = default)
- {
- throw new NotImplementedException();
- }
-
- /// <inheritdoc />
public Task<Result> SendPacketAsync(string packetString, CancellationToken ct = default)
{
throw new NotImplementedException();
@@ 42,12 36,6 @@ public class FakeEmptyNostaleClient : INostaleClient
}
/// <inheritdoc />
- public Task<Result> ReceivePacketAsync(IPacket packet, CancellationToken ct = default)
- {
- throw new NotImplementedException();
- }
-
- /// <inheritdoc />
public Task<Result> SendCommandAsync(ICommand command, CancellationToken ct = default)
{
throw new NotImplementedException();
A Tests/NosSmooth.Core.Tests/Fakes/FakeLogger.cs => Tests/NosSmooth.Core.Tests/Fakes/FakeLogger.cs +39 -0
@@ 0,0 1,39 @@
+//
+// FakeLogger.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 Microsoft.Extensions.Logging;
+
+namespace NosSmooth.Core.Tests.Fakes;
+
+/// <inheritdoc />
+public class FakeLogger<T> : ILogger<T>
+{
+ /// <inheritdoc />
+ public void Log<TState>
+ (
+ LogLevel logLevel,
+ EventId eventId,
+ TState state,
+ Exception? exception,
+ Func<TState, Exception?, string> formatter
+ )
+ {
+ }
+
+ /// <inheritdoc />
+ public bool IsEnabled(LogLevel logLevel)
+ {
+ return true;
+ }
+
+ /// <inheritdoc />
+ public IDisposable? BeginScope<TState>(TState state)
+ where TState : notnull
+ {
+ return null;
+ }
+}<
\ No newline at end of file
M Tests/NosSmooth.Core.Tests/Fakes/FakeNostaleClient.cs => Tests/NosSmooth.Core.Tests/Fakes/FakeNostaleClient.cs +0 -12
@@ 37,12 37,6 @@ public class FakeNostaleClient : INostaleClient
}
/// <inheritdoc />
- public Task<Result> SendPacketAsync(IPacket packet, CancellationToken ct = default)
- {
- throw new System.NotImplementedException();
- }
-
- /// <inheritdoc />
public Task<Result> SendPacketAsync(string packetString, CancellationToken ct = default)
{
throw new System.NotImplementedException();
@@ 55,12 49,6 @@ public class FakeNostaleClient : INostaleClient
}
/// <inheritdoc />
- public Task<Result> ReceivePacketAsync(IPacket packet, CancellationToken ct = default)
- {
- throw new System.NotImplementedException();
- }
-
- /// <inheritdoc />
public Task<Result> SendCommandAsync(ICommand command, CancellationToken ct = default)
=> Task.FromResult(_handleCommand(command, ct));
}=
\ No newline at end of file
M Tests/NosSmooth.Core.Tests/Fakes/Packets/Events/PacketEvent.cs => Tests/NosSmooth.Core.Tests/Fakes/Packets/Events/PacketEvent.cs +15 -0
@@ 47,6 47,11 @@ public class PacketEvent : IPreExecutionEvent, IPostExecutionEvent
=> Task.FromResult(_preHandler(client, packetArgs.Source, packetArgs.Packet, packetArgs.PacketString));
/// <inheritdoc />
+ public Task<Result> ExecuteBeforeExecutionAsync
+ (INostaleClient client, PacketEventArgs packetArgs, CancellationToken ct = default)
+ => Task.FromResult(Result.FromSuccess());
+
+ /// <inheritdoc />
public Task<Result> ExecuteAfterExecutionAsync<TPacket>
(
INostaleClient client,
@@ 66,4 71,14 @@ public class PacketEvent : IPreExecutionEvent, IPostExecutionEvent
executionResults
)
);
+
+ /// <inheritdoc />
+ public Task<Result> ExecuteAfterExecutionAsync
+ (
+ INostaleClient client,
+ PacketEventArgs packetArgs,
+ IReadOnlyList<Result> executionResults,
+ CancellationToken ct = default
+ )
+ => Task.FromResult(Result.FromSuccess());
}=
\ No newline at end of file
M Tests/NosSmooth.Core.Tests/Fakes/Packets/FakePacket.cs => Tests/NosSmooth.Core.Tests/Fakes/Packets/FakePacket.cs +8 -1
@@ 5,6 5,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using NosSmooth.Packets;
+using NosSmooth.PacketSerializer.Abstractions.Attributes;
namespace NosSmooth.Core.Tests.Fakes.Packets;
@@ 12,4 13,10 @@ namespace NosSmooth.Core.Tests.Fakes.Packets;
/// A fake packet.
/// </summary>
/// <param name="Input">The input.</param>
-public record FakePacket(string Input) : IPacket;>
\ No newline at end of file
+[PacketHeader("fake", PacketSource.Server)]
+[GenerateSerializer(true)]
+public record FakePacket
+(
+ [PacketGreedyIndex(0)]
+ string Input
+) : IPacket;<
\ No newline at end of file
M Tests/NosSmooth.Core.Tests/NosSmooth.Core.Tests.csproj => Tests/NosSmooth.Core.Tests/NosSmooth.Core.Tests.csproj +7 -1
@@ 1,8 1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <TargetFramework>net7.0</TargetFramework>
+ <ImplicitUsings>enable</ImplicitUsings>
+ <TargetFrameworks>net7.0;netstandard2.1</TargetFrameworks>
<Nullable>enable</Nullable>
+ <LangVersion>10</LangVersion>
<IsPackable>false</IsPackable>
</PropertyGroup>
@@ 27,4 29,8 @@
<ProjectReference Include="..\..\Core\NosSmooth.Core\NosSmooth.Core.csproj" />
</ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\Packets\NosSmooth.PacketSerializersGenerator\NosSmooth.PacketSerializersGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
+ </ItemGroup>
+
</Project>
M Tests/NosSmooth.Core.Tests/Packets/PacketHandlerTests.Events.cs => Tests/NosSmooth.Core.Tests/Packets/PacketHandlerTests.Events.cs +11 -3
@@ 5,8 5,10 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
+using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
using NosSmooth.Core.Commands;
using NosSmooth.Core.Packets;
using NosSmooth.Core.Tests.Fakes;
@@ 14,6 16,8 @@ using NosSmooth.Core.Tests.Fakes.Commands;
using NosSmooth.Core.Tests.Fakes.Packets;
using NosSmooth.Core.Tests.Fakes.Packets.Events;
using NosSmooth.PacketSerializer.Abstractions.Attributes;
+using NosSmooth.PacketSerializer.Extensions;
+using NosSmooth.PacketSerializer.Packets;
using Remora.Results;
using Xunit;
@@ 34,7 38,10 @@ public class PacketHandlerTestsEvents
var called = false;
var client = new FakeEmptyNostaleClient();
var provider = new ServiceCollection()
- .AddSingleton<PacketHandler>()
+ .AddPacketSerialization()
+ .AddGeneratedSerializers(Assembly.GetExecutingAssembly())
+ .AddSingleton(typeof(ILogger<>), typeof(FakeLogger<>))
+ .AddSingleton<IPacketHandler, ManagedPacketHandler>()
.AddScoped<IPreExecutionEvent>
(
_ => new PacketEvent
@@ 59,8 66,9 @@ public class PacketHandlerTestsEvents
)
.BuildServiceProvider();
- var result = await provider.GetRequiredService<PacketHandler>().HandlePacketAsync
- (client, PacketSource.Client, new FakePacket("a"), "fake a");
+ provider.GetRequiredService<IPacketTypesRepository>().AddPacketType(typeof(FakePacket));
+ var result = await provider.GetRequiredService<IPacketHandler>().HandlePacketAsync
+ (client, PacketSource.Client, "fake a");
Assert.True(result.IsSuccess);
Assert.True(called);
}
M Tests/NosSmooth.Core.Tests/Stateful/StatefulInjectorTests.cs => Tests/NosSmooth.Core.Tests/Stateful/StatefulInjectorTests.cs +12 -4
@@ 4,8 4,10 @@
// 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.Reflection;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
using NosSmooth.Core.Client;
using NosSmooth.Core.Commands;
using NosSmooth.Core.Extensions;
@@ 17,6 19,8 @@ using NosSmooth.Core.Tests.Fakes.Packets;
using NosSmooth.Core.Tests.Packets;
using NosSmooth.Packets.Server.Maps;
using NosSmooth.PacketSerializer.Abstractions.Attributes;
+using NosSmooth.PacketSerializer.Extensions;
+using NosSmooth.PacketSerializer.Packets;
using Remora.Results;
using Xunit;
@@ 135,7 139,10 @@ public class StatefulInjectorTests
.AddStatefulInjector()
.AddStatefulEntity<FakeEntity>()
.AddSingleton<CommandProcessor>()
- .AddSingleton<PacketHandler>()
+ .AddSingleton(typeof(ILogger<>), typeof(FakeLogger<>))
+ .AddPacketSerialization()
+ .AddGeneratedSerializers(Assembly.GetExecutingAssembly())
+ .AddSingleton<IPacketHandler, ManagedPacketHandler>()
.AddScoped<IPacketResponder<FakePacket>>
(p =>
{
@@ 161,10 168,11 @@ public class StatefulInjectorTests
)
.BuildServiceProvider();
- var handler = services.GetRequiredService<PacketHandler>();
+ var handler = services.GetRequiredService<IPacketHandler>();
- Assert.True((await handler.HandlePacketAsync(client1, PacketSource.Server, new FakePacket("1"), "fake 1")).IsSuccess);
- Assert.True((await handler.HandlePacketAsync(client2, PacketSource.Server, new FakePacket("2"), "fake 2")).IsSuccess);
+ services.GetRequiredService<IPacketTypesRepository>().AddPacketType(typeof(FakePacket));
+ Assert.True((await handler.HandlePacketAsync(client1, PacketSource.Server, "fake 1")).IsSuccess);
+ Assert.True((await handler.HandlePacketAsync(client2, PacketSource.Server, "fake 2")).IsSuccess);
Assert.NotNull(entity1);
Assert.NotNull(entity2);
Assert.NotEqual(entity1, entity2);