/// <summary> /// Generate a string containing the ACK message in response to the original message. Supply a string containing the original message (or at least the MSH segment). /// </summary> /// <returns></returns> string GenerateACK(string originalMessage) { // create a HL7Message object using the original message as the source to obtain details to reflect back in the ACK message HL7Message tmpMsg = new HL7Message(originalMessage); string trigger = tmpMsg.GetHL7Item("MSH-9.2")[0]; string originatingApp = tmpMsg.GetHL7Item("MSH-3")[0]; string originatingSite = tmpMsg.GetHL7Item("MSH-4")[0]; string messageID = tmpMsg.GetHL7Item("MSH-10")[0]; string processingID = tmpMsg.GetHL7Item("MSH-11")[0]; string hl7Version = tmpMsg.GetHL7Item("MSH-12")[0]; string ackTimestamp = DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString(); StringBuilder ACKString = new StringBuilder(); ACKString.Append((char)0x0B); ACKString.Append("MSH|^~\\&|HL7Listener|HL7Listener|" + originatingSite + "|" + originatingApp + "|" + ackTimestamp + "||ACK^" + trigger + "|" + messageID + "|" + processingID + "|" + hl7Version); ACKString.Append((char)0x0D); ACKString.Append("MSA|CA|" + messageID); ACKString.Append((char)0x1C); ACKString.Append((char)0x0D); return(ACKString.ToString()); }
/// <summary> /// Receive data from a client connection, look for MLLP HL7 message. /// </summary> /// <param name="client"></param> private void ReceiveData(object client) { // generate a random sequence number to use for the file names Random random = new Random(Guid.NewGuid().GetHashCode()); int filenameSequenceStart = random.Next(0, 1000000); TcpClient tcpClient = (TcpClient)client; NetworkStream clientStream = tcpClient.GetStream(); clientStream.ReadTimeout = TCP_TIMEOUT; clientStream.WriteTimeout = TCP_TIMEOUT; byte[] messageBuffer = new byte[4096]; int bytesRead; String messageData = ""; int messageCount = 0; while (true) { bytesRead = 0; try { // Wait until a client application submits a message bytesRead = clientStream.Read(messageBuffer, 0, 4096); } catch (Exception e) { // A network error has occurred LogInformation("Connection from " + tcpClient.Client.RemoteEndPoint + " has ended"); break; } if (bytesRead == 0) { // The client has disconected LogInformation("The client " + tcpClient.Client.RemoteEndPoint + " has disconnected"); break; } // Message buffer received successfully messageData += Encoding.UTF8.GetString(messageBuffer, 0, bytesRead); // Find a VT character, this is the beginning of the MLLP frame int start = messageData.IndexOf((char)0x0B); if (start >= 0) { // Search for the end of the MLLP frame (a FS character) int end = messageData.IndexOf((char)0x1C); if (end > start) { messageCount++; try { // queue the message to sent to the passthru host if the -PassThru option has been set if (passthruHost != null) { messageQueue.Enqueue(messageData.Substring(start + 1, end - (start + 1))); } // create a HL7message object from the message recieved. Use this to access elements needed to populate the ACK message and file name of the archived message HL7Message message = new HL7Message(messageData.Substring(start + 1, end - (start + 1))); messageData = ""; // reset the message data string for the next message string messageTrigger = message.GetMessageTrigger(); string messageControlID = message.GetHL7Item("MSH-10")[0]; //string acceptAckType = message.GetHL7Item("MSH-15")[0]; string dateStamp = DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString().PadLeft(2, '0') + DateTime.Now.Day.ToString().PadLeft(2, '0') + DateTime.Now.Hour.ToString().PadLeft(2, '0') + DateTime.Now.Minute.ToString().PadLeft(2, '0'); string filename = dateStamp + "_" + (filenameSequenceStart + messageCount).ToString("D6") + "_" + messageTrigger + ".hl7"; // increment sequence number for each filename // Write the HL7 message to file. WriteMessagetoFile(message.ToString(), this.archivePath + filename); // send ACK message is MSH-15 is set to AL and ACKs not disbaled by -NOACK command line switch //if ((this.sendACK) && (acceptAckType.ToUpper() == "AL")) if (this.sendACK) { LogInformation("Sending ACK (Message Control ID: " + messageControlID + ")"); // generate ACK Message and send in response to the message received string response = GenerateACK(message.ToString()); // TO DO: send ACKS if set in message header, or specified on command line byte[] encodedResponse = Encoding.UTF8.GetBytes(response); // Send response try { clientStream.Write(encodedResponse, 0, encodedResponse.Length); clientStream.Flush(); } catch (Exception e) { // A network error has occurred LogInformation("An error has occurred while sending an ACK to the client " + tcpClient.Client.RemoteEndPoint); LogInformation(e.Message); break; } } } catch (Exception e) { messageData = ""; // reset the message data string for the next message LogWarning("An exception occurred while parsing the HL7 message"); LogWarning(e.Message); break; } } } } LogInformation("Total messages received:" + messageCount); clientStream.Close(); clientStream.Dispose(); tcpClient.Close(); }