update
This commit is contained in:
+119
-61
@@ -227,6 +227,13 @@ def parse_hl7_result(hl7_message, device_name="GeneXpert"):
|
||||
try:
|
||||
# 1. Bersihkan dan Split Pesan
|
||||
# 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')
|
||||
|
||||
# Variabel penampung
|
||||
@@ -294,23 +301,28 @@ def parse_hl7_result(hl7_message, device_name="GeneXpert"):
|
||||
else:
|
||||
final_result = "; ".join(results_list)
|
||||
|
||||
# 4. Validasi Data Penting
|
||||
# 4. Validasi Data Penting (DIMODIFIKASI)
|
||||
if not sample_id:
|
||||
logging.warning("[HL7 Parser] Sample ID tidak ditemukan. Data tidak disimpan.")
|
||||
print("[HL7 Parser] Sample ID tidak ditemukan. Data tidak disimpan.")
|
||||
return
|
||||
# JANGAN RETURN, tapi buat ID palsu agar tetap bisa masuk database
|
||||
timestamp_err = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
|
||||
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}")
|
||||
print(f"[HL7 Parser] Menyimpan hasil untuk Sample: {sample_id} - {patient_name}")
|
||||
# 5. Simpan ke Database (Tabel LisPhoenix)
|
||||
logging.info(f"[HL7 Parser] Menyimpan hasil untuk Sample: {sample_id}")
|
||||
print(f"[HL7 Parser] Menyimpan hasil untuk Sample: {sample_id}")
|
||||
|
||||
# 5. Simpan ke Database
|
||||
new_data = LisPhoenix(
|
||||
no_id=sample_id, # OBR-3
|
||||
seq_no=patient_id, # PID-3
|
||||
rnmpas=patient_name, # PID-5
|
||||
tgl_data=result_date, # MSH-7
|
||||
rawdt=hl7_message, # Pesan Asli
|
||||
organisme=final_result, # Gabungan OBX-5
|
||||
alat=device_name # Parameter fungsi
|
||||
no_id=sample_id,
|
||||
seq_no=patient_id,
|
||||
rnmpas=patient_name,
|
||||
tgl_data=result_date,
|
||||
rawdt=hl7_message,
|
||||
organisme=final_result,
|
||||
alat=device_name
|
||||
)
|
||||
|
||||
session.add(new_data)
|
||||
@@ -407,61 +419,107 @@ def send_mllp_message(sock, hl7_msg):
|
||||
sock.sendall(mllp_msg)
|
||||
|
||||
def handle_genexpert_client(conn, addr):
|
||||
ip_sender = addr[0]
|
||||
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
|
||||
|
||||
print(f"[TCP] Koneksi baru dari {addr}")
|
||||
buffer = b""
|
||||
|
||||
try:
|
||||
while True:
|
||||
data = conn.recv(4096)
|
||||
if not data:
|
||||
break
|
||||
|
||||
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:
|
||||
try:
|
||||
data = conn.recv(4096)
|
||||
if not data:
|
||||
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:
|
||||
logging.error(f"[ERROR] Koneksi {ip_sender} terputus: {e}")
|
||||
logging.error(f"[TCP Error] Koneksi {addr} terputus: {e}")
|
||||
finally:
|
||||
with connection_lock:
|
||||
if ip_sender in active_genexpert_connections:
|
||||
del active_genexpert_connections[ip_sender]
|
||||
conn.close()
|
||||
logging.info(f"[DISCONNECT] Koneksi dengan {ip_sender} ditutup.")
|
||||
logging.info(f"[TCP] Koneksi {addr} ditutup.")
|
||||
|
||||
def run_tcp_server():
|
||||
"""Loop utama TCP Server"""
|
||||
|
||||
Reference in New Issue
Block a user