From: AeonLucid Date: Sat, 31 Oct 2020 22:23:26 +0000 (+0100) Subject: Pooling X-Git-Tag: v1.2.2~55 X-Git-Url: https://git.deb.at/?a=commitdiff_plain;h=3faf1ebe134b2be349e17cd39bf92af1d6a11113;p=rhonda%2Fimpostor.git Pooling --- diff --git a/src/Impostor.Api/Net/Messages/IMessageReader.cs b/src/Impostor.Api/Net/Messages/IMessageReader.cs index 99e2e4d..3a99946 100644 --- a/src/Impostor.Api/Net/Messages/IMessageReader.cs +++ b/src/Impostor.Api/Net/Messages/IMessageReader.cs @@ -2,7 +2,7 @@ namespace Impostor.Api.Net.Messages { - public interface IMessageReader + public interface IMessageReader : IDisposable { /// /// Gets the tag of the message. @@ -58,4 +58,4 @@ namespace Impostor.Api.Net.Messages IMessageReader Slice(int start, int length); } -} \ No newline at end of file +} diff --git a/src/Impostor.Benchmarks/Tests/MessageReaderBenchmark.cs b/src/Impostor.Benchmarks/Tests/MessageReaderBenchmark.cs index c64ace9..c8ad228 100644 --- a/src/Impostor.Benchmarks/Tests/MessageReaderBenchmark.cs +++ b/src/Impostor.Benchmarks/Tests/MessageReaderBenchmark.cs @@ -62,20 +62,20 @@ namespace Impostor.Benchmarks.Tests } } - [Benchmark] - public void Normal_Run_1_000_000() - { - for (var i = 0; i < 1_000_000; i++) - { - var reader = new MessageReader(_data); - var inner = reader.ReadMessage(); - - _ = inner.ReadUInt16(); - _ = inner.ReadByte(); - _ = inner.ReadInt32(); - // inner.ReadPackedInt32(); - } - } + // [Benchmark] + // public void Normal_Run_1_000_000() + // { + // for (var i = 0; i < 1_000_000; i++) + // { + // var reader = new MessageReader(_data); + // var inner = reader.ReadMessage(); + // + // _ = inner.ReadUInt16(); + // _ = inner.ReadByte(); + // _ = inner.ReadInt32(); + // // inner.ReadPackedInt32(); + // } + // } [Benchmark] public void Bytes_Run_1_000_000() diff --git a/src/Impostor.Client.App/Program.cs b/src/Impostor.Client.App/Program.cs index cce1d29..aa8866a 100644 --- a/src/Impostor.Client.App/Program.cs +++ b/src/Impostor.Client.App/Program.cs @@ -34,7 +34,8 @@ namespace Impostor.Client.App NumImpostors = 2 }); - using (var connection = new UdpClientConnection(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 22023))) + // TODO: ObjectPool for MessageReaders + using (var connection = new UdpClientConnection(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 22023), null)) { var e = new ManualResetEvent(false); @@ -71,4 +72,4 @@ namespace Impostor.Client.App return default; } } -} \ No newline at end of file +} diff --git a/src/Impostor.Hazel/Extensions/ServiceProviderExtensions.cs b/src/Impostor.Hazel/Extensions/ServiceProviderExtensions.cs new file mode 100644 index 0000000..56c7380 --- /dev/null +++ b/src/Impostor.Hazel/Extensions/ServiceProviderExtensions.cs @@ -0,0 +1,21 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.ObjectPool; + +namespace Impostor.Hazel.Extensions +{ + public static class ServiceProviderExtensions + { + public static void AddHazel(this IServiceCollection services) + { + services.TryAddSingleton(new DefaultObjectPoolProvider()); + + services.AddSingleton(serviceProvider => + { + var provider = serviceProvider.GetRequiredService(); + var policy = ActivatorUtilities.CreateInstance(serviceProvider); + return provider.Create(policy); + }); + } + } +} diff --git a/src/Impostor.Hazel/Impostor.Hazel.csproj b/src/Impostor.Hazel/Impostor.Hazel.csproj index 9767304..53ed881 100644 --- a/src/Impostor.Hazel/Impostor.Hazel.csproj +++ b/src/Impostor.Hazel/Impostor.Hazel.csproj @@ -8,6 +8,7 @@ + diff --git a/src/Impostor.Hazel/MessageReader.cs b/src/Impostor.Hazel/MessageReader.cs index f81c482..df6d014 100644 --- a/src/Impostor.Hazel/MessageReader.cs +++ b/src/Impostor.Hazel/MessageReader.cs @@ -3,26 +3,41 @@ using System.Buffers.Binary; using System.Runtime.CompilerServices; using System.Text; using Impostor.Api.Net.Messages; +using Microsoft.Extensions.ObjectPool; namespace Impostor.Hazel { public class MessageReader : IMessageReader { - public byte Tag { get; } - public ReadOnlyMemory Buffer { get; } + private readonly ObjectPool _pool; + + public byte Tag { get; private set; } + public ReadOnlyMemory Buffer { get; private set; } public int Position { get; set; } public int Length => Buffer.Length; - public MessageReader(ReadOnlyMemory buffer) + internal MessageReader(ObjectPool pool) { - Tag = byte.MaxValue; - Buffer = buffer; + _pool = pool; } - public MessageReader(byte tag, ReadOnlyMemory buffer) + public void Update(ReadOnlyMemory buffer) + { + Update(byte.MaxValue, buffer); + } + + public void Update(byte tag, ReadOnlyMemory buffer) { Tag = tag; Buffer = buffer; + Position = 0; + } + + internal void Reset() + { + Tag = byte.MaxValue; + Buffer = null; + Position = 0; } public IMessageReader ReadMessage() @@ -33,7 +48,9 @@ namespace Impostor.Hazel Position += length; - return new MessageReader(tag, Buffer.Slice(pos, length)); + var reader = _pool.Get(); + reader.Update(tag, Buffer.Slice(pos, length)); + return reader; } public bool ReadBoolean() @@ -148,12 +165,16 @@ namespace Impostor.Hazel public IMessageReader Slice(int start) { - return new MessageReader(Tag, Buffer.Slice(start)); + var reader = _pool.Get(); + reader.Update(Tag, Buffer.Slice(start)); + return reader; } public IMessageReader Slice(int start, int length) { - return new MessageReader(Tag, Buffer.Slice(start, length)); + var reader = _pool.Get(); + reader.Update(Tag, Buffer.Slice(start, length)); + return reader; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -161,5 +182,10 @@ namespace Impostor.Hazel { return Buffer.Span[Position++]; } + + public void Dispose() + { + _pool.Return(this); + } } -} \ No newline at end of file +} diff --git a/src/Impostor.Hazel/MessageReaderPolicy.cs b/src/Impostor.Hazel/MessageReaderPolicy.cs new file mode 100644 index 0000000..995ad78 --- /dev/null +++ b/src/Impostor.Hazel/MessageReaderPolicy.cs @@ -0,0 +1,27 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.ObjectPool; + +namespace Impostor.Hazel +{ + public class MessageReaderPolicy : IPooledObjectPolicy + { + private readonly IServiceProvider _serviceProvider; + + public MessageReaderPolicy(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public MessageReader Create() + { + return new MessageReader(_serviceProvider.GetRequiredService>()); + } + + public bool Return(MessageReader obj) + { + obj.Reset(); + return true; + } + } +} diff --git a/src/Impostor.Hazel/MessageWriter.cs b/src/Impostor.Hazel/MessageWriter.cs index d12c7c9..5b7342a 100644 --- a/src/Impostor.Hazel/MessageWriter.cs +++ b/src/Impostor.Hazel/MessageWriter.cs @@ -11,7 +11,7 @@ namespace Impostor.Hazel public class MessageWriter : IMessageWriter, IRecyclable, IDisposable { private static int BufferSize = 64000; - private static readonly ObjectPool WriterPool = new ObjectPool(() => new MessageWriter(BufferSize)); + private static readonly ObjectPoolCustom WriterPool = new ObjectPoolCustom(() => new MessageWriter(BufferSize)); public MessageType SendOption { get; private set; } diff --git a/src/Impostor.Hazel/ObjectPool.cs b/src/Impostor.Hazel/ObjectPool.cs deleted file mode 100644 index 6d6ce6e..0000000 --- a/src/Impostor.Hazel/ObjectPool.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Threading; - -namespace Impostor.Hazel -{ - /// - /// A fairly simple object pool for items that will be created a lot. - /// - /// The type that is pooled. - /// - public sealed class ObjectPool where T : IRecyclable - { - private int numberCreated; - public int NumberCreated { get { return numberCreated; } } - - public int NumberInUse { get { return this.inuse.Count; } } - public int NumberNotInUse { get { return this.pool.Count; } } - public int Size { get { return this.NumberInUse + this.NumberNotInUse; } } - -#if HAZEL_BAG - private readonly ConcurrentBag pool = new ConcurrentBag(); -#else - private readonly List pool = new List(); -#endif - - // Unavailable objects - private readonly ConcurrentDictionary inuse = new ConcurrentDictionary(); - - /// - /// The generator for creating new objects. - /// - /// - private readonly Func objectFactory; - - /// - /// Internal constructor for our ObjectPool. - /// - internal ObjectPool(Func objectFactory) - { - this.objectFactory = objectFactory; - } - - /// - /// Returns a pooled object of type T, if none are available another is created. - /// - /// An instance of T. - internal T GetObject() - { -#if HAZEL_BAG - if (!pool.TryTake(out T item)) - { - Interlocked.Increment(ref numberCreated); - item = objectFactory.Invoke(); - } -#else - T item; - lock (this.pool) - { - if (this.pool.Count > 0) - { - var idx = this.pool.Count - 1; - item = this.pool[idx]; - this.pool.RemoveAt(idx); - } - else - { - Interlocked.Increment(ref numberCreated); - item = objectFactory.Invoke(); - } - } -#endif - - if (!inuse.TryAdd(item, true)) - { - throw new Exception("Duplicate pull " + typeof(T).Name); - } - - return item; - } - - /// - /// Returns an object to the pool. - /// - /// The item to return. - internal void PutObject(T item) - { - if (inuse.TryRemove(item, out bool b)) - { -#if HAZEL_BAG - pool.Add(item); -#else - lock (this.pool) - { - pool.Add(item); - } -#endif - } - else - { -#if DEBUG - throw new Exception("Duplicate add " + typeof(T).Name); -#endif - } - } - } -} diff --git a/src/Impostor.Hazel/ObjectPoolCustom.cs b/src/Impostor.Hazel/ObjectPoolCustom.cs new file mode 100644 index 0000000..5c9ef9b --- /dev/null +++ b/src/Impostor.Hazel/ObjectPoolCustom.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Concurrent; +using System.Threading; + +namespace Impostor.Hazel +{ + /// + /// A fairly simple object pool for items that will be created a lot. + /// + /// The type that is pooled. + /// + public sealed class ObjectPoolCustom where T : IRecyclable + { + private int numberCreated; + public int NumberCreated { get { return numberCreated; } } + + public int NumberInUse { get { return this.inuse.Count; } } + public int NumberNotInUse { get { return this.pool.Count; } } + public int Size { get { return this.NumberInUse + this.NumberNotInUse; } } + +#if HAZEL_BAG + private readonly ConcurrentBag pool = new ConcurrentBag(); +#else + private readonly List pool = new List(); +#endif + + // Unavailable objects + private readonly ConcurrentDictionary inuse = new ConcurrentDictionary(); + + /// + /// The generator for creating new objects. + /// + /// + private readonly Func objectFactory; + + /// + /// Internal constructor for our ObjectPool. + /// + internal ObjectPoolCustom(Func objectFactory) + { + this.objectFactory = objectFactory; + } + + /// + /// Returns a pooled object of type T, if none are available another is created. + /// + /// An instance of T. + internal T GetObject() + { +#if HAZEL_BAG + if (!pool.TryTake(out T item)) + { + Interlocked.Increment(ref numberCreated); + item = objectFactory.Invoke(); + } +#else + T item; + lock (this.pool) + { + if (this.pool.Count > 0) + { + var idx = this.pool.Count - 1; + item = this.pool[idx]; + this.pool.RemoveAt(idx); + } + else + { + Interlocked.Increment(ref numberCreated); + item = objectFactory.Invoke(); + } + } +#endif + + if (!inuse.TryAdd(item, true)) + { + throw new Exception("Duplicate pull " + typeof(T).Name); + } + + return item; + } + + /// + /// Returns an object to the pool. + /// + /// The item to return. + internal void PutObject(T item) + { + if (inuse.TryRemove(item, out bool b)) + { +#if HAZEL_BAG + pool.Add(item); +#else + lock (this.pool) + { + pool.Add(item); + } +#endif + } + else + { +#if DEBUG + throw new Exception("Duplicate add " + typeof(T).Name); +#endif + } + } + } +} diff --git a/src/Impostor.Hazel/Udp/UdpClientConnection.cs b/src/Impostor.Hazel/Udp/UdpClientConnection.cs index 4f81177..d2f5e59 100644 --- a/src/Impostor.Hazel/Udp/UdpClientConnection.cs +++ b/src/Impostor.Hazel/Udp/UdpClientConnection.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; using Impostor.Api.Net.Messages; +using Microsoft.Extensions.ObjectPool; using Serilog; namespace Impostor.Hazel.Udp @@ -34,7 +35,7 @@ namespace Impostor.Hazel.Udp /// Creates a new UdpClientConnection. /// /// A to connect to. - public UdpClientConnection(IPEndPoint remoteEndPoint, IPMode ipMode = IPMode.IPv4) : base(null) + public UdpClientConnection(IPEndPoint remoteEndPoint, ObjectPool readerPool, IPMode ipMode = IPMode.IPv4) : base(null, readerPool) { EndPoint = remoteEndPoint; RemoteEndPoint = remoteEndPoint; @@ -249,4 +250,4 @@ namespace Impostor.Hazel.Udp base.Dispose(disposing); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Hazel/Udp/UdpConnection.KeepAlive.cs b/src/Impostor.Hazel/Udp/UdpConnection.KeepAlive.cs index 81cffab..a73291b 100644 --- a/src/Impostor.Hazel/Udp/UdpConnection.KeepAlive.cs +++ b/src/Impostor.Hazel/Udp/UdpConnection.KeepAlive.cs @@ -14,7 +14,7 @@ namespace Impostor.Hazel.Udp /// public class PingPacket : IRecyclable { - private static readonly ObjectPool PacketPool = new ObjectPool(() => new PingPacket()); + private static readonly ObjectPoolCustom PacketPool = new ObjectPoolCustom(() => new PingPacket()); public readonly Stopwatch Stopwatch = new Stopwatch(); diff --git a/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs b/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs index 4d925ff..25c3633 100644 --- a/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs +++ b/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs @@ -87,7 +87,7 @@ namespace Impostor.Hazel.Udp /// /// Object pool for this event. /// - public static readonly ObjectPool PacketPool = new ObjectPool(() => new Packet()); + public static readonly ObjectPoolCustom PacketPool = new ObjectPoolCustom(() => new Packet()); /// /// Returns an instance of this object from the pool. diff --git a/src/Impostor.Hazel/Udp/UdpConnection.cs b/src/Impostor.Hazel/Udp/UdpConnection.cs index 4990469..4fffb30 100644 --- a/src/Impostor.Hazel/Udp/UdpConnection.cs +++ b/src/Impostor.Hazel/Udp/UdpConnection.cs @@ -17,15 +17,17 @@ namespace Impostor.Hazel.Udp private static readonly ILogger Logger = Log.ForContext(); private readonly ConnectionListener _listener; + private readonly Microsoft.Extensions.ObjectPool.ObjectPool _readerPool; private readonly CancellationTokenSource _stoppingCts; private bool _isDisposing; private bool _isFirst = true; private Task _executingTask; - protected UdpConnection(ConnectionListener listener) + protected UdpConnection(ConnectionListener listener, Microsoft.Extensions.ObjectPool.ObjectPool readerPool) { _listener = listener; + _readerPool = readerPool; _stoppingCts = new CancellationTokenSource(); Pipeline = Channel.CreateUnbounded(new UnboundedChannelOptions @@ -89,7 +91,11 @@ namespace Impostor.Hazel.Udp try { - await HandleReceive(new MessageReader(result.Buffer)); + using (var reader = _readerPool.Get()) + { + reader.Update(byte.MaxValue, result.Buffer); + await HandleReceive(reader); + } } catch (Exception e) { diff --git a/src/Impostor.Hazel/Udp/UdpConnectionListener.cs b/src/Impostor.Hazel/Udp/UdpConnectionListener.cs index f00f98f..b0f7cef 100644 --- a/src/Impostor.Hazel/Udp/UdpConnectionListener.cs +++ b/src/Impostor.Hazel/Udp/UdpConnectionListener.cs @@ -6,6 +6,7 @@ using System.Net.Sockets; using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; +using Microsoft.Extensions.ObjectPool; using Serilog; namespace Impostor.Hazel.Udp @@ -27,6 +28,7 @@ namespace Impostor.Hazel.Udp public delegate bool AcceptConnectionCheck(IPEndPoint endPoint, byte[] input, out byte[] response); private readonly UdpClient _socket; + private readonly ObjectPool _readerPool; private readonly MemoryPool _pool; private readonly Timer _reliablePacketTimer; private readonly ConcurrentDictionary _allConnections; @@ -39,11 +41,12 @@ namespace Impostor.Hazel.Udp /// /// The endpoint to listen on. /// - public UdpConnectionListener(IPEndPoint endPoint, IPMode ipMode = IPMode.IPv4) + public UdpConnectionListener(IPEndPoint endPoint, ObjectPool readerPool, IPMode ipMode = IPMode.IPv4) { EndPoint = endPoint; IPMode = ipMode; + _readerPool = readerPool; _pool = MemoryPool.Shared; _socket = new UdpClient(endPoint) { @@ -165,7 +168,7 @@ namespace Impostor.Hazel.Udp } // Create new client - client = new UdpServerConnection(this, data.RemoteEndPoint, IPMode); + client = new UdpServerConnection(this, data.RemoteEndPoint, IPMode, _readerPool); // Store the client if (!_allConnections.TryAdd(data.RemoteEndPoint, client)) diff --git a/src/Impostor.Hazel/Udp/UdpServerConnection.cs b/src/Impostor.Hazel/Udp/UdpServerConnection.cs index 0803496..22eed98 100644 --- a/src/Impostor.Hazel/Udp/UdpServerConnection.cs +++ b/src/Impostor.Hazel/Udp/UdpServerConnection.cs @@ -2,6 +2,7 @@ using System.Net; using System.Threading.Tasks; using Impostor.Api.Net.Messages; +using Microsoft.Extensions.ObjectPool; namespace Impostor.Hazel.Udp { @@ -26,7 +27,7 @@ namespace Impostor.Hazel.Udp /// The listener that created this connection. /// The endpoint that we are connected to. /// The IPMode we are connected using. - internal UdpServerConnection(UdpConnectionListener listener, IPEndPoint endPoint, IPMode IPMode) : base(listener) + internal UdpServerConnection(UdpConnectionListener listener, IPEndPoint endPoint, IPMode IPMode, ObjectPool readerPool) : base(listener, readerPool) { this.Listener = listener; this.RemoteEndPoint = endPoint; diff --git a/src/Impostor.Server/Net/Matchmaker.cs b/src/Impostor.Server/Net/Matchmaker.cs index 1c1bcf3..64ece55 100644 --- a/src/Impostor.Server/Net/Matchmaker.cs +++ b/src/Impostor.Server/Net/Matchmaker.cs @@ -7,23 +7,27 @@ using Impostor.Hazel.Udp; using Impostor.Server.Net.Hazel; using Impostor.Server.Net.Manager; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.ObjectPool; namespace Impostor.Server.Net { internal class Matchmaker { private readonly ClientManager _clientManager; + private readonly ObjectPool _readerPool; private readonly ILogger _logger; - private readonly ILogger _connectionLogger; + private readonly ILogger _connectionLogger; private UdpConnectionListener _connection; public Matchmaker( ILogger logger, ClientManager clientManager, + ObjectPool readerPool, ILogger connectionLogger) { _logger = logger; _clientManager = clientManager; + _readerPool = readerPool; _connectionLogger = connectionLogger; } @@ -36,7 +40,7 @@ namespace Impostor.Server.Net _ => throw new InvalidOperationException() }; - _connection = new UdpConnectionListener(ipEndPoint, mode); + _connection = new UdpConnectionListener(ipEndPoint, _readerPool, mode); _connection.NewConnection = OnNewConnection; await _connection.StartAsync(); @@ -59,4 +63,4 @@ namespace Impostor.Server.Net await _clientManager.RegisterConnectionAsync(connection, name, clientVersion); } } -} \ No newline at end of file +} diff --git a/src/Impostor.Server/Program.cs b/src/Impostor.Server/Program.cs index a646267..234ee01 100644 --- a/src/Impostor.Server/Program.cs +++ b/src/Impostor.Server/Program.cs @@ -4,6 +4,7 @@ using Impostor.Api.Games; using Impostor.Api.Games.Managers; using Impostor.Api.Net.Manager; using Impostor.Api.Net.Messages; +using Impostor.Hazel.Extensions; using Impostor.Server.Config; using Impostor.Server.Events; using Impostor.Server.Net; @@ -171,6 +172,7 @@ namespace Impostor.Server services.AddSingleton(p => p.GetRequiredService()); } + services.AddHazel(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/Impostor.Tests/Hazel/MessageReaderTests.cs b/src/Impostor.Tests/Hazel/MessageReaderTests.cs index 0d1f613..2658e29 100644 --- a/src/Impostor.Tests/Hazel/MessageReaderTests.cs +++ b/src/Impostor.Tests/Hazel/MessageReaderTests.cs @@ -1,10 +1,21 @@ -using Impostor.Hazel; +using System; +using Impostor.Hazel; +using Impostor.Hazel.Extensions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.ObjectPool; using Xunit; namespace Impostor.Tests.Hazel { public class BufferMessageReaderTests { + private ObjectPool CreateReaderPool() + { + var services = new ServiceCollection(); + services.AddHazel(); + return services.BuildServiceProvider().GetRequiredService>(); + } + [Fact] public void ReadProperInt() { @@ -20,7 +31,9 @@ namespace Impostor.Tests.Hazel Assert.Equal(11, msg.Length); Assert.Equal(msg.Length, msg.Position); - var reader = new MessageReader(msg.Buffer); + var readerPool = CreateReaderPool(); + var reader = readerPool.Get(); + reader.Update(msg.Buffer); Assert.Equal(byte.MaxValue, reader.Tag); var message = reader.ReadMessage(); Assert.Equal(1, message.Tag); @@ -43,7 +56,9 @@ namespace Impostor.Tests.Hazel Assert.Equal(5, msg.Length); Assert.Equal(msg.Length, msg.Position); - var reader = new MessageReader(msg.Buffer); + var readerPool = CreateReaderPool(); + var reader = readerPool.Get(); + reader.Update(msg.Buffer); Assert.Equal(byte.MaxValue, reader.Tag); var message = reader.ReadMessage(); Assert.Equal(1, message.Tag); @@ -65,7 +80,9 @@ namespace Impostor.Tests.Hazel Assert.Equal(msg.Length, msg.Position); - var reader = new MessageReader(msg.Buffer); + var readerPool = CreateReaderPool(); + var reader = readerPool.Get(); + reader.Update(msg.Buffer); Assert.Equal(byte.MaxValue, reader.Tag); var message = reader.ReadMessage(); Assert.Equal(1, message.Tag); @@ -87,7 +104,9 @@ namespace Impostor.Tests.Hazel Assert.Equal(7, msg.Length); Assert.Equal(msg.Length, msg.Position); - var reader = new MessageReader(msg.Buffer); + var readerPool = CreateReaderPool(); + var reader = readerPool.Get(); + reader.Update(msg.Buffer); Assert.Equal(byte.MaxValue, reader.Tag); var message = reader.ReadMessage(); Assert.Equal(1, message.Tag); @@ -110,7 +129,9 @@ namespace Impostor.Tests.Hazel msg.EndMessage(); - var handleReader = new MessageReader(msg.Buffer); + var readerPool = CreateReaderPool(); + var handleReader = readerPool.Get(); + handleReader.Update(msg.Buffer); var handleMessage = handleReader.ReadMessage(); Assert.Equal(1, handleMessage.Tag); @@ -141,7 +162,9 @@ namespace Impostor.Tests.Hazel Assert.Equal(msg.Length, msg.Position); - var reader = new MessageReader(msg.Buffer); + var readerPool = CreateReaderPool(); + var reader = readerPool.Get(); + reader.Update(msg.Buffer); Assert.Equal(byte.MaxValue, reader.Tag); var message = reader.ReadMessage(); Assert.Equal(1, message.Tag); @@ -189,7 +212,9 @@ namespace Impostor.Tests.Hazel messageWriter.EndMessage(); // Do the magic. - var reader = new MessageReader(messageWriter.Buffer); + var readerPool = CreateReaderPool(); + var reader = readerPool.Get(); + reader.Update(messageWriter.Buffer); var inner = reader.ReadMessage(); while (inner.Position < inner.Length) diff --git a/src/Impostor.Tools.Proxy/Impostor.Tools.Proxy.csproj b/src/Impostor.Tools.Proxy/Impostor.Tools.Proxy.csproj index f111871..9118c83 100644 --- a/src/Impostor.Tools.Proxy/Impostor.Tools.Proxy.csproj +++ b/src/Impostor.Tools.Proxy/Impostor.Tools.Proxy.csproj @@ -6,6 +6,7 @@ + diff --git a/src/Impostor.Tools.Proxy/Program.cs b/src/Impostor.Tools.Proxy/Program.cs index fdfce50..d891bdf 100644 --- a/src/Impostor.Tools.Proxy/Program.cs +++ b/src/Impostor.Tools.Proxy/Program.cs @@ -3,7 +3,10 @@ using System.Collections.Generic; using System.Linq; using Impostor.Api.Net.Messages; using Impostor.Hazel; +using Impostor.Hazel.Extensions; using Impostor.Hazel.Udp; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.ObjectPool; using PcapDotNet.Core; using PcapDotNet.Packets; @@ -32,9 +35,18 @@ namespace Impostor.Tools.Proxy {14, "ReselectServer"}, {16, "GetGameListV2"} }; - + + private static IServiceProvider _serviceProvider; + private static ObjectPool _readerPool; + private static void Main(string[] args) { + var services = new ServiceCollection(); + services.AddHazel(); + + _serviceProvider = services.BuildServiceProvider(); + _readerPool = _serviceProvider.GetRequiredService>(); + var devices = LivePacketDevice.AllLocalMachine; if (devices.Count == 0) { @@ -69,11 +81,14 @@ namespace Impostor.Tools.Proxy // True if this is our own packet. using (var stream = udp.Payload.ToMemoryStream()) { - var reader = (IMessageReader) new MessageReader(stream.ToArray()); + using var reader = _readerPool.Get(); + + reader.Update(stream.ToArray()); + var option = reader.Buffer.Span[0]; if (option == (byte) MessageType.Reliable) { - reader = reader.Slice(3); + reader.Position += 3; } else if (option == (byte) UdpSendOption.Acknowledgement || option == (byte) UdpSendOption.Ping || @@ -84,7 +99,7 @@ namespace Impostor.Tools.Proxy } else { - reader = reader.Slice(1); + reader.Position += 1; } var isSent = ipSrc.StartsWith("192."); diff --git a/src/Impostor.Tools.ServerReplay/Program.cs b/src/Impostor.Tools.ServerReplay/Program.cs index 8ae8bfa..3fe40e6 100644 --- a/src/Impostor.Tools.ServerReplay/Program.cs +++ b/src/Impostor.Tools.ServerReplay/Program.cs @@ -21,6 +21,7 @@ using Impostor.Server.Recorder; using Impostor.Tools.ServerReplay.Mocks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.ObjectPool; using Serilog; using ILogger = Serilog.ILogger; @@ -36,6 +37,7 @@ namespace Impostor.Tools.ServerReplay private static ServiceProvider _serviceProvider; + private static ObjectPool _readerPool; private static MockGameCodeFactory _gameCodeFactory; private static ClientManager _clientManager; private static GameManager _gameManager; @@ -54,6 +56,7 @@ namespace Impostor.Tools.ServerReplay _serviceProvider = BuildServices(); // Create required instances. + _readerPool = _serviceProvider.GetRequiredService>(); _gameCodeFactory = _serviceProvider.GetRequiredService(); _clientManager = _serviceProvider.GetRequiredService(); _gameManager = _serviceProvider.GetRequiredService(); @@ -143,11 +146,14 @@ namespace Impostor.Tools.ServerReplay break; case RecordedPacketType.Message: - var messageType = (MessageType) reader.ReadByte(); + { + var messageType = (MessageType)reader.ReadByte(); var tag = reader.ReadByte(); var length = reader.ReadInt32(); var buffer = reader.ReadBytes(length); - var message = new MessageReader(tag, buffer); + using var message = _readerPool.Get(); + + message.Update(tag, buffer); if (tag == MessageFlags.HostGame) { @@ -157,7 +163,9 @@ namespace Impostor.Tools.ServerReplay { await client.Client!.HandleMessageAsync(message, messageType); } + break; + } case RecordedPacketType.GameCreated: _gameCodeFactory.Result = GameCode.From(reader.ReadString()); @@ -172,4 +180,4 @@ namespace Impostor.Tools.ServerReplay } } } -} \ No newline at end of file +}