public string GetAckMessage(HL7Connection Connection, string controlId) { Throw.IfNull(Connection); var response = new Message(); var msh = new Segment("MSH"); msh.Field(2, "^~\\&"); msh.Field(7, DateTime.Now.ToString("yyyyMMddhhmmssfff")); msh.Field(9, Connection.ack); // "ACK"); msh.Field(10, Guid.NewGuid().ToString()); msh.Field(11, "P"); msh.Field(12, "2.5.1"); response.Add(msh); var msa = new Segment("MSA"); msa.Field(1, "AA"); msa.Field(2, controlId); // msg.MessageControlId()); response.Add(msa); // Put response message into an MLLP frame ( <VT> data <FS><CR> ) // var frame = new StringBuilder(); frame.Append((char)0x0B); frame.Append(response.Serialize()); frame.Append((char)0x0D); frame.Append((char)0x1C); frame.Append((char)0x0D); return(frame.ToString()); }
public async Task Accept(HL7Connection connection, BourneListens bourne, List <TcpClient> clients, Func <TcpClient, int, Task> func, int taskID) { Connection = connection; _logger.Log(LogLevel.Debug, $"{Connection.name} Entering accept on {bourne.LocalEndpoint}"); string local = string.Empty; try { while (!_taskManager.cts.IsCancellationRequested) { if (!bourne.Active()) { break; } local = await ProcessItem(bourne, clients, func, taskID); } } catch (TaskCanceledException) { _logger.Log(LogLevel.Information, $"Task was canceled."); } catch (SocketException e) { _logger.Log(LogLevel.Warning, $"{local} SocketException: {e.ErrorCode} {e.Message} {e.StackTrace}"); if (e.InnerException != null) { _logger.Log(LogLevel.Warning, $"Inner Exception: {e.InnerException}"); } } catch (ObjectDisposedException e) { _logger.Log(LogLevel.Warning, $"{local} HL7 Connection is closed."); if (e.InnerException != null) { _logger.Log(LogLevel.Warning, $"Inner Exception: {e.InnerException}"); } } catch (System.InvalidOperationException e) { _logger.Log(LogLevel.Warning, $"{local} InvalidOperationException: {e.Message} {e.StackTrace}"); if (e.InnerException != null) { _logger.Log(LogLevel.Warning, $"Inner Exception: {e.InnerException}"); } } catch (Exception e) { _logger.LogFullException(e, local); } finally { _taskManager.Stop($"{Connection.name}.accept: {bourne.LocalEndpoint}"); } _logger.Log(LogLevel.Warning, $"Cancellation received. Exiting accept."); }
public MedicationTO refillPrescription(string pwd, string sitecode, string mpiPid, string rxId) { MedicationTO result = new MedicationTO(); if (String.IsNullOrEmpty(pwd)) { result.fault = new FaultTO("Missing pwd"); } else if (String.IsNullOrEmpty(sitecode)) { result.fault = new FaultTO("Missing site ID"); } else if (String.IsNullOrEmpty(mpiPid)) { result.fault = new FaultTO("Missing patient ID"); } else if (String.IsNullOrEmpty(rxId)) { result.fault = new FaultTO("Missing Rx ID"); } if (result.fault != null) { return(result); } try { Site hl7Site = mySession.SiteTable.getSite(sitecode); DataSource hl7Src = null; foreach (DataSource src in hl7Site.Sources) { if (String.Equals(src.Protocol, "HL7", StringComparison.CurrentCultureIgnoreCase)) { hl7Src = src; break; } } if (hl7Src == null) { throw new gov.va.medora.mdo.exceptions.MdoException("No HL7 data source in site table for that site ID"); } HL7Connection cxn = new HL7Connection(hl7Src); cxn.connect(); cxn.Pid = mpiPid; result = new MedicationTO(new MedsApi().refillPrescription(cxn, rxId)); } catch (Exception exc) { result.fault = new FaultTO(exc); } return(result); }
public void Clean(HL7Connection Connection, List <TcpClient> clients) { foreach (var client in clients.ToArray()) { if (!client.Connected) { _logger.Log(LogLevel.Debug, $"{Connection.name} Disconnected"); client.Dispose(); clients.Remove(client); } else { _logger.Log(LogLevel.Debug, $"{Connection.name} Connected: {client.Client.RemoteEndPoint}"); } } }
public async Task Start(HL7Connection Connection, List <BourneListens> listeners, ObservableCollection <BourneListens> deadListeners, List <TcpClient> clients, Func <TcpClient, int, Task> Read) { try { await StartImpl(Connection, listeners, deadListeners, clients, Read); } catch (TaskCanceledException) { _logger.Log(LogLevel.Information, $"Task was canceled."); } catch (SocketException e) { _logger.Log(LogLevel.Warning, $"{e.Message} {e.StackTrace}"); } catch (ObjectDisposedException e) { _logger.LogFullException(e); } catch (Exception e) { _logger.LogFullException(e); } }
public override AbstractConnection getConnection(DataSource dataSource) { HL7Connection cxn = new HL7Connection(dataSource); return(cxn); }
public async Task SendToHL7(int taskID, HL7Connection connection) { Connection = connection; var taskInfo = $"task: {taskID} connection: {Connection.name}"; TcpClient tcpclnt = new TcpClient(Connection.remoteHostname, Connection.remotePort); _logger.Log(LogLevel.Debug, $"HL7 tcpclient connection {Connection.name} opened - task = {Task.CurrentId} connected = {tcpclnt.Connected}"); Stream stm = null; SslStream sslStream = null; try { switch (Connection.useTLS) { case true: { sslStream = new SslStream(tcpclnt.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); sslStream.AuthenticateAsClient(Connection.remoteHostname); break; } default: { stm = tcpclnt.GetStream(); break; } } var temp = Connection.ToHL7.ToArray(); foreach (var routedItem in temp) { try { await ProcessItem(routedItem, sslStream, stm, taskInfo); } catch (Exception e) { _logger.LogFullException(e, taskInfo); } } await Task.Delay(5000).ConfigureAwait(false); //give the socket enough time to clear. tcpclnt.Close(); _logger.Log(LogLevel.Debug, "Regular HL7 tcpclient connection {name} closed - task = {Task.CurrentId} completed = {Task.CompletedTask}"); foreach (var hl7 in temp) { _routedItemManager.Init(hl7); _routedItemManager.Dequeue(Connection, Connection.ToHL7, nameof(Connection.ToHL7), error: false); } } catch (Exception e) { _logger.LogFullException(e); } finally { switch (Connection.useTLS) { case true: sslStream.Close(); break; default: stm.Close(); break; } tcpclnt.Close(); _logger.Log(LogLevel.Debug, "Final HL7 tcpclient connection {name} closed - task = {Task.CurrentId} completed = {Task.CompletedTask}"); } }
private async Task StartImpl(HL7Connection Connection, List <BourneListens> listeners, ObservableCollection <BourneListens> deadListeners, List <TcpClient> clients, Func <TcpClient, int, Task> Read) { RemoveDeadListeners(listeners, deadListeners); //frequent DNS lookup required for Cloud and HA environments where a lower TTL results in faster failover. //For a listener this means a container might have been moved to another server with different IP. var hostEntry = Dns.GetHostEntry(Connection.localHostname); foreach (var ip in hostEntry.AddressList) { _logger.Log(LogLevel.Information, $"{Connection.name} hostEntry: {Connection.localHostname} ip: {ip}"); BourneListens bourne = null; if (ip.AddressFamily == AddressFamily.InterNetworkV6 && Connection.UseIPV6) { if (!listeners.Exists(x => x.localaddr.Equals(ip) && x.port.Equals(Connection.localPort))) { bourne = new BourneListens(ip, Connection.localPort); listeners.Add(bourne); //you can verify Start worked on mac by doing lsof -n -i:2575 | grep LISTEN, where 2575 is HL7 or whatever port you want. bourne.Start(); _logger.Log(LogLevel.Information, $"{Connection.name} is listening on {bourne.LocalEndpoint}"); _logger.Log(LogLevel.Information, $"{Connection.name} Verify with Mac/Linux:lsof -n -i:{Connection.localPort} | grep LISTEN and with echo \"Hello world\" | nc {Connection.localHostname} {Connection.localPort}"); _logger.Log(LogLevel.Information, $"{Connection.name} Verify with Windows:netstat -abno (requires elevated privileges)"); } } if ((ip.AddressFamily == AddressFamily.InterNetwork && Connection.UseIPV4 && !RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) || (ip.AddressFamily == AddressFamily.InterNetwork && Connection.UseIPV4 && !Connection.UseIPV6 && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))) { if (!listeners.Exists(x => x.localaddr.Equals(ip) && x.port.Equals(Connection.localPort))) { bourne = new BourneListens(ip, Connection.localPort); listeners.Add(bourne); //you can verify Start worked on mac by doing lsof -n -i:2575 | grep LISTEN, where 2575 is HL7 or whatever port you want. bourne.Start(); _logger.Log(LogLevel.Information, $"{Connection.name} is listening on {bourne.LocalEndpoint}"); _logger.Log(LogLevel.Information, $"{Connection.name} Verify with Mac/Linux:lsof -n -i:{Connection.localPort} | grep LISTEN and with echo \"Hello world\" | nc {Connection.localHostname} {Connection.localPort}"); _logger.Log(LogLevel.Information, $"{Connection.name} Verify with Windows:netstat -abno (requires elevated privileges)"); } } } foreach (var listener in listeners) { if (listener != null && listener.LocalEndpoint != null) { if (_taskManager.CanStart($"{Connection.name}.accept: {listener.LocalEndpoint}")) { var newTaskID = _taskManager.NewTaskID(); Task task = new Task(new Action(async() => await _hl7AcceptService.Accept(Connection, listener, clients, Read, newTaskID)), _taskManager.cts.Token); await _taskManager.Start(newTaskID, task, $"{Connection.name}.accept: {listener.LocalEndpoint}", $"{Connection.name}.accept: {listener.LocalEndpoint}", isLongRunning : true); await Task.Delay(1000); } } else { _logger.Log(LogLevel.Information, $"listener is disposed but still in list. Ignoring"); } } }
public async Task Read(TcpClient client, int taskID, HL7Connection connection) { Connection = connection; Stopwatch idle = new Stopwatch(); var taskInfo = $"task: {taskID} connection: {Connection.name} {client?.Client?.RemoteEndPoint}"; Stream stream = null; try { NetworkStream networkStream = client.GetStream(); if (Connection.useTLS) { SslStream ssls = new SslStream(networkStream, false); ssls.AuthenticateAsServer(_x509CertificateService.GetServerCertificate(Connection.name), false, SslProtocols.Tls12, true); stream = ssls; } else { stream = networkStream; } if (client.Connected) { //read the stream if avail, acknowledge, throw into hl7 receive array for other async processing do { byte[] buffer = new byte[client.ReceiveBufferSize]; if (stream.CanRead) { var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, _taskManager.cts.Token); if (bytesRead > 0) { idle.Stop(); string controlId = ""; byte[] tmp = new byte[bytesRead]; Array.Copy(buffer, tmp, bytesRead); var dir = _profileStorage.Current.tempPath + Path.DirectorySeparatorChar + Connection.name + Path.DirectorySeparatorChar + Constants.Dirs.ToRules; Directory.CreateDirectory(dir); var filename = dir + Path.DirectorySeparatorChar + Connection.name + "_" + DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss.ffff") + ".hl7"; await File.WriteAllBytesAsync(filename, buffer); RoutedItem routedItem = new RoutedItem(Connection.name, filename, taskID) { type = RoutedItem.Type.HL7 }; string msg = Encoding.Default.GetString(tmp); if (msg.StartsWith('\v')) { msg = msg.Substring(1); } if (msg.Length >= 4 && msg.StartsWith("MSH")) { List <KeyValuePair <string, List <string> > > segments = new List <KeyValuePair <string, List <string> > >(); List <string> temp = null; if (msg.Contains("\r\n")) { temp = msg.Split("\r\n").ToList(); } else if (msg.Contains("\n")) { temp = msg.Split("\n").ToList(); } else if (msg.Contains("\r")) { temp = msg.Split("\r").ToList(); } else { _logger.Log(LogLevel.Error, $"Unknown segment delimiter"); } foreach (var segment in temp) { if (segment.Length >= 4) { segments.Add(new KeyValuePair <string, List <string> >(segment.Substring(0, 3), segment.Split((char)msg[3]).ToList())); } } routedItem.hl7 = segments; //string[] fields = msg.Split((char)tmp[4]); var msh = segments.Find(e => e.Key == "MSH"); if (msh.Value.Count >= 10) { controlId = msh.Value[9]; } //determine the patientID and accession number and populate the ID field try { var pid = segments.Find(e => e.Key == "PID"); if (pid.Value[3].IndexOf("^") > 0) { routedItem.PatientID = pid.Value[3].Substring(0, pid.Value[3].IndexOf("^")); } else { routedItem.PatientID = pid.Value[3]; } } catch (Exception e) { _logger.Log(LogLevel.Critical, $"{taskInfo} Error Parsing PID: {e.Message} {e.StackTrace}"); } try { var obr = segments.Find(e => e.Key == "OBR"); if (obr.Value[3].IndexOf("^") > 0) { routedItem.AccessionNumber = obr.Value[3].Substring(0, obr.Value[3].IndexOf("^")); } else { routedItem.AccessionNumber = obr.Value[3]; } } catch (Exception e) { _logger.Log(LogLevel.Critical, $"{taskInfo} Error Parsing OBR: {e.Message} {e.StackTrace}"); } routedItem.id = $"PID:{routedItem.PatientID}, AN:{routedItem.AccessionNumber}"; //, UID:{routedItem.Study}"; } _routedItemManager.Init(routedItem); _routedItemManager.Enqueue(Connection, Connection.toRules, nameof(Connection.toRules)); _logger.Log(LogLevel.Debug, $"{taskInfo} {msg}"); byte[] serverResponseBytes = null; switch (Connection.ackMode) { case AckMode.Original: { //process message and return response bytes break; } case AckMode.Enhanced: { //process message and return response bytes break; } case AckMode.Custom: { serverResponseBytes = Encoding.UTF8.GetBytes(GetAckMessage(controlId)); break; } } if (serverResponseBytes != null) { await stream.WriteAsync(serverResponseBytes, 0, serverResponseBytes.Length); _logger.Log(LogLevel.Debug, $"{taskInfo} {Encoding.Default.GetString(serverResponseBytes)}"); } else { _logger.Log(LogLevel.Debug, $"{taskInfo} serverResponseBytes is null. Please verify ackMode and ack values."); } } //await stream.FlushAsync(); } else { break; } } while (networkStream.DataAvailable); // await Task.Delay(10000); //if no data avail then sleep on socke } } catch (TaskCanceledException) { _logger.Log(LogLevel.Information, $"{taskInfo} Task was canceled."); } catch (Exception e) { _logger.LogFullException(e, taskInfo); } finally { if (stream != null) { stream.Close(); } if (client != null) { client.Close(); _logger.Log(LogLevel.Debug, "Inbound HL7 tcpclient connection {name} closed - task = {Task.CurrentId} completed = {Task.CompletedTask}"); } // note: do not call this logic inside method. It should be outside //Clean(); // cleanup the connection, remove from list //LITETask.Stop($"{Connection.name}.read"); } }