/// <summary> /// Monitors the queue of pending commands and causes the next pending request /// to be sent to Cornerstone. /// </summary> private void MonitorQueue() { while (true) { //Wait until we have a request in the queue _requestEnqueued.WaitOne(); //Check to see if we are already processing another command. We do not //want to process the next command until a response has been returned for //command currently being processed. if (_pendingCommand == null) { //Prepare to send this command. Grab it off of the queue. SendDataEventArgs eventArgs; if (_pendingCommands.TryDequeue(out eventArgs)) { //Make sure the command has data to be sent. var data = eventArgs.Data; if (data != null) { //If the command does not already have an cookie, we will give //it a GUID as its cookie. if (String.IsNullOrEmpty(eventArgs.Cookie)) { eventArgs.Cookie = Guid.NewGuid().ToString(); } if (data.StartsWith("<")) { var document = XDocument.Parse(data); //Add on the cookie ID and the current request culture to the data XML. document.Root.SetAttributeValue("Cookie", eventArgs.Cookie); document.Root.SetAttributeValue("Culture", RequestCulture); data = document.ToString(); } //Keep track of this command. _pendingCommand = eventArgs; //Fire the command off to Cornerstone. SendData(EncodingToUse.GetBytes(data)); //Let the sender know that the data went out. if (eventArgs.Sender != null) { eventArgs.Sender.TrafficOut(data); } } } } if (_pendingCommands.Count > 0) { _requestEnqueued.Set(); } } }
/// <summary> /// Called when data is received from Cornerstone. This method will be called multiple /// times until all of the data in response to a command is received. When Cornerstone /// responds to a command, it will first send the number of bytes contained in the command /// response, followed by the command response itself. This method uses the ReceivedDataStateObject /// to keep a running compilation of the data received in the case where Cornerstone's response /// does not arrive all at once. /// </summary> /// <param name="ar">Received data.</param> private void DataReceived(IAsyncResult ar) { try { var stateObject = ar.AsyncState as ReceivedDataStateObject; if (stateObject == null) { //The state object is null which indicates that this is a new response and not a continuation //of a previous response. var bytes = _tcpClient.GetStream().EndRead(ar); // Detect the stream ended. if (bytes == 0) { return; } //Get the number of bytes contained in the command response. int length = BitConverter.ToInt32(_receiveBuffer, 0); //Create a state object to hold onto the response. stateObject = new ReceivedDataStateObject { Length = length }; EventAggregatorContext.Current.GetEvent <RecordDataTrafficEvent>().Publish(new DataTrafficSentReceivedViewModel(_receiveBuffer, false, bytes)); //check if we have received more than 4 bytes. The 4 bytes contains the length of the following //data. If we have received more than the 4 bytes, we need to add that to our buffer. if (bytes > 4) { stateObject.Length -= (bytes - 4); stateObject.Data += EncodingToUse.GetString(_receiveBuffer, 4, bytes - 4); //check if we have received it all. if (stateObject.Length <= 0) { //process the data we have received. ProcessReceivedData(stateObject); } } //Set ourselves up to be notified when more data arrives. _tcpClient.GetStream().BeginRead(_receiveBuffer, 0, _receiveBuffer.Length, DataReceived, stateObject); } else { //Find out how many bytes are in the response. var bytes = _tcpClient.GetStream().EndRead(ar); //Subtract them from the total that we are expecting. stateObject.Length -= bytes; //Append the data to our running compilation. stateObject.Data += EncodingToUse.GetString(_receiveBuffer, 0, bytes); EventAggregatorContext.Current.GetEvent <RecordDataTrafficEvent>().Publish(new DataTrafficSentReceivedViewModel(_receiveBuffer, false, bytes)); if (stateObject.Length > 0) { //We are still waiting for more of the response, so starting waiting.... _tcpClient.GetStream().BeginRead(_receiveBuffer, 0, _receiveBuffer.Length, DataReceived, stateObject); } else { //process the data we have received. ProcessReceivedData(stateObject); //Start waiting for the next response. _tcpClient.GetStream().BeginRead(_receiveBuffer, 0, _receiveBuffer.Length, DataReceived, null); } } } catch { Disconnect(); } }