using System; using System.Collections; using System.Collections.Generic; using System.Threading; using Wayne.Lib; using Wayne.Lib.Log; namespace Wayne.ForecourtControl.Fusion { class AsyncResponseOperation : IDisposable { public int requestId; public EventHandler requestCompleted; public long resultLong; public ITankReadingEx resultITankReading; public ITankReconciliation resultITankReconciliation; public ITankDelivery resultITankDelivery; public IList resultFuelPriceReading; public PumpAccumulatorReading resultPumpAccumulatorReading; public object userToken; public object src; private System.Threading.Timer responseTimer = null; public event EventHandler OnResponseTimeout; public AsyncResponseOperation(int requestId, int responseTimeout, EventHandler requestCompleted, object userToken, object src) { this.requestId = requestId; this.requestCompleted = requestCompleted; this.userToken = userToken; this.src = src; if (responseTimeout > 0) responseTimer = new System.Threading.Timer(new System.Threading.TimerCallback(ResponseTimeout), this, responseTimeout, System.Threading.Timeout.Infinite); } public void Dispose() { if (responseTimer != null) responseTimer.Dispose(); } private void ResponseTimeout(Object state) { if (OnResponseTimeout != null) OnResponseTimeout.Invoke(this, null); } } public class AsyncResponseManager { public Hashtable AsyncResponseOperationList; public event EventHandler OnResponseTimeout; private readonly DebugLogger debugLogger; public AsyncResponseManager(DebugLogger debugLogger) { this.debugLogger = debugLogger; AsyncResponseOperationList = new Hashtable(); } private void DebugLog(string s) { if (debugLogger.IsActive()) debugLogger.Add(s); } public void OnMessageEnqueuing(object sender, MessageEnqueuedEventArgs e) { // add the request to the 'waiting for response request list' DebugLog("init enqueuing message"); AsyncResponseOperation asyncResponseOperation = null; try { Monitor.Enter(AsyncResponseOperationList); if (e.ResponseRequired) { if (e.RequestCompleted != null) asyncResponseOperation = new AsyncResponseOperation(e.RequestId, e.ResponseTimeout, e.RequestCompleted, e.UserToken, e.Scr); else asyncResponseOperation = new AsyncResponseOperation(e.RequestId, e.ResponseTimeout, null, null, null); asyncResponseOperation.OnResponseTimeout += new EventHandler(asyncResponseOperation_OnResponseTimeout); AsyncResponseOperationList.Add(e.RequestId, asyncResponseOperation); } } catch (Exception ex) { DebugLog("Exception! " + ex.ToString()); } finally { Monitor.Exit(AsyncResponseOperationList); } DebugLog("end enqueuing message"); } private void asyncResponseOperation_OnResponseTimeout(object sender, EventArgs e) { DebugLog("OnResponseTimeout init"); var operation = sender as AsyncResponseOperation; SendResponse(operation.requestId, false); if (OnResponseTimeout != null) OnResponseTimeout.Invoke(this, e); DebugLog("OnResponseTimeout end"); } public void SendResponse(int requestId, bool result) { SendResponse(requestId, result, null); } /// /// Invokes the standard EventHandler<AsyncCompletedEventArgs> , but with an instance of /// AsyncCompletedEventArgs<TResponseData> is actually passed as an argument. So the actual /// response data is sent, even through the signature is unchanged. /// /// /// /// /// public void SendResponse(int requestId, bool result, TResponseData responseData) { AsyncResponseOperation asyncResponseOperation = null; try { DebugLog(string.Format("SendResponse init requestId={0}", requestId)); Monitor.Enter(AsyncResponseOperationList); if (AsyncResponseOperationList.ContainsKey(requestId)) { asyncResponseOperation = (AsyncResponseOperation)(this.AsyncResponseOperationList[requestId]); this.RemoveRequest(requestId); } DebugLog(string.Format("SendResponse got operation requestId={0}", requestId)); } catch (Exception ex) { DebugLog("AsyncResponseOperation Exception! " + ex.ToString()); } finally { Monitor.Exit(AsyncResponseOperationList); } try { if (asyncResponseOperation != null) { if (asyncResponseOperation.requestCompleted != null) { DebugLog(string.Format("SendResponse requestId={0} requestCompleted != null", requestId)); asyncResponseOperation.requestCompleted(asyncResponseOperation.src, new AsyncCompletedEventArgs(result, responseData, asyncResponseOperation.userToken)); } } DebugLog(string.Format("SendResponse end requestId={0}", requestId)); } catch (Exception ex) { DebugLog("SendResponse Exception! " + ex.ToString()); } } public void SendResponse(int requestId, bool result, Object objresult) { AsyncResponseOperation asyncResponseOperation = null; try { DebugLog(string.Format("SendResponse init requestId={0}", requestId)); Monitor.Enter(AsyncResponseOperationList); if (AsyncResponseOperationList.ContainsKey(requestId)) { asyncResponseOperation = (AsyncResponseOperation)(this.AsyncResponseOperationList[requestId]); this.RemoveRequest(requestId); } DebugLog(string.Format("SendResponse got operation requestId={0}", requestId)); } catch (Exception ex) { DebugLog("AsyncResponseOperation Exception! " + ex.ToString()); } finally { Monitor.Exit(AsyncResponseOperationList); } try { if (asyncResponseOperation != null) { if (asyncResponseOperation.requestCompleted != null) { DebugLog(string.Format("SendResponse requestId={0} requestCompleted != null", requestId)); asyncResponseOperation.requestCompleted(asyncResponseOperation.src, new AsyncCompletedEventArgs(result, asyncResponseOperation.userToken)); } } DebugLog(string.Format("SendResponse end requestId={0}", requestId)); } catch (Exception ex) { DebugLog("SendResponse Exception! " + ex.ToString()); } } private void RemoveRequest(int requestId) { try { if (this.AsyncResponseOperationList.ContainsKey(requestId)) { AsyncResponseOperation asyncResponseOperation = (AsyncResponseOperation)(this.AsyncResponseOperationList[requestId]); asyncResponseOperation.Dispose(); AsyncResponseOperationList.Remove(requestId); } } catch (Exception ex) { DebugLog("RemoveRequest Exception! " + ex.ToString()); } } } }