update
This commit is contained in:
+119
-61
@@ -227,6 +227,13 @@ def parse_hl7_result(hl7_message, device_name="GeneXpert"):
|
|||||||
try:
|
try:
|
||||||
# 1. Bersihkan dan Split Pesan
|
# 1. Bersihkan dan Split Pesan
|
||||||
# HL7 dipisahkan oleh \r (Carriage Return)
|
# HL7 dipisahkan oleh \r (Carriage Return)
|
||||||
|
if "MSH|" not in hl7_message:
|
||||||
|
logging.warning("[HL7] Data tidak mengandung segmen MSH valid.")
|
||||||
|
print("[HL7] Data tidak mengandung segmen MSH valid.")
|
||||||
|
return
|
||||||
|
start_idx = hl7_message.find("MSH|")
|
||||||
|
hl7_message = hl7_message[start_idx:]
|
||||||
|
|
||||||
segments = hl7_message.strip().split('\r')
|
segments = hl7_message.strip().split('\r')
|
||||||
|
|
||||||
# Variabel penampung
|
# Variabel penampung
|
||||||
@@ -294,23 +301,28 @@ def parse_hl7_result(hl7_message, device_name="GeneXpert"):
|
|||||||
else:
|
else:
|
||||||
final_result = "; ".join(results_list)
|
final_result = "; ".join(results_list)
|
||||||
|
|
||||||
# 4. Validasi Data Penting
|
# 4. Validasi Data Penting (DIMODIFIKASI)
|
||||||
if not sample_id:
|
if not sample_id:
|
||||||
logging.warning("[HL7 Parser] Sample ID tidak ditemukan. Data tidak disimpan.")
|
# JANGAN RETURN, tapi buat ID palsu agar tetap bisa masuk database
|
||||||
print("[HL7 Parser] Sample ID tidak ditemukan. Data tidak disimpan.")
|
timestamp_err = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
|
||||||
return
|
sample_id = f"ERR_{timestamp_err}"
|
||||||
|
logging.warning(f"[HL7 Parser] Sample ID kosong. Disimpan sebagai {sample_id} untuk audit.")
|
||||||
|
print(f"[HL7 Parser] Sample ID kosong. Disimpan sebagai {sample_id} untuk audit.")
|
||||||
|
# Tambahkan penanda di hasil agar Anda tahu ini error
|
||||||
|
final_result = f"[PARSE FAIL] {final_result}"
|
||||||
|
|
||||||
logging.info(f"[HL7 Parser] Menyimpan hasil untuk Sample: {sample_id} - {patient_name}")
|
logging.info(f"[HL7 Parser] Menyimpan hasil untuk Sample: {sample_id}")
|
||||||
print(f"[HL7 Parser] Menyimpan hasil untuk Sample: {sample_id} - {patient_name}")
|
print(f"[HL7 Parser] Menyimpan hasil untuk Sample: {sample_id}")
|
||||||
# 5. Simpan ke Database (Tabel LisPhoenix)
|
|
||||||
|
# 5. Simpan ke Database
|
||||||
new_data = LisPhoenix(
|
new_data = LisPhoenix(
|
||||||
no_id=sample_id, # OBR-3
|
no_id=sample_id,
|
||||||
seq_no=patient_id, # PID-3
|
seq_no=patient_id,
|
||||||
rnmpas=patient_name, # PID-5
|
rnmpas=patient_name,
|
||||||
tgl_data=result_date, # MSH-7
|
tgl_data=result_date,
|
||||||
rawdt=hl7_message, # Pesan Asli
|
rawdt=hl7_message,
|
||||||
organisme=final_result, # Gabungan OBX-5
|
organisme=final_result,
|
||||||
alat=device_name # Parameter fungsi
|
alat=device_name
|
||||||
)
|
)
|
||||||
|
|
||||||
session.add(new_data)
|
session.add(new_data)
|
||||||
@@ -407,61 +419,107 @@ def send_mllp_message(sock, hl7_msg):
|
|||||||
sock.sendall(mllp_msg)
|
sock.sendall(mllp_msg)
|
||||||
|
|
||||||
def handle_genexpert_client(conn, addr):
|
def handle_genexpert_client(conn, addr):
|
||||||
ip_sender = addr[0]
|
print(f"[TCP] Koneksi baru dari {addr}")
|
||||||
logging.info(f"[CONNECT] GeneXpert terkoneksi dari IP: {ip_sender}")
|
|
||||||
print(f"[CONNECT] GeneXpert terkoneksi dari IP: {ip_sender}")
|
|
||||||
with connection_lock:
|
|
||||||
active_genexpert_connections[ip_sender] = conn
|
|
||||||
|
|
||||||
buffer = b""
|
buffer = b""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
data = conn.recv(4096)
|
try:
|
||||||
if not data:
|
data = conn.recv(4096)
|
||||||
break
|
if not data:
|
||||||
|
|
||||||
buffer += data
|
|
||||||
|
|
||||||
# Cek apakah paket MLLP lengkap (diawali \x0b dan diakhiri \x1c\r)
|
|
||||||
# Logic sederhana: cari penutup \x1c\r
|
|
||||||
while b'\x1c\r' in buffer:
|
|
||||||
# Ekstrak pesan
|
|
||||||
start_marker = buffer.find(b'\x0b')
|
|
||||||
end_marker = buffer.find(b'\x1c\r')
|
|
||||||
|
|
||||||
if start_marker != -1 and end_marker != -1:
|
|
||||||
raw_msg = buffer[start_marker+1 : end_marker]
|
|
||||||
hl7_str = raw_msg.decode('utf-8')
|
|
||||||
|
|
||||||
logging.info(f"[RECV] Dari {ip_sender}: {hl7_str[:50]}...") # Log 50 karakter awal
|
|
||||||
print(f"[RECV] Dari {ip_sender}: {hl7_str[:50]}...") # Print 50 karakter awal
|
|
||||||
# Cek Tipe Pesan (MSH field 9)
|
|
||||||
if "ORU^R01" in hl7_str:
|
|
||||||
# Ini adalah Hasil
|
|
||||||
hasil = parse_hl7_result(hl7_str, device_name=addr[0] if addr else "GeneXpert")
|
|
||||||
logging.info(f"[RESULT] {hasil}")
|
|
||||||
print(f"[RESULT] {hasil}")
|
|
||||||
# TODO: Simpan 'hasil' ke database berdasarkan Sample ID di HL7
|
|
||||||
|
|
||||||
# Kirim ACK (Terima Kasih) ke Alat
|
|
||||||
# ACK dinamis
|
|
||||||
msg_control_id = hl7_str.split('|')[9] # Ambil ID pesan asli
|
|
||||||
ack_msg = f"MSH|^~\\&|LIS|LAB|GeneXpert|Cepheid|{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}||ACK|{msg_control_id}|P|2.3\rMSA|AA|{msg_control_id}\r"
|
|
||||||
send_mllp_message(conn, ack_msg)
|
|
||||||
|
|
||||||
# Hapus pesan yang sudah diproses dari buffer
|
|
||||||
buffer = buffer[end_marker+2:]
|
|
||||||
else:
|
|
||||||
break
|
break
|
||||||
|
|
||||||
|
buffer += data
|
||||||
|
|
||||||
|
# --- 1. HANDLE HANDSHAKE (ENQ) ---
|
||||||
|
# Jika alat kirim ENQ (\x05/♣), langsung balas ACK (\x06)
|
||||||
|
if b'\x05' in buffer:
|
||||||
|
# logging.info(f"[TCP] Terima ENQ dari {addr}, kirim ACK.")
|
||||||
|
conn.sendall(b'\x06')
|
||||||
|
# Hapus ENQ dari buffer agar tidak mengganggu
|
||||||
|
buffer = buffer.replace(b'\x05', b'')
|
||||||
|
|
||||||
|
# --- 2. CEK APAKAH PESAN SUDAH LENGKAP? ---
|
||||||
|
# Kita cari tanda akhir pesan umum:
|
||||||
|
# - \x1c (End Block MLLP)
|
||||||
|
# - \x03 (ETX - End Text ASTM)
|
||||||
|
# - \x04 (EOT - End Transmission ASTM)
|
||||||
|
|
||||||
|
msg_complete = False
|
||||||
|
end_marker_pos = -1
|
||||||
|
|
||||||
|
if b'\x1c' in buffer: # Pola MLLP Standard
|
||||||
|
end_marker_pos = buffer.find(b'\x1c')
|
||||||
|
msg_complete = True
|
||||||
|
elif b'\x03' in buffer: # Pola ASTM (Ada Checksum setelahnya)
|
||||||
|
# ASTM: <STX>...<ETX>CS<CR><LF>
|
||||||
|
# Kita cari \x03, lalu tambah 4 byte (CS + CRLF) untuk aman
|
||||||
|
pos = buffer.find(b'\x03')
|
||||||
|
if len(buffer) >= pos + 4:
|
||||||
|
end_marker_pos = pos + 4
|
||||||
|
msg_complete = True
|
||||||
|
elif b'\x04' in buffer: # Pola EOT (Putus Koneksi/Selesai)
|
||||||
|
end_marker_pos = buffer.find(b'\x04')
|
||||||
|
msg_complete = True
|
||||||
|
|
||||||
|
# --- 3. PROSES JIKA LENGKAP ---
|
||||||
|
if msg_complete:
|
||||||
|
# Ambil pesan dari awal sampai marker
|
||||||
|
# (Gunakan slice sampai end_marker_pos+1 agar karakter penutup ikut terambil/dibuang)
|
||||||
|
if end_marker_pos == -1: end_marker_pos = len(buffer)
|
||||||
|
|
||||||
|
full_message_bytes = buffer[:end_marker_pos]
|
||||||
|
|
||||||
|
# Sisa buffer (jika ada paket nempel di belakangnya) disimpan untuk loop berikutnya
|
||||||
|
buffer = buffer[end_marker_pos:]
|
||||||
|
|
||||||
|
# Bersihkan buffer dari sisa marker di awal (jika loop sebelumnya menyisakan sampah)
|
||||||
|
buffer = buffer.lstrip(b'\x04').lstrip(b'\r').lstrip(b'\n')
|
||||||
|
|
||||||
|
# Decode ke string
|
||||||
|
temp_str = full_message_bytes.decode('latin-1', errors='ignore')
|
||||||
|
|
||||||
|
# --- SANITIZING (PEMBERSIHAN) ---
|
||||||
|
# Cari MSH pertama
|
||||||
|
if "MSH|" in temp_str:
|
||||||
|
msh_index = temp_str.find("MSH|")
|
||||||
|
clean_hl7 = temp_str[msh_index:]
|
||||||
|
|
||||||
|
# Logging sample data (50 karakter)
|
||||||
|
print(f"[TCP] Pesan Lengkap Diterima: {clean_hl7[:50]}...")
|
||||||
|
|
||||||
|
# Panggil Parser
|
||||||
|
parse_hl7_result(clean_hl7, device_name=f"GeneXpert-{addr[0]}")
|
||||||
|
|
||||||
|
# --- KIRIM ACK ---
|
||||||
|
try:
|
||||||
|
lines = clean_hl7.split('\r')
|
||||||
|
msh_fields = lines[0].split('|')
|
||||||
|
if len(msh_fields) > 9:
|
||||||
|
msg_control_id = msh_fields[9]
|
||||||
|
ack_time = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
|
||||||
|
ack_msg = f"MSH|^~\\&|LIS|LAB|GeneXpert|Cepheid|{ack_time}||ACK|{msg_control_id}|P|2.5\rMSA|AA|{msg_control_id}\r"
|
||||||
|
|
||||||
|
# Kirim ACK format MLLP
|
||||||
|
full_ack = f"\x0b{ack_msg}\x1c\r"
|
||||||
|
conn.sendall(full_ack.encode('utf-8'))
|
||||||
|
print(f"[ACK] Terkirim untuk ID {msg_control_id}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Gagal kirim ACK: {e}")
|
||||||
|
else:
|
||||||
|
# Jika pesan lengkap tapi tidak ada MSH (misal cuma EOT doang)
|
||||||
|
pass
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[Loop Error] {e}")
|
||||||
|
# Jangan break, lanjut terima data
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"[ERROR] Koneksi {ip_sender} terputus: {e}")
|
logging.error(f"[TCP Error] Koneksi {addr} terputus: {e}")
|
||||||
finally:
|
finally:
|
||||||
with connection_lock:
|
|
||||||
if ip_sender in active_genexpert_connections:
|
|
||||||
del active_genexpert_connections[ip_sender]
|
|
||||||
conn.close()
|
conn.close()
|
||||||
logging.info(f"[DISCONNECT] Koneksi dengan {ip_sender} ditutup.")
|
logging.info(f"[TCP] Koneksi {addr} ditutup.")
|
||||||
|
|
||||||
def run_tcp_server():
|
def run_tcp_server():
|
||||||
"""Loop utama TCP Server"""
|
"""Loop utama TCP Server"""
|
||||||
|
|||||||
Reference in New Issue
Block a user