feat: a big draft

This commit is contained in:
Timothy Schenk 2023-08-09 16:23:41 +02:00
parent 20937f14b2
commit df3aae5d49
29 changed files with 570 additions and 332 deletions

25
.dockerignore Normal file
View file

@ -0,0 +1,25 @@
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/.idea
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md

View file

@ -1,10 +1,6 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{DDE63D00-4CC2-4397-B409-410D9F272F0F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server.Tests", "Server.Tests\Server.Tests.csproj", "{5D09881E-E059-46F5-9064-66F192258C0C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server.Packets", "Server.Packets\Server.Packets.csproj", "{C0769799-62D3-4AEE-9335-9011D97C1DE2}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{7EDA8B31-3E03-4CA3-87D1-CFEB05C277D6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -12,17 +8,9 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DDE63D00-4CC2-4397-B409-410D9F272F0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DDE63D00-4CC2-4397-B409-410D9F272F0F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DDE63D00-4CC2-4397-B409-410D9F272F0F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DDE63D00-4CC2-4397-B409-410D9F272F0F}.Release|Any CPU.Build.0 = Release|Any CPU
{5D09881E-E059-46F5-9064-66F192258C0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5D09881E-E059-46F5-9064-66F192258C0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5D09881E-E059-46F5-9064-66F192258C0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5D09881E-E059-46F5-9064-66F192258C0C}.Release|Any CPU.Build.0 = Release|Any CPU
{C0769799-62D3-4AEE-9335-9011D97C1DE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C0769799-62D3-4AEE-9335-9011D97C1DE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C0769799-62D3-4AEE-9335-9011D97C1DE2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C0769799-62D3-4AEE-9335-9011D97C1DE2}.Release|Any CPU.Build.0 = Release|Any CPU
{7EDA8B31-3E03-4CA3-87D1-CFEB05C277D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7EDA8B31-3E03-4CA3-87D1-CFEB05C277D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7EDA8B31-3E03-4CA3-87D1-CFEB05C277D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7EDA8B31-3E03-4CA3-87D1-CFEB05C277D6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=decryptor/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View file

@ -1,7 +0,0 @@
namespace Server.Packets;
public interface IPacket
{
Span<Byte> Serialize();
void Deserialize(Span<Byte> bytes);
}

View file

@ -1,40 +0,0 @@
using System.Collections.Immutable;
using System.Reflection;
namespace Server.Packets;
public class PacketForwardingService
{
private ImmutableDictionary<PacketId, System.Reflection.ConstructorInfo> _packets = null!;
public PacketForwardingService()
{
InitializePackets(typeof(IPacket).Assembly);
}
private void InitializePackets(Assembly assembly)
{
// Get all types that implement IPacket and have a PacketIdAttribute
_packets = assembly.GetTypes()
.Select(x => (attr: x.GetCustomAttribute<PacketIdAttribute>(), ctor: x.GetConstructor(Type.EmptyTypes)))
.Where(x => x.GetType().IsAssignableTo(typeof(IPacket)) && x.GetType().IsClass)
.Where(x => x.attr != null && x.ctor != null)
.ToImmutableDictionary(x => x.attr!.PacketId, x => x.ctor)!;
}
public IPacket Dispatch(Span<Byte> bytes)
{
// Get constructor according to packet id
IPacket packet = _packets[GetPacketId(bytes)].Invoke(Array.Empty<object>()) as IPacket ??
throw new InvalidOperationException();
// Slice off packet id
packet.Deserialize(bytes.Slice(2));
return packet;
}
private PacketId GetPacketId(Span<Byte> bytes)
{
var id = (PacketId)BitConverter.ToUInt16(new[] { bytes[0], bytes[1] });
return id;
}
}

View file

@ -1,6 +0,0 @@
namespace Server.Packets;
public enum PacketId : ushort
{
}

View file

@ -1,12 +0,0 @@
namespace Server.Packets;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
[JetBrains.Annotations.BaseTypeRequiredAttribute(typeof(IPacket))]
public class PacketIdAttribute : Attribute
{
public PacketIdAttribute(PacketId packetId)
{
PacketId = packetId;
}
public PacketId PacketId { get; private set; }
}

View file

@ -1,13 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2023.2.0" />
</ItemGroup>
</Project>

View file

@ -1,19 +0,0 @@
using System.Reflection;
namespace Server.Tests;
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]
public class PacketTests
{
[Fact]
public void TestPacketInheritingIPacket()
{
var allTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())
.Where(x => x.IsAssignableTo(typeof(Packets.IPacket)) && x.IsClass);
if (!allTypes.Any())
true.Should().BeTrue("There have been no types found which can be checked");
else
allTypes.All(t => t.GetCustomAttributes<Packets.PacketIdAttribute>().Any())
.Should().BeTrue("All types inheriting from IPacket should have the PacketIdAttribute attribute.");
}
}

View file

@ -1,29 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.0" />
<PackageReference Include="xunit" Version="2.5.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Server.Packets\Server.Packets.csproj" />
</ItemGroup>
</Project>

View file

@ -1,2 +0,0 @@
global using Xunit;
global using FluentAssertions;

View file

@ -1,46 +0,0 @@
using System.Security.Cryptography;
using Microsoft.Extensions.Logging;
namespace Server;
public class AesProvider
{
private readonly Aes _aes;
private readonly ICryptoTransform _encryptor;
private readonly ICryptoTransform _decryptor;
private readonly ILogger _logger;
public AesProvider(ILoggerFactory loggerFactory, Span<byte> key, Span<byte> iv)
{
_logger = loggerFactory.CreateLogger(nameof(AesProvider));
_aes = Aes.Create();
_aes.Key = key.ToArray();
_aes.IV = iv.ToArray();
_encryptor = _aes.CreateEncryptor();
_decryptor = _aes.CreateDecryptor();
}
public Span<byte> Encrypt(Span<byte> input)
{
using MemoryStream memoryStream = new MemoryStream();
using CryptoStream cryptoStream = new CryptoStream(memoryStream, _encryptor, CryptoStreamMode.Write);
cryptoStream.Write(input);
cryptoStream.Flush();
Span<byte> bytes = memoryStream.ToArray();
return bytes;
}
public Span<byte> Decrypt(Span<byte> input)
{
using MemoryStream memoryStream = new MemoryStream(input.ToArray());
using CryptoStream cryptoStream = new CryptoStream(memoryStream, _decryptor, CryptoStreamMode.Read);
Span<byte> bytes = new byte[input.Length];
var i = cryptoStream.Read(bytes);
if (i > 0)
_logger.LogWarning("CryptoStream hasn't been read till the end. ({length}", i);
return bytes;
}
}

216
Server/AesSession.cs Normal file
View file

@ -0,0 +1,216 @@
using System.Buffers.Binary;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json.Serialization;
using MassTransit.Mediator;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NetCoreServer;
using Buffer = NetCoreServer.Buffer;
namespace Server;
public abstract class AesSession : TcpSession
{
private readonly ILogger _logger;
private readonly IMediator _mediator;
private static readonly byte[] Key = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7 }
.Reverse().ToArray();
private static readonly byte[] IV = new byte[]
{ 0xfe, 220, 0xba, 0x98, 0x76, 0x54, 50, 0x10, 15, 30, 0x2d, 60, 0x4b, 90, 0x69, 120 }.Reverse().ToArray();
private readonly ICryptoTransform _encryptor;
private readonly ICryptoTransform _decryptor;
protected AesSession(TcpServer
server, ILogger logger, IMediator mediator) : base(server)
{
_logger = logger;
_mediator = mediator;
var aes = Aes.Create();
aes.Key = Key;
aes.IV = IV;
aes.Padding = PaddingMode.None;
aes.Mode = CipherMode.ECB;
_decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
_encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
}
public override long Send(byte[] buffer)
{
byte[] encryptedBuffer;
using (var ms = new MemoryStream())
using (var cs = new CryptoStream(ms, _encryptor, CryptoStreamMode.Write))
{
cs.Write(buffer);
cs.FlushFinalBlock();
encryptedBuffer = ms.ToArray();
}
return base.Send(encryptedBuffer);
}
public override long Send(byte[] buffer, long offset, long size)
{
byte[] encryptedBuffer;
using (var ms = new MemoryStream())
using (var cs = new CryptoStream(ms, _encryptor, CryptoStreamMode.Write))
{
cs.Write(buffer, (int)offset, (int)size);
cs.FlushFinalBlock();
encryptedBuffer = ms.ToArray();
}
return base.Send(encryptedBuffer, 0, encryptedBuffer.Length);
}
public override long Send(ReadOnlySpan<byte> buffer)
{
Span<byte> encryptedBuffer;
using (var ms = new MemoryStream())
using (var cs = new CryptoStream(ms, _encryptor, CryptoStreamMode.Write))
{
cs.Write(buffer);
cs.FlushFinalBlock();
encryptedBuffer = ms.ToArray();
}
return base.Send(encryptedBuffer);
}
public override bool SendAsync(byte[] buffer)
{
byte[] encryptedBuffer;
using (var ms = new MemoryStream())
using (var cs = new CryptoStream(ms, _encryptor, CryptoStreamMode.Write))
{
cs.Write(buffer);
cs.FlushFinalBlock();
encryptedBuffer = ms.ToArray();
}
return base.SendAsync(encryptedBuffer);
}
public override bool SendAsync(byte[] buffer, long offset, long size)
{
byte[] encryptedBuffer;
using (var ms = new MemoryStream())
using (var cs = new CryptoStream(ms, _encryptor, CryptoStreamMode.Write))
{
cs.Write(buffer, (int)offset, (int)size);
cs.FlushFinalBlock();
encryptedBuffer = ms.ToArray();
}
return base.SendAsync(encryptedBuffer, 0, encryptedBuffer.Length);
}
public override bool SendAsync(ReadOnlySpan<byte> buffer)
{
Span<byte> encryptedBuffer;
using (var ms = new MemoryStream())
using (var cs = new CryptoStream(ms, _encryptor, CryptoStreamMode.Write))
{
cs.Write(buffer);
cs.FlushFinalBlock();
encryptedBuffer = ms.ToArray();
}
return base.SendAsync(encryptedBuffer);
}
public override long Receive(byte[] buffer)
{
Span<byte> decryptedBuffer;
using (var ms = new MemoryStream())
using (var cs = new CryptoStream(ms, _decryptor, CryptoStreamMode.Write))
{
cs.Write(buffer);
cs.FlushFinalBlock();
decryptedBuffer = ms.ToArray();
}
return base.Receive(decryptedBuffer.ToArray());
}
public override long Receive(byte[] buffer, long offset, long size)
{
byte[] decryptedBuffer;
using (var ms = new MemoryStream())
using (var cs = new CryptoStream(ms, _decryptor, CryptoStreamMode.Write))
{
cs.Write(buffer, (int)offset, (int)size);
cs.FlushFinalBlock();
decryptedBuffer = ms.ToArray();
}
return base.Receive(decryptedBuffer, 0, decryptedBuffer.Length);
}
protected override void OnReceived(byte[] buffer, long offset, long size)
{
try
{
Console.WriteLine($"Length: {size} & offset: {offset}");
//Console.WriteLine(BitConverter.ToString(buffer.ToArray()).Replace("-", string.Empty));
Span<byte> decryptedBuffer = new byte[size];
// xor every value after the first 8 bytes
// then apply AES decryption
var dataBuffer = Decrypt(new ArraySegment<byte>(buffer, 8, (int)size - 8).ToArray());
/*using (var ms = new MemoryStream(dataBuffer))
using (var cs = new CryptoStream(ms, _decryptor, CryptoStreamMode.Read))
{
cs.Read(decryptedBuffer);
}*/
Console.WriteLine("Length " + BitConverter.ToUInt16(buffer, 0));
var opCode = BitConverter.ToUInt16(buffer.ToArray(), 2);
Console.WriteLine("Packet Op Code: " + opCode);
Console.WriteLine("Some Value: " + buffer[4]);
/*
* 20s = 5
* 15s = 4
* 10s = 3
*
* client alive time * 5s => uptime
*/
var clientAliveTime = BitConverter.ToUInt16(buffer.ToArray(), 5);
Console.WriteLine("Client Alive time: " + clientAliveTime);
Console.WriteLine("Might be a flag:" + buffer[7]);
Console.WriteLine("username: " + Encoding.ASCII.GetString(dataBuffer.ToArray(), 0, 20));
Console.WriteLine("password: " + Encoding.ASCII.GetString(dataBuffer.ToArray(), 20, 32));
Console.WriteLine("Full buffer: " + Encoding.ASCII.GetString(dataBuffer.ToArray()));
Packet packet = new Packet((OperationCode)opCode, dataBuffer, clientAliveTime, buffer[0], buffer[3],
Id);
Parallel.Invoke(() => _mediator.Send(packet));
base.OnReceived(decryptedBuffer.ToArray(), offset, decryptedBuffer.Length);
}
catch (CryptographicException ex)
{
_logger.LogError("An error has occured while decrypting: {ErrorMessage}", ex.Message);
_logger.LogError("Default buffer message: {Message}", Encoding.ASCII.GetString(buffer));
}
}
private byte[] Decrypt(byte[] buffer)
{
for (int i = 0; i < buffer.Length; ++i)
{
buffer[i] = (byte)(buffer[i] ^ i ^ (3 * (0xFE - i)));
}
return buffer;
}
}

