// Copyright © WireMock.Net using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Threading; namespace WireMock.Models; /// internal class BlockingQueue(TimeSpan? readTimeout = null) : IBlockingQueue { private readonly TimeSpan _readTimeout = readTimeout ?? TimeSpan.FromHours(1); private readonly Queue _queue = new(); private readonly object _lockObject = new(); private bool _isClosed; /// /// Writes an item to the queue and signals that an item is available. /// /// The item to be added to the queue. public void Write(T item) { lock (_lockObject) { if (_isClosed) { throw new InvalidOperationException("Cannot write to a closed queue."); } _queue.Enqueue(item); // Signal that an item is available Monitor.Pulse(_lockObject); } } /// /// Tries to read an item from the queue. /// - waits until an item is available /// - or the timeout occurs /// - or queue is closed /// /// The item read from the queue, or default if the timeout occurs. /// True if an item was successfully read; otherwise, false. public bool TryRead([NotNullWhen(true)] out T? item) { lock (_lockObject) { // Wait until an item is available or timeout occurs while (_queue.Count == 0 && !_isClosed) { // Wait with timeout if (!Monitor.Wait(_lockObject, _readTimeout)) { item = default; return false; } } // After waiting, check if we have items if (_queue.Count == 0) { item = default; return false; } item = _queue.Dequeue(); return item != null; } } /// /// Closes the queue and signals all waiting threads. /// public void Close() { lock (_lockObject) { _isClosed = true; Monitor.PulseAll(_lockObject); } } }