// // Client.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.Text.RegularExpressions; using Microsoft.Extensions.Logging; using NosSmooth.Core.Client; using NosSmooth.Core.Commands; using NosSmooth.Core.Extensions; using NosSmooth.Core.Packets; using NosSmooth.Packets; using NosSmooth.PacketSerializer.Abstractions.Attributes; using Remora.Results; namespace FileClient; /// /// A NosTale client using stream to read lines. /// public class Client : BaseNostaleClient { private const string LineRegex = ".*\\[(Recv|Send)\\]\t(.*)"; private readonly PacketHandler _packetHandler; private readonly IPacketSerializer _packetSerializer; private readonly ILogger _logger; private readonly Stream _stream; /// /// Initializes a new instance of the class. /// /// The stream with packets. /// The packet handler. /// The command processor. /// The packet serializer. /// The logger. public Client ( Stream stream, PacketHandler packetHandler, CommandProcessor commandProcessor, IPacketSerializer packetSerializer, ILogger logger ) : base(commandProcessor, packetSerializer) { _stream = stream; _packetHandler = packetHandler; _packetSerializer = packetSerializer; _logger = logger; } /// public override async Task RunAsync(CancellationToken stopRequested = default) { using var reader = new StreamReader(_stream); var regex = new Regex(LineRegex); while (!reader.EndOfStream) { stopRequested.ThrowIfCancellationRequested(); var line = await reader.ReadLineAsync(); if (line is null) { continue; } var match = regex.Match(line); if (!match.Success) { _logger.LogError("Could not find match on line {Line}", line); continue; } var type = match.Groups[1].Value; 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 ); if (!result.IsSuccess) { _logger.LogResultError(result); } } return Result.FromSuccess(); } /// public override async Task SendPacketAsync(string packetString, CancellationToken ct = default) { return await _packetHandler.HandlePacketAsync ( this, PacketSource.Client, CreatePacket(packetString, PacketSource.Client), packetString, ct ); } /// public override async Task ReceivePacketAsync(string packetString, CancellationToken ct = default) { return await _packetHandler.HandlePacketAsync ( 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; } }