View file

@ -1,55 +0,0 @@
using Microsoft.Extensions.Logging;
using ReInject.Implementation.Attributes;
namespace Server;
using Microsoft.Extensions.Configuration;
public class AuthorizationServer : NetCoreServer.TcpServer
{
private readonly AesProvider _aesProvider;
private readonly ILogger _logger;
public AuthorizationServer(IConfiguration configuration, ILoggerFactory loggerFactory, AesProvider aesProvider) : base(
configuration["auth:address"]!,
configuration.GetValue<int>("auth:port"))
{
_aesProvider = aesProvider;
_logger = loggerFactory.CreateLogger(nameof(AuthorizationServer));
}
protected override NetCoreServer.TcpSession CreateSession()
{
var session = new AuthorizationServerSession(this, _logger, _aesProvider);
return session;
}
protected override void OnStarting()
{
base.OnStarting();
_logger.LogInformation("is starting");
}
protected override void OnStarted()
{
base.OnStarted();
_logger.LogInformation("is started");
}
protected override void OnStopping()
{
base.OnStopping();
_logger.LogInformation("is stopping");
}
protected override void OnStopped()
{
base.OnStopped();
_logger.LogInformation("is stopped");
}
protected override void OnError(System.Net.Sockets.SocketError error)
{
_logger.LogError("Authorization server caught an error with code {error}", error);
}
}

