private void EcwOldTimerCallbackSendFunction(Object stateInfo) { //does not happen for standalone if (_ecwOldIsSending) //if there is a thread that is still sending, return { return; } try { _ecwOldIsSending = true; if (IsVerboseLogging) { EventLog.WriteEntry("GetOnePending Start"); } List <HL7Msg> list = HL7Msgs.GetOnePending(); if (IsVerboseLogging) { EventLog.WriteEntry("GetOnePending Finished"); } string filename; for (int i = 0; i < list.Count; i++) //Right now, there will only be 0 or 1 item in the list. { if (list[i].AptNum == 0) { filename = ODFileUtils.CreateRandomFile(ecwOldHl7FolderIn, ".txt"); } else { filename = Path.Combine(ecwOldHl7FolderIn, list[i].AptNum.ToString() + ".txt"); } //EventLog.WriteEntry("Attempting to create file: "+filename); File.WriteAllText(filename, list[i].MsgText); list[i].HL7Status = HL7MessageStatus.OutSent; HL7Msgs.Update(list[i]); //set the status to sent. } if (_ecwOldDateTimeOldMsgsDeleted.Date < DateTime.Now.Date) { if (IsVerboseLogging) { EventLog.WriteEntry("DeleteOldMsgText Starting"); } _ecwOldDateTimeOldMsgsDeleted = DateTime.Now; HL7Msgs.DeleteOldMsgText(); //this function deletes if DateTStamp is less than CURDATE-INTERVAL 4 MONTH. That means it will delete message text only once a day, not time based. if (IsVerboseLogging) { EventLog.WriteEntry("DeleteOldMsgText Finished"); } } } catch (Exception ex) { EventLog.WriteEntry("OpenDentHL7 error when sending HL7 message: " + ex.Message, EventLogEntryType.Warning); //Warning because the service will spawn a new thread in 1.8 seconds } finally { _ecwOldIsSending = false; } }
private void TimerCallbackSendFiles(Object stateInfo) { List <HL7Msg> list = HL7Msgs.GetOnePending(); string filename; for (int i = 0; i < list.Count; i++) //Right now, there will only be 0 or 1 item in the list. { filename = ODFileUtils.CreateRandomFile(hl7FolderOut, ".txt"); File.WriteAllText(filename, list[i].MsgText); list[i].HL7Status = HL7MessageStatus.OutSent; HL7Msgs.Update(list[i]); //set the status to sent. HL7Msgs.DeleteOldMsgText(); //This is inside the loop so that it happens less frequently. To clean up incoming messages, we may move this someday. } }
private void TimerCallbackSendFunction(Object stateInfo) { //does not happen for standalone List <HL7Msg> list = HL7Msgs.GetOnePending(); string filename; for (int i = 0; i < list.Count; i++) { if (list[i].AptNum == 0) { filename = ODFileUtils.CreateRandomFile(hl7FolderIn, ".txt"); } else { filename = Path.Combine(hl7FolderIn, list[i].AptNum.ToString() + ".txt"); } //EventLog.WriteEntry("Attempting to create file: "+filename); File.WriteAllText(filename, list[i].MsgText); list[i].HL7Status = HL7MessageStatus.OutSent; HL7Msgs.Update(list[i]); //set the status to sent. } }
private void EcwOldTimerCallbackSendFunction(Object stateInfo) { //does not happen for standalone List <HL7Msg> list = HL7Msgs.GetOnePending(); string filename; for (int i = 0; i < list.Count; i++) //Right now, there will only be 0 or 1 item in the list. { if (list[i].AptNum == 0) { filename = ODFileUtils.CreateRandomFile(ecwOldHl7FolderIn, ".txt"); } else { filename = Path.Combine(ecwOldHl7FolderIn, list[i].AptNum.ToString() + ".txt"); } //EventLog.WriteEntry("Attempting to create file: "+filename); File.WriteAllText(filename, list[i].MsgText); list[i].HL7Status = HL7MessageStatus.OutSent; HL7Msgs.Update(list[i]); //set the status to sent. HL7Msgs.DeleteOldMsgText(); //This is inside the loop so that it happens less frequently. To clean up incoming messages, we may move this someday. } }
private void TimerCallbackSendTCP(Object stateInfo) { List <HL7Msg> list = HL7Msgs.GetOnePending(); for (int i = 0; i < list.Count; i++) //Right now, there will only be 0 or 1 item in the list. { string sendMsgControlId = HL7Msgs.GetControlId(list[i]); //could be empty string Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); string[] strIpPort = HL7DefEnabled.OutgoingIpPort.Split(':'); //this was already validated in the HL7DefEdit window. IPAddress ipaddress = IPAddress.Parse(strIpPort[0]); //already validated int port = int.Parse(strIpPort[1]); //already validated IPEndPoint endpoint = new IPEndPoint(ipaddress, port); try { socket.Connect(endpoint); if (!IsSendTCPConnected) //Previous run failed to connect. This time connected so make log entry that connection was successful { EventLog.WriteEntry("OpenDentHL7", "The HL7 send TCP/IP socket connection failed to connect previously and was successful this time.", EventLogEntryType.Information); IsSendTCPConnected = true; } } catch (SocketException ex) { if (IsSendTCPConnected) //Previous run connected fine, make log entry and set bool to false { EventLog.WriteEntry("OpenDentHL7", "The HL7 send TCP/IP socket connection failed to connect.\r\nException: " + ex.Message, EventLogEntryType.Warning); IsSendTCPConnected = false; } return; } string data = MLLP_START_CHAR + list[i].MsgText + MLLP_END_CHAR + MLLP_ENDMSG_CHAR; try { byte[] byteData = Encoding.ASCII.GetBytes(data); socket.Send(byteData); //this is a blocking call //For MLLP V2, do a blocking Receive here, along with a timeout. byte[] ackBuffer = new byte[256]; //plenty big enough to receive the entire ack/nack response socket.ReceiveTimeout = 5000; //5 second timeout. Database is polled every 6 seconds for a new message to send, 5 second wait for acknowledgment int byteCountReceived = socket.Receive(ackBuffer); //blocking Receive char[] chars = new char[byteCountReceived]; Encoding.UTF8.GetDecoder().GetChars(ackBuffer, 0, byteCountReceived, chars, 0); StringBuilder strbAckMsg = new StringBuilder(); strbAckMsg.Append(chars); if (strbAckMsg.Length > 0 && strbAckMsg[0] != MLLP_START_CHAR) { list[i].Note = list[i].Note + "Malformed acknowledgment.\r\n"; HL7Msgs.Update(list[i]); throw new Exception("Malformed acknowledgment."); } else if (strbAckMsg.Length >= 3 && strbAckMsg[strbAckMsg.Length - 1] == MLLP_ENDMSG_CHAR && //last char is the endmsg char. strbAckMsg[strbAckMsg.Length - 2] == MLLP_END_CHAR) //the second-to-the-last char is the end char. { //we have a complete message strbAckMsg.Remove(0, 1); //strip off the start char strbAckMsg.Remove(strbAckMsg.Length - 2, 2); //strip off the end chars } else if (strbAckMsg.Length >= 2 && //so that the next line won't crash strbAckMsg[strbAckMsg.Length - 1] == MLLP_END_CHAR) //the last char is the end char. { //we will treat this as a complete message, because the endmsg char is optional. strbAckMsg.Remove(0, 1); //strip off the start char strbAckMsg.Remove(strbFullMsg.Length - 1, 1); //strip off the end char } else { list[i].Note = list[i].Note + "Malformed acknowledgment.\r\n"; HL7Msgs.Update(list[i]); throw new Exception("Malformed acknowledgment."); } MessageHL7 ackMsg = new MessageHL7(strbAckMsg.ToString()); try { MessageParser.ProcessAck(ackMsg, IsVerboseLogging); } catch (Exception ex) { list[i].Note = list[i].Note + ackMsg.ToString() + "\r\nError processing acknowledgment.\r\n"; HL7Msgs.Update(list[i]); throw new Exception("Error processing acknowledgment.\r\n" + ex.Message); } if (ackMsg.AckCode == "" || ackMsg.ControlId == "") { list[i].Note = list[i].Note + ackMsg.ToString() + "\r\nInvalid ACK message. Attempt to resend.\r\n"; HL7Msgs.Update(list[i]); throw new Exception("Invalid ACK message received."); } if (ackMsg.ControlId == sendMsgControlId && ackMsg.AckCode == "AA") //acknowledged received (Application acknowledgment: Accept) { list[i].Note = list[i].Note + ackMsg.ToString() + "\r\nMessage ACK (acknowledgment) received.\r\n"; } else if (ackMsg.ControlId == sendMsgControlId && ackMsg.AckCode != "AA") //ACK received for this message, but ack code was not acknowledgment accepted { if (list[i].Note.Contains("NACK4")) //this is the 5th negative acknowledgment, don't try again { list[i].Note = list[i].Note + "Ack code: " + ackMsg.AckCode + "\r\nThis is NACK5, the message status has been changed to OutFailed. We will not attempt to send again.\r\n"; list[i].HL7Status = HL7MessageStatus.OutFailed; } else if (list[i].Note.Contains("NACK")) //failed sending at least once already { list[i].Note = list[i].Note + "Ack code: " + ackMsg.AckCode + "\r\nNACK" + list[i].Note.Split(new string[] { "NACK" }, StringSplitOptions.None).Length + "\r\n"; } else { list[i].Note = list[i].Note + "Ack code: " + ackMsg.AckCode + "\r\nMessage NACK (negative acknowlegment) received. We will try to send again.\r\n"; } HL7Msgs.Update(list[i]); //Add NACK note to hl7msg table entry return; //socket closed in finally } else //ack received for control ID that does not match the control ID of message just sent { list[i].Note = list[i].Note + "Sent message control ID: " + sendMsgControlId + "\r\nAck message control ID: " + ackMsg.ControlId + "\r\nAck received for message other than message just sent. We will try to send again.\r\n"; HL7Msgs.Update(list[i]); return; } } catch (SocketException ex) { EventLog.WriteEntry("OpenDentHL7", "The HL7 send TCP/IP socket encountered an error when sending message or receiving acknowledgment.\r\nSocket Exception: " + ex.Message, EventLogEntryType.Warning); return; //Try again in 3 seconds. socket closed in finally } catch (Exception ex) { EventLog.WriteEntry("OpenDentHL7", "The HL7 send TCP/IP encountered an error when sending message or receiving acknowledgment.\r\nException: " + ex.Message, EventLogEntryType.Warning); return; //socket closed in finally } finally { if (socket != null) { socket.Shutdown(SocketShutdown.Both); socket.Close(); } } list[i].HL7Status = HL7MessageStatus.OutSent; HL7Msgs.Update(list[i]); //set the status to sent and save ack message in Note field. HL7Msgs.DeleteOldMsgText(); //This is inside the loop so that it happens less frequently. To clean up incoming messages, we may move this someday. } }