0
0
Fork 0
mirror of https://github.com/Sanae6/SmoOnlineServer.git synced 2024-11-22 03:05:16 +00:00

Untested conversion to variable size packets

This commit is contained in:
Sanae 2022-03-10 23:59:02 -06:00
parent 713e5f4cce
commit 8c5cd0ced2
16 changed files with 132 additions and 99 deletions

View file

@ -1,6 +1,7 @@
using System.Buffers; using System.Buffers;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Net.Sockets; using System.Net.Sockets;
using System.Runtime.InteropServices;
using Shared; using Shared;
using Shared.Packet; using Shared.Packet;
using Shared.Packet.Packets; using Shared.Packet.Packets;
@ -36,25 +37,26 @@ public class Client : IDisposable {
public event PacketTransformerDel? PacketTransformer; public event PacketTransformerDel? PacketTransformer;
public async Task Send<T>(T packet, Client? sender = null) where T : struct, IPacket { public async Task Send<T>(T packet, Client? sender = null) where T : struct, IPacket {
IMemoryOwner<byte> memory = MemoryPool<byte>.Shared.RentZero(Constants.MaxPacketSize); IMemoryOwner<byte> memory = MemoryPool<byte>.Shared.RentZero(Constants.HeaderSize + packet.Size);
packet = (T) (PacketTransformer?.Invoke(sender, packet) ?? packet); packet = (T) (PacketTransformer?.Invoke(sender, packet) ?? packet);
PacketHeader header = new PacketHeader { PacketHeader header = new PacketHeader {
Id = sender?.Id ?? Guid.Empty, Id = sender?.Id ?? Guid.Empty,
Type = Constants.PacketMap[typeof(T)].Type Type = Constants.PacketMap[typeof(T)].Type,
PacketSize = packet.Size
}; };
Server.FillPacket(header, packet, memory.Memory); Server.FillPacket(header, packet, memory.Memory);
await Send(memory.Memory[..Constants.MaxPacketSize], sender); await Send(memory.Memory[..], sender);
memory.Dispose(); memory.Dispose();
} }
public async Task Send(ReadOnlyMemory<byte> data, Client? sender) { public async Task Send(ReadOnlyMemory<byte> data, Client? sender) {
if (!Connected) { if (!Connected) {
Server.Logger.Info($"Didn't send {(PacketType) data.Span[16]} to {Id} because they weren't connected yet"); Server.Logger.Info($"Didn't send {MemoryMarshal.Read<PacketType>(data.Span[16..])} to {Id} because they weren't connected yet");
return; return;
} }
// Server.Logger.Info($"Sending {(PacketType) data.Span[16]} to {Id} from {other?.Id.ToString() ?? "server"}"); int packetSize = MemoryMarshal.Read<short>(data.Span[18..]);
await Socket!.SendAsync(data[..Constants.MaxPacketSize], SocketFlags.None); await Socket!.SendAsync(data[..(Constants.HeaderSize + packetSize)], SocketFlags.None);
} }
public static bool operator ==(Client? left, Client? right) { public static bool operator ==(Client? left, Client? right) {

View file

@ -78,11 +78,11 @@ public class Server {
} }
public async Task Broadcast<T>(T packet, Client sender) where T : struct, IPacket { public async Task Broadcast<T>(T packet, Client sender) where T : struct, IPacket {
IMemoryOwner<byte> memory = memoryPool.RentZero(Constants.MaxPacketSize); IMemoryOwner<byte> memory = MemoryPool<byte>.Shared.RentZero(Constants.HeaderSize + packet.Size);
PacketHeader header = new PacketHeader { PacketHeader header = new PacketHeader {
Id = sender?.Id ?? Guid.Empty, Id = sender?.Id ?? Guid.Empty,
Type = Constants.PacketMap[typeof(T)].Type Type = Constants.PacketMap[typeof(T)].Type,
PacketSize = packet.Size
}; };
FillPacket(header, packet, memory.Memory); FillPacket(header, packet, memory.Memory);
await Broadcast(memory, sender); await Broadcast(memory, sender);
@ -118,11 +118,12 @@ public class Server {
bool first = true; bool first = true;
try { try {
while (true) { while (true) {
memory = memoryPool.Rent(Constants.MaxPacketSize); memory = memoryPool.Rent(Constants.HeaderSize);
{
int readOffset = 0; async Task Read(Memory<byte> readMem, int readOffset = 0, int readSize = -1) {
while (readOffset < Constants.MaxPacketSize) { if (readSize == -1) readSize = Constants.HeaderSize;
int size = await socket.ReceiveAsync(memory.Memory[readOffset..Constants.MaxPacketSize], SocketFlags.None); while (readOffset < readSize) {
int size = await socket.ReceiveAsync(readMem[readOffset..readSize], SocketFlags.None);
if (size == 0) { if (size == 0) {
// treat it as a disconnect and exit // treat it as a disconnect and exit
Logger.Info($"Socket {socket.RemoteEndPoint} disconnected."); Logger.Info($"Socket {socket.RemoteEndPoint} disconnected.");
@ -132,11 +133,17 @@ public class Server {
readOffset += size; readOffset += size;
} }
if (readOffset < Constants.MaxPacketSize) break;
} }
PacketHeader header = GetHeader(memory.Memory.Span[..Constants.MaxPacketSize]); await Read(memory.Memory[..Constants.HeaderSize]);
PacketHeader header = GetHeader(memory.Memory.Span[..Constants.HeaderSize]);
{
IMemoryOwner<byte> memTemp = memory;
memory = memoryPool.Rent(Constants.HeaderSize + header.Size);
memTemp.Memory.CopyTo(memory.Memory);
memTemp.Dispose();
}
await Read(memory.Memory[Constants.HeaderSize..(Constants.HeaderSize + header.Size)]);
// connection initialization // connection initialization
if (first) { if (first) {
@ -144,7 +151,7 @@ public class Server {
if (header.Type != PacketType.Connect) throw new Exception($"First packet was not init, instead it was {header.Type}"); if (header.Type != PacketType.Connect) throw new Exception($"First packet was not init, instead it was {header.Type}");
ConnectPacket connect = new ConnectPacket(); ConnectPacket connect = new ConnectPacket();
connect.Deserialize(memory.Memory.Span[Constants.HeaderSize..Constants.MaxPacketSize]); connect.Deserialize(memory.Memory.Span[Constants.HeaderSize..(Constants.HeaderSize + header.PacketSize)]);
lock (Clients) { lock (Clients) {
client.Name = connect.ClientName; client.Name = connect.ClientName;
bool firstConn = false; bool firstConn = false;
@ -188,10 +195,11 @@ public class Server {
List<Client> otherConnectedPlayers = Clients.FindAll(c => c.Id != header.Id && c.Connected && c.Socket != null); List<Client> otherConnectedPlayers = Clients.FindAll(c => c.Id != header.Id && c.Connected && c.Socket != null);
await Parallel.ForEachAsync(otherConnectedPlayers, async (other, _) => { await Parallel.ForEachAsync(otherConnectedPlayers, async (other, _) => {
IMemoryOwner<byte> tempBuffer = MemoryPool<byte>.Shared.RentZero(Constants.MaxPacketSize); IMemoryOwner<byte> tempBuffer = MemoryPool<byte>.Shared.RentZero(Constants.HeaderSize + (other.CurrentCostume.HasValue ? Math.Max(connect.Size, other.CurrentCostume.Value.Size) : connect.Size));
PacketHeader connectHeader = new PacketHeader { PacketHeader connectHeader = new PacketHeader {
Id = other.Id, Id = other.Id,
Type = PacketType.Connect Type = PacketType.Connect,
PacketSize = connect.Size
}; };
MemoryMarshal.Write(tempBuffer.Memory.Span, ref connectHeader); MemoryMarshal.Write(tempBuffer.Memory.Span, ref connectHeader);
ConnectPacket connectPacket = new ConnectPacket { ConnectPacket connectPacket = new ConnectPacket {
@ -199,12 +207,13 @@ public class Server {
ClientName = other.Name ClientName = other.Name
}; };
connectPacket.Serialize(tempBuffer.Memory.Span[Constants.HeaderSize..]); connectPacket.Serialize(tempBuffer.Memory.Span[Constants.HeaderSize..]);
await client.Send(tempBuffer.Memory, null); await client.Send(tempBuffer.Memory[..(Constants.HeaderSize + connect.Size)], null);
if (other.CurrentCostume.HasValue) { if (other.CurrentCostume.HasValue) {
connectHeader.Type = PacketType.Costume; connectHeader.Type = PacketType.Costume;
connectHeader.PacketSize = other.CurrentCostume.Value.Size;
MemoryMarshal.Write(tempBuffer.Memory.Span, ref connectHeader); MemoryMarshal.Write(tempBuffer.Memory.Span, ref connectHeader);
other.CurrentCostume.Value.Serialize(tempBuffer.Memory.Span[Constants.HeaderSize..]); other.CurrentCostume.Value.Serialize(tempBuffer.Memory.Span[Constants.HeaderSize..(Constants.HeaderSize + connectHeader.PacketSize)]);
await client.Send(tempBuffer.Memory, null); await client.Send(tempBuffer.Memory[..(Constants.HeaderSize + connectHeader.PacketSize)], null);
} }
tempBuffer.Dispose(); tempBuffer.Dispose();
@ -219,14 +228,14 @@ public class Server {
CostumePacket costumePacket = new CostumePacket { CostumePacket costumePacket = new CostumePacket {
BodyName = "" BodyName = ""
}; };
costumePacket.Deserialize(memory.Memory.Span[Constants.HeaderSize..Constants.MaxPacketSize]); costumePacket.Deserialize(memory.Memory.Span[Constants.HeaderSize..(Constants.HeaderSize + costumePacket.Size)]);
client.CurrentCostume = costumePacket; client.CurrentCostume = costumePacket;
} }
try { try {
// if (header.Type is not PacketType.Cap and not PacketType.Player) client.Logger.Warn($"lol {header.Type}"); // if (header.Type is not PacketType.Cap and not PacketType.Player) client.Logger.Warn($"lol {header.Type}");
IPacket packet = (IPacket) Activator.CreateInstance(Constants.PacketIdMap[header.Type])!; IPacket packet = (IPacket) Activator.CreateInstance(Constants.PacketIdMap[header.Type])!;
packet.Deserialize(memory.Memory.Span[Constants.HeaderSize..Constants.MaxPacketSize]); packet.Deserialize(memory.Memory.Span[Constants.HeaderSize..(Constants.HeaderSize + packet.Size)]);
if (PacketHandler?.Invoke(client, packet) is false) { if (PacketHandler?.Invoke(client, packet) is false) {
memory.Dispose(); memory.Dispose();
continue; continue;

View file

@ -6,7 +6,6 @@ using Shared.Packet.Packets;
namespace Shared; namespace Shared;
public static class Constants { public static class Constants {
public const int MaxPacketSize = 256;
public const int MaxClients = 8; public const int MaxClients = 8;
public const int CostumeNameSize = 0x20; public const int CostumeNameSize = 0x20;
@ -23,5 +22,4 @@ public static class Constants {
.ToDictionary(type => type.GetCustomAttribute<PacketAttribute>()!.Type, type => type); .ToDictionary(type => type.GetCustomAttribute<PacketAttribute>()!.Type, type => type);
public static int HeaderSize { get; } = Marshal.SizeOf<PacketHeader>(); public static int HeaderSize { get; } = Marshal.SizeOf<PacketHeader>();
public static int PacketDataSize { get; } = MaxPacketSize - HeaderSize;
} }

View file

@ -8,6 +8,9 @@ public struct PacketHeader : IPacket {
// public int Length; // public int Length;
public Guid Id; public Guid Id;
public PacketType Type; public PacketType Type;
public short PacketSize;
public short Size => 20;
public void Serialize(Span<byte> data) { public void Serialize(Span<byte> data) {
// MemoryMarshal.Write(data, ref Length); // MemoryMarshal.Write(data, ref Length);
@ -18,5 +21,6 @@ public struct PacketHeader : IPacket {
public void Deserialize(Span<byte> data) { public void Deserialize(Span<byte> data) {
Id = MemoryMarshal.Read<Guid>(data); Id = MemoryMarshal.Read<Guid>(data);
Type = MemoryMarshal.Read<PacketType>(data[16..]); Type = MemoryMarshal.Read<PacketType>(data[16..]);
Type = MemoryMarshal.Read<PacketType>(data[16..]);
} }
} }

View file

@ -1,6 +1,6 @@
namespace Shared.Packet; namespace Shared.Packet;
public enum PacketType { public enum PacketType : short {
Unknown, Unknown,
Player, Player,
Cap, Cap,

View file

@ -11,6 +11,8 @@ public struct CapPacket : IPacket {
public Quaternion Rotation; public Quaternion Rotation;
public string CapAnim; public string CapAnim;
public short Size => 0x4C;
public void Serialize(Span<byte> data) { public void Serialize(Span<byte> data) {
MemoryMarshal.Write(data, ref Position); MemoryMarshal.Write(data, ref Position);
MemoryMarshal.Write(data[12..], ref Position); MemoryMarshal.Write(data[12..], ref Position);

View file

@ -10,6 +10,7 @@ public struct CapturePacket : IPacket {
public bool IsCaptured; public bool IsCaptured;
public short Size => Constants.CostumeNameSize + 1;
public void Serialize(Span<byte> data) { public void Serialize(Span<byte> data) {
Encoding.UTF8.GetBytes(ModelName).CopyTo(data[..Constants.CostumeNameSize]); Encoding.UTF8.GetBytes(ModelName).CopyTo(data[..Constants.CostumeNameSize]);
MemoryMarshal.Write(data[Constants.CostumeNameSize..], ref IsCaptured); MemoryMarshal.Write(data[Constants.CostumeNameSize..], ref IsCaptured);
@ -19,4 +20,5 @@ public struct CapturePacket : IPacket {
ModelName = Encoding.UTF8.GetString(data[..Constants.CostumeNameSize]).TrimNullTerm(); ModelName = Encoding.UTF8.GetString(data[..Constants.CostumeNameSize]).TrimNullTerm();
IsCaptured = MemoryMarshal.Read<bool>(data[Constants.CostumeNameSize..]); IsCaptured = MemoryMarshal.Read<bool>(data[Constants.CostumeNameSize..]);
} }
} }

View file

@ -10,6 +10,8 @@ public struct ConnectPacket : IPacket {
public ConnectPacket() { } public ConnectPacket() { }
public short Size => 4 + Constants.CostumeNameSize;
public void Serialize(Span<byte> data) { public void Serialize(Span<byte> data) {
MemoryMarshal.Write(data, ref ConnectionType); MemoryMarshal.Write(data, ref ConnectionType);
Encoding.UTF8.GetBytes(ClientName).CopyTo(data[4..(4 + Constants.CostumeNameSize)]); Encoding.UTF8.GetBytes(ClientName).CopyTo(data[4..(4 + Constants.CostumeNameSize)]);

View file

@ -11,6 +11,8 @@ public struct CostumePacket : IPacket {
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Constants.CostumeNameSize)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = Constants.CostumeNameSize)]
public string CapName; public string CapName;
public short Size => Constants.CostumeNameSize * 2;
public void Serialize(Span<byte> data) { public void Serialize(Span<byte> data) {
Encoding.UTF8.GetBytes(BodyName).CopyTo(data[..Constants.CostumeNameSize]); Encoding.UTF8.GetBytes(BodyName).CopyTo(data[..Constants.CostumeNameSize]);
Encoding.UTF8.GetBytes(CapName).CopyTo(data[Constants.CostumeNameSize..]); Encoding.UTF8.GetBytes(CapName).CopyTo(data[Constants.CostumeNameSize..]);

View file

@ -3,6 +3,7 @@
[Packet(PacketType.Disconnect)] [Packet(PacketType.Disconnect)]
public struct DisconnectPacket : IPacket { public struct DisconnectPacket : IPacket {
//empty packet //empty packet
public short Size => 0;
public void Serialize(Span<byte> data) { } public void Serialize(Span<byte> data) { }
public void Deserialize(Span<byte> data) { } public void Deserialize(Span<byte> data) { }

View file

@ -2,6 +2,7 @@
// Packet interface for type safety // Packet interface for type safety
public interface IPacket { public interface IPacket {
short Size { get; }
void Serialize(Span<byte> data); void Serialize(Span<byte> data);
void Deserialize(Span<byte> data); void Deserialize(Span<byte> data);
} }

View file

@ -35,6 +35,8 @@ public struct PlayerPacket : IPacket {
public PlayerPacket() { } public PlayerPacket() { }
public short Size => 0xE0;
public void Serialize(Span<byte> data) { public void Serialize(Span<byte> data) {
int offset = 0; int offset = 0;
MemoryMarshal.Write(data, ref Position); MemoryMarshal.Write(data, ref Position);

View file

@ -6,6 +6,8 @@ namespace Shared.Packet.Packets;
public struct ShinePacket : IPacket { public struct ShinePacket : IPacket {
public int ShineId; public int ShineId;
public short Size => 4;
public void Serialize(Span<byte> data) { public void Serialize(Span<byte> data) {
MemoryMarshal.Write(data, ref ShineId); MemoryMarshal.Write(data, ref ShineId);
} }

View file

@ -6,6 +6,8 @@ namespace Shared.Packet.Packets;
public struct TagPacket : IPacket { public struct TagPacket : IPacket {
public bool IsIt; public bool IsIt;
public short Size => 1;
public void Serialize(Span<byte> data) { public void Serialize(Span<byte> data) {
MemoryMarshal.Write(data, ref IsIt); MemoryMarshal.Write(data, ref IsIt);
} }

View file

@ -3,15 +3,19 @@
[Packet(PacketType.Unknown)] // empty like boss [Packet(PacketType.Unknown)] // empty like boss
// [Packet(PacketType.Command)] // [Packet(PacketType.Command)]
public struct UnhandledPacket : IPacket { public struct UnhandledPacket : IPacket {
public byte[] Data = new byte[Constants.PacketDataSize]; public byte[] Data;
public UnhandledPacket() { } public UnhandledPacket() {
Data = null!;
}
public short Size => 0;
public void Serialize(Span<byte> data) { public void Serialize(Span<byte> data) {
Data.CopyTo(data); Data.CopyTo(data);
} }
public void Deserialize(Span<byte> data) { public void Deserialize(Span<byte> data) {
data.CopyTo(Data); Data = data.ToArray();
} }
} }

View file

@ -6,73 +6,73 @@ using Shared;
using Shared.Packet; using Shared.Packet;
using Shared.Packet.Packets; using Shared.Packet.Packets;
TcpClient client = new TcpClient(args[0], 1027); // TcpClient client = new TcpClient(args[0], 1027);
Guid ownId = new Guid(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); Guid ownId = new Guid(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
// Guid ownId = Guid.NewGuid(); // Guid ownId = Guid.NewGuid();
Guid otherId = Guid.Parse("d5feae62-2e71-1000-88fd-597ea147ae88"); // Guid otherId = Guid.Parse("d5feae62-2e71-1000-88fd-597ea147ae88");
Logger logger = new Logger("Client"); // Logger logger = new Logger("Client");
NetworkStream stream = client.GetStream(); // NetworkStream stream = client.GetStream();
//
Vector3 basePoint = Vector3.Zero; // Vector3 basePoint = Vector3.Zero;
//
PacketType[] reboundPackets = { // PacketType[] reboundPackets = {
PacketType.Player, // PacketType.Player,
PacketType.Cap, // PacketType.Cap,
PacketType.Capture, // PacketType.Capture,
PacketType.Costume, // PacketType.Costume,
PacketType.Tag, // PacketType.Tag,
PacketType.Shine // PacketType.Shine
}; // };
//
string lastCapture = ""; // string lastCapture = "";
//
async Task S() { // async Task S() {
IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.Rent(Constants.MaxPacketSize); // IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.Rent(Constants.MaxPacketSize);
while (true) { // while (true) {
await stream.ReadAsync(owner.Memory); // await stream.ReadAsync(owner.Memory);
PacketHeader header = MemoryMarshal.Read<PacketHeader>(owner.Memory.Span); // PacketHeader header = MemoryMarshal.Read<PacketHeader>(owner.Memory.Span);
PacketType type = header.Type; // PacketType type = header.Type;
if (header.Id != otherId) continue; // if (header.Id != otherId) continue;
if (type is PacketType.Player) { // if (type is PacketType.Player) {
// CapPacket cap = new CapPacket(); // // CapPacket cap = new CapPacket();
PlayerPacket playerPacket = new PlayerPacket(); // PlayerPacket playerPacket = new PlayerPacket();
playerPacket.Deserialize(owner.Memory.Span[Constants.HeaderSize..]); // playerPacket.Deserialize(owner.Memory.Span[Constants.HeaderSize..]);
logger.Info(playerPacket.Hack); // logger.Info(playerPacket.Hack);
if (playerPacket.Hack != lastCapture) logger.Info($"Changed to hack: {lastCapture = playerPacket.Hack}"); // if (playerPacket.Hack != lastCapture) logger.Info($"Changed to hack: {lastCapture = playerPacket.Hack}");
// cap.Position = playerPacket.Position + Vector3.UnitY * 500f; // // cap.Position = playerPacket.Position + Vector3.UnitY * 500f;
// cap.Rotation = Quaternion.CreateFromYawPitchRoll(0,0,0); // // cap.Rotation = Quaternion.CreateFromYawPitchRoll(0,0,0);
// cap.CapAnim = "StayR"; // // cap.CapAnim = "StayR";
// playerPacket.Position = new Vector3(1000000f); // // playerPacket.Position = new Vector3(1000000f);
// playerPacket.ThrowingCap = true; // // playerPacket.ThrowingCap = true;
// header.Id = ownId; // // header.Id = ownId;
// MemoryMarshal.Write(owner.Memory.Span, ref header); // // MemoryMarshal.Write(owner.Memory.Span, ref header);
// playerPacket.Serialize(owner.Memory.Span[Constants.HeaderSize..]); // // playerPacket.Serialize(owner.Memory.Span[Constants.HeaderSize..]);
// await stream.WriteAsync(owner.Memory[..Constants.MaxPacketSize]); // // await stream.WriteAsync(owner.Memory[..Constants.MaxPacketSize]);
// header.Type = PacketType.Cap; // // header.Type = PacketType.Cap;
// MemoryMarshal.Write(owner.Memory.Span, ref header); // // MemoryMarshal.Write(owner.Memory.Span, ref header);
// cap.Serialize(owner.Memory.Span[Constants.HeaderSize..]); // // cap.Serialize(owner.Memory.Span[Constants.HeaderSize..]);
// await stream.WriteAsync(owner.Memory[..Constants.MaxPacketSize]); // // await stream.WriteAsync(owner.Memory[..Constants.MaxPacketSize]);
// continue; // // continue;
} // }
//
if (reboundPackets.All(x => x != type)) continue; // if (reboundPackets.All(x => x != type)) continue;
header.Id = ownId; // header.Id = ownId;
MemoryMarshal.Write(owner.Memory.Span, ref header); // MemoryMarshal.Write(owner.Memory.Span, ref header);
await stream.WriteAsync(owner.Memory[..Constants.MaxPacketSize]); // await stream.WriteAsync(owner.Memory[..Constants.MaxPacketSize]);
} // }
} // }
//
PacketHeader coolHeader = new PacketHeader { // PacketHeader coolHeader = new PacketHeader {
Type = PacketType.Connect, // Type = PacketType.Connect,
Id = ownId // Id = ownId
}; // };
IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.RentZero(Constants.MaxPacketSize); // IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.RentZero(Constants.MaxPacketSize);
MemoryMarshal.Write(owner.Memory.Span[..], ref coolHeader); // MemoryMarshal.Write(owner.Memory.Span[..], ref coolHeader);
ConnectPacket connect = new ConnectPacket { // ConnectPacket connect = new ConnectPacket {
ConnectionType = ConnectionTypes.Reconnecting, // ConnectionType = ConnectionTypes.Reconnecting,
ClientName = "Test Sanae" // ClientName = "Test Sanae"
}; // };
connect.Serialize(owner.Memory.Span[Constants.HeaderSize..Constants.MaxPacketSize]); // connect.Serialize(owner.Memory.Span[Constants.HeaderSize..Constants.MaxPacketSize]);
await stream.WriteAsync(owner.Memory); // await stream.WriteAsync(owner.Memory);
logger.Info("Connected"); // logger.Info("Connected");
await S(); // await S();