View file

@ -1,44 +0,0 @@
using System.Net.Sockets;
using Microsoft.Extensions.Logging;
using NetCoreServer;
namespace Server;
public class AuthorizationServerSession : TcpSession
{
private readonly ILogger _logger;
private readonly AesProvider _aesProvider;
public AuthorizationServerSession(AuthorizationServer server, ILogger logger, AesProvider aesProvider) : base(server)
{
_logger = logger;
_aesProvider = aesProvider;
}
public override long Send(byte[] buffer, long offset, long size)
{
var bytes = _aesProvider.Encrypt(buffer);
return bytes.Length;
}
public override long Receive(byte[] buffer, long offset, long size)
{
var bytes = _aesProvider.Decrypt(buffer);
return bytes.Length;
}
protected override void OnConnected()
{
_logger.LogInformation("Session with Id {Id} is connected.", Id);
}
protected override void OnDisconnected()
{
_logger.LogInformation("Session with Id {Id} is disconnected.", Id);
}
protected override void OnError(SocketError error)
{
_logger.LogError("Authorization session caught an error with code {error}", error);
}
}

18
Server/Dockerfile Normal file
View file

@ -0,0 +1,18 @@
FROM mcr.microsoft.com/dotnet/runtime:7.0 AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY ["Serer/Serer.csproj", "Serer/"]
RUN dotnet restore "Serer/Serer.csproj"
COPY . .
WORKDIR "/src/Serer"
RUN dotnet build "Serer.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "Serer.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Serer.dll"]

