using System.Threading.Channels; namespace Manager.App.Services; public class CircularBuffer { private readonly T[] _buffer; private readonly Channel _channel; private readonly object _lock = new(); public int Capacity { get; } public int Head { get; private set; } public int Count { get; private set; } public CircularBuffer(int capacity) { if (capacity <= 0) { throw new ArgumentOutOfRangeException(nameof(capacity)); } Capacity = capacity; _buffer = new T[Capacity]; _channel = Channel.CreateBounded(new BoundedChannelOptions(Capacity) { SingleReader = false, SingleWriter = false, FullMode = BoundedChannelFullMode.DropOldest }); } public void Add(T item) { lock (_lock) { _buffer[Head] = item; Head = (Head + 1) % _buffer.Length; if (Count < _buffer.Length) { Count++; } } _channel.Writer.TryWrite(item); } public IEnumerable Items { get { for (var i = 0; i < Count; i++) { lock (_lock) { yield return _buffer[(Head - Count + i + _buffer.Length) % _buffer.Length]; } } } } public IAsyncEnumerable GetStreamAsync() => _channel.Reader.ReadAllAsync(); }