using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; using System.Windows.Forms; using DTS.Common.Utilities.Logging; namespace DTS.Common.Utils { public class SecureQueue : IDisposable where T : new() { public enum NullPolicy { DenyNull, // throw an exception if try to Enqueue null or zero length SkipNull, // don't complain but don't enqueue null or zero length AllowNull // let null's in too } protected Queue ByteQueue; protected object ByteQueueLock; protected ManualResetEvent ByteQueueEvent; protected NullPolicy _NullPolicy; protected string Name; protected Stopwatch StopWatch; public SecureQueue(NullPolicy policy, string name) { StopWatch = new Stopwatch(); StopWatch.Start(); ByteQueue = new Queue(); ByteQueueLock = new object(); ByteQueueEvent = new ManualResetEvent(false); _NullPolicy = policy; Name = name; } public void ResetEvent() { //latestReset = GetCaller(); ByteQueueEvent.Reset(); } public void Enqueue(T[] newData) { try { lock (ByteQueueLock) { if (newData == null || newData.Length == 0) { switch (_NullPolicy) { case NullPolicy.DenyNull: throw new ArgumentException("SecureQueue_Enqueue_Err1"); case NullPolicy.SkipNull: return; } } ByteQueue.Enqueue((T[])newData?.Clone()); if (Enums.DASFactory.DFConstantsAndEnums.ExtraCommunicationLogging) { APILogger.Log("Enqueing data", newData); } ByteQueueEvent.Set(); } } catch (Exception ex) { APILogger.LogString("SecureQueue.Enqueue: The queue(" + Name + ") threw an exception. " + ex.Message + " " + ex.StackTrace); throw; } } /// /// Wait for TimeoutMillisec milliseconds for data to arrive in the buffer. Returns false if it times out. /// /// /// true if data has arrived, false if it times out public bool WaitForData(int timeoutMillisec) { try { var result = ByteQueueEvent.WaitOne(timeoutMillisec, false); return result; } catch (Exception ex) { APILogger.LogString("SecureQueue.WaitForData: The queue(" + Name + ") threw an exception. " + ex.Message + " " + ex.StackTrace); } return false; } public WaitHandle QueueWaitHandle => ByteQueueEvent; public T[] Dequeue(bool resetEvent) { try { lock (ByteQueueLock) { ByteQueueEvent = new ManualResetEvent(false); if (ByteQueue.Count == 0) { return new T[0]; } if (ByteQueue.Count == 1) { var ret = ByteQueue.Dequeue(); return ret; } // count how much data we have var totalBytes = ByteQueue.Sum(arr => arr.Length); if (totalBytes == 0) { APILogger.LogString("SecureQueue.Dequeue: The queue(" + Name + ") has 0 bytes!"); } // allocate that much var result = new T[totalBytes]; var index = 0; // now make one large array while (ByteQueue.Any()) { var element = ByteQueue.Dequeue(); Array.Copy(element, 0, result, index, element.Length); index += element.Length; } return result; } } catch (Exception ex) { APILogger.LogString("SecureQueue.Dequeue: The queue(" + Name + ") threw an exception. " + ex.Message + " " + ex.StackTrace); } return new T[0]; } public void Flush() { try { lock (ByteQueueLock) { //latestFlush = GetCaller(); ByteQueueEvent = new ManualResetEvent(false); ByteQueue.Clear(); } } catch (Exception ex) { APILogger.LogString("SecureQueue.Flush: The queue(" + Name + ") threw an exception. " + ex.Message + " " + ex.StackTrace); } } public bool IsEmpty() { return ByteQueue.Count == 0; } public void Dispose() { } } }