6
Server/IPacketHandler.cs Normal file
View file

@ -0,0 +1,6 @@
namespace Server;
public interface IPacketHandler
{
public void Process(Packet packet);
}

12
Server/LoginHandler.cs Normal file
View file

@ -0,0 +1,12 @@
using Microsoft.Extensions.DependencyInjection;
namespace Server;
[PacketHandler(OperationCode.LoginInfo)]
public class LoginHandler : IPacketHandler
{
public void Process(Packet packet)
{
Console.WriteLine("Login being processed.");
}
}

6
Server/OperationCode.cs Normal file
View file

@ -0,0 +1,6 @@
namespace Server;
public enum OperationCode : ushort
{
LoginInfo = 11
}

24
Server/Packet.cs Normal file
View file

@ -0,0 +1,24 @@
using MassTransit;
namespace Server;
[MessageUrn("packets")]
public class Packet
{
public readonly OperationCode OperationCode;
public readonly byte[] MessageBody;
public readonly TimeSpan ClientAliveTime;
public readonly byte UnknownValue;
public readonly byte UnknownValue2;
public readonly Guid SessionId;
public Packet(OperationCode operationCode, byte[] messageBody, uint aliveTime, byte unknownValue2, byte unknownValue, Guid sessionId)
{
MessageBody = messageBody;
UnknownValue2 = unknownValue2;
UnknownValue = unknownValue;
SessionId = sessionId;
OperationCode = operationCode;
ClientAliveTime = TimeSpan.FromSeconds(5 * aliveTime);
}
}

18
Server/PacketConsumer.cs Normal file
View file

@ -0,0 +1,18 @@
using MassTransit;
namespace Server;
public class PacketConsumer : IConsumer<Packet>
{
private readonly PacketDistributorService _distributorService;
public PacketConsumer(PacketDistributorService distributorService)
{
_distributorService = distributorService;
}
public Task Consume(ConsumeContext<Packet> context)
{
return _distributorService.AddPacket(context.Message);
}
}

View file

@ -0,0 +1,74 @@
using System.Collections.Concurrent;
using System.Reflection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Server;
public class PacketDistributorService : IHostedService
{
private readonly ConcurrentQueue<Packet> _concurrentQueue;
private readonly ILogger<PacketDistributorService> _logger;
private readonly CancellationTokenSource _cancellationTokenSource = new();
private readonly Dictionary<OperationCode, IPacketHandler> _actions;
public PacketDistributorService(ILogger<PacketDistributorService> logger)
{
_concurrentQueue = new ConcurrentQueue<Packet>();
_logger = logger;
_actions = new Dictionary<OperationCode, IPacketHandler>();
var packetHandlers = Assembly.GetExecutingAssembly().GetTypes().Where(t =>
t.GetCustomAttributes().Any(attribute => attribute.GetType() == typeof(PacketHandler)) &&
t.GetInterfaces().Contains(typeof(IPacketHandler)));
foreach (var type in packetHandlers)
{
PacketHandler packetHandler = type.GetCustomAttribute<PacketHandler>()!;
_actions.Add(packetHandler.Code,
type.GetConstructor( Type.EmptyTypes)
.Invoke(null) as IPacketHandler);
_logger.LogInformation(
"Handler for ID \"{PacketHandlerCode}\" has been added with name \"{PacketHandlerName}\"",
packetHandler.Code, type.Name);
}
}
public Task StartAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public Task AddPacket(Packet packet)
{
_logger.LogInformation("Packet with ID: {MessageOperationCode} has been received",
packet.OperationCode);
_concurrentQueue.Enqueue(packet);
return Task.Run(DequeueAndProcessAsync);
}
private async Task DequeueAndProcessAsync()
{
while (!_cancellationTokenSource.IsCancellationRequested)
{
if (_concurrentQueue.TryDequeue(out var item))
{
Parallel.Invoke(() =>
{
var tempId = Guid.NewGuid();
_logger.LogInformation("[{TempId}] Packet with ID: {MessageOperationCode} is being dequeued",tempId, item.OperationCode);
var packetHandler = _actions[item.OperationCode];
packetHandler.Process(item);
_logger.LogInformation("[{TempId}] Packet with ID: {MessageOperationCode} has finished",tempId, item.OperationCode);
});
}
else
{
await Task.Delay(100); // Delay to prevent busy-waiting, can be adjusted based on needs
}
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}

11
Server/PacketHandler.cs Normal file
View file

@ -0,0 +1,11 @@
namespace Server;
public class PacketHandler : Attribute
{
public readonly OperationCode Code;
public PacketHandler(OperationCode code)
{
Code = code;
}
}

View file

@ -1,28 +1,27 @@
using Microsoft.Extensions.Configuration;
using System.Net;
using System.Reflection;
using MassTransit;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ReInject;
using Server;
var services = Injector.GetContainer();
Console.WriteLine(BitConverter.IsLittleEndian);
var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
services.Register<IConfiguration>(DependencyStrategy.AtomicInstance, true, configuration);
ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
var builder = Host.CreateApplicationBuilder();
builder.Services.AddLogging();
builder.Services.AddSingleton<PacketDistributorService>();
builder.Services.AddHostedService<PacketDistributorService>(provider =>
provider.GetService<PacketDistributorService>() ?? throw new InvalidOperationException());
builder.Services.AddMassTransit(x =>
{
builder.AddSimpleConsole(options =>
{
options.ColorBehavior = Microsoft.Extensions.Logging.Console.LoggerColorBehavior.Enabled;
options.TimestampFormat = "[HH:mm:ss]";
options.IncludeScopes = true;
});
builder.AddFile("Logs/log-{0:yyyy}-{0:MM}-{0:dd}.txt",
opts => opts.FormatLogFileName = fileName => String.Format(fileName, DateTime.UtcNow));
x.UsingInMemory((context, configurator) => { configurator.ConfigureEndpoints(context); });
x.AddMediator(cfg => { cfg.AddConsumers(Assembly.GetExecutingAssembly()); });
});
builder.Services.AddHostedService<WonderkingAuthServer>(provider => new WonderkingAuthServer(IPAddress.Any, 10001,
provider.GetService<ILogger<WonderkingAuthServer>>() ?? throw new InvalidOperationException(),
provider.GetService<IServiceProvider>() ?? throw new InvalidOperationException(),
provider.GetService<ILoggerFactory>() ?? throw new InvalidOperationException()));
services.Register<AesProvider>(DependencyStrategy.AtomicInstance, true, new AesProvider(loggerFactory, null, null));
services.Register<ILoggerFactory>(DependencyStrategy.AtomicInstance, true, loggerFactory);
var authServer = services.GetInstance<AuthorizationServer>();
authServer.Start();
using IHost host = builder.Build();
await host.RunAsync();

View file

@ -5,27 +5,27 @@
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<RootNamespace>Server</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Server.Packets\Server.Packets.csproj" />
<Content Include="..\.dockerignore">
<Link>.dockerignore</Link>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Aeolin.reInject" Version="2.1.0" />
<PackageReference Include="Aeolin.reInject.Scopes" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
<PackageReference Include="JetBrains.Annotations" Version="2023.2.0" />
<PackageReference Include="MassTransit" Version="8.0.16" />
<PackageReference Include="MassTransit.Analyzers" Version="8.0.16">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
<PackageReference Include="NetCoreServer" Version="7.0.0" />
<PackageReference Include="NReco.Logging.File" Version="1.1.6" />
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View file

@ -0,0 +1,70 @@
using System.Net;
using System.Net.Sockets;
using MassTransit;
using MassTransit.Mediator;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NetCoreServer;
namespace Server;
public class WonderkingAuthServer : TcpServer, IHostedService
{
private readonly ILogger<WonderkingAuthServer> _logger;
private readonly IServiceProvider _serviceProvider;
private readonly ILoggerFactory _loggerFactory;
public WonderkingAuthServer(IPAddress address, int port, ILogger<WonderkingAuthServer> logger,
IServiceProvider serviceProvider, ILoggerFactory loggerFactory) : base(address, port)
{
_logger = logger;
_serviceProvider = serviceProvider;
_loggerFactory = loggerFactory;
}
protected override TcpSession CreateSession() => new WonderkingSession(this,
_serviceProvider.GetService<IMediator>() ?? throw new InvalidOperationException(),
_loggerFactory.CreateLogger(nameof(WonderkingSession)));
protected override void OnStarting()
{
_logger.LogInformation("Starting");
base.OnStarting();
}
protected override void OnStarted()
{
_logger.LogInformation("Started");
base.OnStarted();
}
protected override void OnStopping()
{
_logger.LogInformation("Stopping");
base.OnStopping();
}
protected override void OnStopped()
{
_logger.LogInformation("Stopped");
base.OnStopped();
}
protected override void OnError(SocketError error)
{
_logger.LogError("An error has occured {Error}", error);
}
public Task StartAsync(CancellationToken cancellationToken)
{
Start();
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
Stop();
return Task.CompletedTask;
}
}

View file

@ -0,0 +1,21 @@
using MassTransit;
using MassTransit.Mediator;
using Microsoft.Extensions.Logging;
using NetCoreServer;
namespace Server;
public class WonderkingSession : AesSession
{
private readonly IMediator _mediator;
public WonderkingSession(TcpServer server, IMediator mediator, ILogger logger) : base(server, logger, mediator)
{
_mediator = mediator;
}
protected override void OnReceived(byte[] buffer, long offset, long size)
{
base.OnReceived(buffer, offset, size);
}
}

View file

@ -1,8 +0,0 @@
{
"auth": {
"port": 10001,
"address": "127.0.0.1"
},
"logging":{
}
}

29
qodana.yaml Normal file
View file

@ -0,0 +1,29 @@
#-------------------------------------------------------------------------------#
# Qodana analysis is configured by qodana.yaml file #
# https://www.jetbrains.com/help/qodana/qodana-yaml.html #
#-------------------------------------------------------------------------------#
version: "1.0"
#Specify inspection profile for code analysis
profile:
name: qodana.starter
#Enable inspections
#include:
# - name: <SomeEnabledInspectionId>
#Disable inspections
#exclude:
# - name: <SomeDisabledInspectionId>
# paths:
# - <path/where/not/run/inspection>
#Execute shell command before Qodana execution (Applied in CI/CD pipeline)
#bootstrap: sh ./prepare-qodana.sh
#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline)
#plugins:
# - id: <plugin.id> #(plugin id can be found at https://plugins.jetbrains.com)
#Specify Qodana linter for analysis (Applied in CI/CD pipeline)
linter: jetbrains/qodana-dotnet:latest