astm-universal-server-nestjs
v1.0.1
Published
Universal ASTM Laboratory Server built with NestJS
Readme
Universal ASTM Laboratory Server - NestJS
Tổng quan hệ thống
Universal ASTM Laboratory Server là một hệ thống server TCP hiện đại được xây dựng bằng NestJS, chuyên dụng để kết nối và xử lý dữ liệu từ các thiết bị xét nghiệm y tế trong phòng thí nghiệm. Server hỗ trợ nhiều giao thức truyền thông khác nhau và cung cấp khả năng giám sát thời gian thực thông qua WebSocket.
🔄 LUỒNG XỬ LÝ DỮ LIỆU - TỪ KHI NHẬN KẾT QUẢ ĐẾN XỬ LÝ CUỐI CÙNG
1. Khởi động hệ thống (main.ts:5-31)
Hàm: bootstrap()
- Công dụng: Khởi tạo và cấu hình toàn bộ ứng dụng NestJS
- Gọi các hàm:
NestFactory.create(AppModule)- Tạo instance NestJSapp.useGlobalPipes()- Cấu hình validationapp.enableCors()- Bật CORSapp.listen(port)- Lắng nghe HTTP trên port 3000
- Kết quả: Server HTTP chạy trên port 3000, TCP server tự động khởi động
2. Khởi tạo TCP Server (tcp-server.service.ts:33-73)
Hàm: onModuleInit() → start()
- Công dụng: Khởi động TCP server để nhận dữ liệu từ thiết bị lab
- Gọi các hàm:
net.createServer()- Tạo TCP serverserver.listen()- Lắng nghe trên port 1008eventEmitter.emit('server.started')- Thông báo server đã sẵn sàng
- Kết quả: TCP server đang lắng nghe các kết nối từ thiết bị lab
3. Thiết bị kết nối (tcp-server.service.ts:90-138)
Hàm: handleConnection(socket)
- Công dụng: Xử lý khi có thiết bị xét nghiệm kết nối TCP mới
- Gọi các hàm:
deviceService.findDevice(ip, port)- Tìm thiết bị trong configdeviceService.getDeviceName(ip, port)- Lấy tên thiết bịdeviceService.isDeviceKnown(ip, port)- Kiểm tra thiết bị có trong danh sáchdeviceService.addClient(clientInfo)- Thêm client vào danh sách quản lý
- Kết quả: ClientInfo được tạo và quản lý, socket events được đăng ký
4. Nhận dữ liệu từ thiết bị (tcp-server.service.ts:140-181)
Hàm: handleData(clientInfo, data, socket)
- Công dụng: Xử lý mỗi packet dữ liệu nhận được từ máy xét nghiệm
- Gọi các hàm:
deviceService.updateClientActivity(clientId)- Cập nhật thời gian hoạt độngdetectProtocol(data)- Phát hiện giao thức (ASTM/HL7/JSON...)eventEmitter.emit('protocol.detected')- Thông báo phát hiện giao thứceventEmitter.emit('data.received')- Broadcast dữ liệu thôprocessProtocolData()- Xử lý theo giao thức cụ thể
- Kết quả: DeviceData object được tạo và truyền qua event system
5. Phát hiện giao thức (tcp-server.service.ts:183-226)
Hàm: detectProtocol(data)
- Công dụng: Tự động xác định giao thức của dữ liệu nhận được
- Logic xử lý:
- ASTM: Kiểm tra bytes 0x05, 0x02, 0x04, 0x03 hoặc pattern
H|\\^& - HL7: Kiểm tra byte 0x0B hoặc bắt đầu với
MSH| - JSON: Validate cấu trúc JSON hợp lệ
- XML: Kiểm tra XML tags
- LIS2-A2: Kiểm tra frame format
- Raw: Mặc định cho dữ liệu không nhận dạng được
- ASTM: Kiểm tra bytes 0x05, 0x02, 0x04, 0x03 hoặc pattern
- Kết quả: Trả về string protocol type
6. Xử lý theo giao thức (tcp-server.service.ts:228-248)
Hàm: processProtocolData(protocol, deviceData, socket)
- Công dụng: Xử lý và ghi log theo từng loại giao thức cụ thể
- Gọi các hàm:
logProtocolData(protocol, deviceData)- Ghi log với format phù hợpeventEmitter.emit('astm.message')- Cho ASTM (kèm gửi ACK)eventEmitter.emit('hl7.message')- Cho HL7eventEmitter.emit('raw.data')- Cho dữ liệu thô
- Xử lý đặc biệt: Gửi ACK response cho ASTM protocol
- Kết quả: Events được emit theo loại giao thức
7. Ghi log dữ liệu (tcp-server.service.ts:250-283)
Hàm: logProtocolData(protocol, deviceData)
- Công dụng: Format và ghi log theo từng loại giao thức
- Gọi các hàm format:
formatAstmLogEntry()- Xử lý ASTM: bỏ control chars, chỉ lưu records hợp lệformatHl7LogEntry()- Xử lý HL7: phân tích message typeformatJsonLogEntry()- Xử lý JSON: extract test typeformatXmlLogEntry()- Xử lý XML: lấy root elementformatRawLogEntry()- Xử lý raw data: preview 100 ký tự
- Cuối cùng gọi:
loggingService.appendToSessionLog()- Ghi vào file log - Kết quả: Log entry được format và truyền đến logging service
8. Ghi log session (logging.service.ts:59-76)
Hàm: appendToSessionLog(clientInfo, data)
- Công dụng: Ghi dữ liệu vào cả file log và database
- Gọi các hàm:
createSessionLogFile(clientInfo)- Tạo file log nếu chưa cófs.appendFileSync()- Ghi vào file logdataLogsService.saveDataLog(clientInfo, data)- Lưu vào database
- Kết quả: Dữ liệu được lưu song song vào file và database
9. Tạo file log session (logging.service.ts:27-56)
Hàm: createSessionLogFile(clientInfo)
- Công dụng: Tạo file log riêng biệt cho mỗi session kết nối
- Format tên file:
{DeviceName}_{IP}_{Port}_{Timestamp}.txt - Tạo header: Thông tin thiết bị, IP, port, thời gian kết nối
- Gọi:
fs.writeFileSync()- Tạo file với header - Kết quả: Đường dẫn file log được trả về và lưu trong clientInfo
10. Lưu vào database (data-logs.service.ts:46-93)
Hàm: saveDataLog(clientInfo, rawData)
- Công dụng: Lưu dữ liệu vào bảng
data_logstrong SQL Server - Gọi các hàm xử lý:
generateSessionId(clientInfo)- Tạo session ID duy nhấtcleanData(rawDataString)- Làm sạch dữ liệu (bỏ control characters)detectDataType(cleanedData)- Xác định loại dữ liệu (HL7/ASTM/Lab_Result...)getNextSequence(sessionId)- Tạo số thứ tự message trong sessiondataLogsRepository.save()- Lưu vào database với TypeORM
- Kết quả: Record được lưu vào bảng data_logs với đầy đủ metadata
11. Broadcast qua WebSocket (lab.gateway.ts:87-177)
Event listeners nhận và xử lý:
handleDeviceConnected()- Khi thiết bị kết nốihandleDeviceDisconnected()- Khi thiết bị ngắt kết nốihandleDataReceived()- Khi nhận dữ liệu thôhandleAstmMessage()- Khi nhận ASTM messagehandleHl7Message()- Khi nhận HL7 messagehandleRawData()- Khi nhận raw data
Công dụng: Broadcast thông tin real-time đến các WebSocket clients Gọi các hàm:
server.to(room).emit()- Gửi đến specific room subscribersserver.emit()- Broadcast đến tất cả clients- Kết quả: Frontend nhận updates real-time
12. API endpoints (lab-server.controller.ts)
REST API cung cấp các chức năng:
getStatus()- Trạng thái server và thiết bị đang kết nốigetDevices()- Danh sách tất cả thiết bị đang kết nốigetDevice(clientId)- Thông tin chi tiết một thiết bị cụ thểgetDevicesByIP(ip)- Lọc thiết bị theo IP addressgetLogs()- Danh sách tất cả file log sessionsgetLogContent(filename)- Đọc nội dung file log cụ thểgetStats()- Thống kê chi tiết hệ thống và performance
Gọi các service methods:
tcpServerService.getStatus()- Server statusdeviceService.getServerStatus()- Device statuslabGateway.getConnectedClientsCount()- WebSocket clientsloggingService.getLogFiles()- Log files list
🎯 Tóm tắt luồng hoàn chỉnh từ A-Z:
[Thiết bị Lab]
↓ (TCP connection)
[TCP Server:1008]
↓ (socket.on('data'))
[handleData]
↓ (detectProtocol)
[Protocol Detection]
↓ (processProtocolData)
[Format & Log]
↓ (appendToSessionLog)
[File + Database]
↓ (eventEmitter.emit)
[WebSocket Broadcast]
↓ (real-time)
[Frontend Clients]Mỗi bước đều có error handling, logging chi tiết và event emission để đảm bảo tính ổn định và khả năng truy vết hoàn chỉnh của hệ thống.
🚀 Tính năng chính
1. TCP Server đa giao thức
- Tự động nhận diện giao thức: ASTM, HL7, JSON, XML, LIS2-A2, Raw data
- Kết nối đồng thời: Hỗ trợ nhiều thiết bị kết nối cùng lúc
- Quản lý timeout: Tự động ngắt kết nối các client không hoạt động
2. Nhận diện thiết bị thông minh
- Mapping thiết bị: Tự động nhận diện thiết bị dựa trên IP và port
- Danh sách thiết bị được cấu hình sẵn: Bao gồm các máy xét nghiệm phổ biến
- Xử lý thiết bị không xác định: Vẫn cho phép kết nối và xử lý dữ liệu
3. WebSocket Gateway (Thời gian thực)
- Broadcasting events: Phát sóng sự kiện đến tất cả client đã kết nối
- Room-based subscription: Client có thể đăng ký theo dõi các sự kiện cụ thể
- Real-time monitoring: Giám sát trạng thái server và thiết bị trực tiếp
4. Logging và Monitoring
- Session logs: Lưu trữ toàn bộ dữ liệu giao tiếp với từng thiết bị
- API monitoring: Theo dõi trạng thái server và thống kê kết nối
- Device statistics: Thống kê chi tiết về các thiết bị đã kết nối
🔧 Cấu trúc hệ thống
TCP Server Service
Thành phần cốt lõi xử lý kết nối TCP và nhận diện giao thức:
Quy trình xử lý kết nối:
- Nhận kết nối mới → Tạo
clientIdduy nhất - Nhận diện thiết bị → Tra cứu trong
device.config.tsdựa trên IP:Port - Detect protocol → Phân tích dữ liệu đầu tiên để xác định giao thức
- Xử lý dữ liệu → Forward đến module xử lý tương ứng
- Logging → Ghi lại toàn bộ session
Device Service
Quản lý thông tin thiết bị và client kết nối:
- Lưu trữ danh sách client đang kết nối
- Emit events khi có thiết bị kết nối/ngắt kết nối
- Cung cấp API để truy vấn thông tin thiết bị
WebSocket Gateway
Cung cấp giao tiếp thời gian thực:
- Broadcast events đến WebSocket clients
- Hỗ trợ subscription theo room/topic
- Realtime monitoring cho frontend applications
🔍 Nhận diện giao thức
Server tự động phát hiện giao thức dựa trên đặc điểm dữ liệu:
ASTM (Automated Sequential Treatment Machine)
- Byte đầu: 0x05 (ENQ) hoặc 0x02 (STX)
- Byte cuối: 0x04 (EOT) hoặc 0x03 (ETX)
- Pattern: H|\^& (Header record)
- Format: [HPORCL]\d*\| (Record types)HL7 (Health Level 7)
- Byte đầu: 0x0B (VT - Vertical Tab)
- Bắt đầu với: MSH| (Message Header)
- Kết thúc với: \r (Carriage Return)Các giao thức khác
- JSON: Phát hiện cấu trúc
{...}và validate JSON - XML: Phát hiện tags
<...> - LIS2-A2: Kiểm tra control characters (SOH, STX, etc.)
- Raw: Dữ liệu không thuộc các loại trên
🏥 Cấu hình thiết bị
File src/config/device.config.ts chứa mapping các thiết bị phòng thí nghiệm:
Các thiết bị được hỗ trợ:
- Máy xét nghiệm HbA1c AdamA1C
- Máy Cobas6000 (nhiều máy)
- Máy điện giải Erba
- Máy xét nghiệm đông máu CA600
- Máy xét nghiệm nước tiểu UraM/U411
- Máy cobas E601
- Máy định danh kháng sinh Vitek 2
📡 WebSocket Events
Client Events (Gửi đến server)
subscribe: Đăng ký theo dõi eventsunsubscribe: Hủy đăng ký eventsgetStatus: Lấy trạng thái server
Server Events (Phát từ server)
device.connected: Thiết bị kết nốidevice.disconnected: Thiết bị ngắt kết nốiprotocol.detected: Phát hiện giao thức mớidata.received: Nhận dữ liệu từ thiết bịastm.message: Tin nhắn ASTM cụ thểhl7.message: Tin nhắn HL7 cụ thểraw.data: Dữ liệu raw
🔬 Luồng xử lý kết quả xét nghiệm
Quy trình xử lý từ A-Z khi nhận 1 kết quả xét nghiệm
Bước 1: Thiết bị kết nối và nhận diện
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Thiết bị Lab │───▶│ TCP Server │───▶│ Device Service │
│ (Cobas6000) │ │ (Port 1008) │ │ (Nhận diện) │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│ │ │
│ │ ▼
│ │ ✅ Mapping IP:Port
│ │ 📍 "Máy Cobas6000 số 1"
│ │ 🔍 isKnownDevice = trueBước 2: Phát hiện giao thức từ dữ liệu đầu tiên
// Ví dụ dữ liệu ASTM từ Cobas6000
const astmData = "\u0005H|\\^&|||Cobas6000^123456||||||P||20250915\r\u0004";
// Logic detection trong tcp-server.service.ts:188
private detectProtocol(data: Buffer): string {
const firstByte = data[0]; // 0x05 (ENQ)
const lastByte = data[data.length - 1]; // 0x04 (EOT)
if (firstByte === 0x05 || dataStr.includes('H|\\^&')) {
return 'astm'; // ✅ Xác định là ASTM
}
// ... logic khác
}Bước 3: Xử lý dữ liệu và tạo DeviceData object
// Tạo đối tượng DeviceData chuẩn hóa
const deviceData: DeviceData = {
clientId: "client_1726388445123_abc123",
protocol: "astm",
data: "H|\\^&|||Cobas6000^123456||||||P||20250915\r",
timestamp: new Date(),
deviceInfo: {
remoteAddress: "192.168.25.107",
remotePort: 52341,
localPort: 10008,
deviceName: "Máy Cobas6000 số 1",
connectionId: "client_1726388445123_abc123",
isKnownDevice: true
},
sessionLogFile: "May_Cobas6000_so_1_192.168.25.107_10008_2025-09-15T14-20-45.txt"
};Bước 4: Logging session chi tiết
📁 ./logs/May_Cobas6000_so_1_192.168.25.107_10008_2025-09-15T14-20-45.txt
=== LOG SESSION ===
Thiết bị: Máy Cobas6000 số 1
IP: 192.168.25.107
Port: 10008
Kết nối lúc: 2025-09-15T14:20:45.123Z
Protocol: ASTM
=====================================
[2025-09-15T14:20:45.123Z] [Máy Cobas6000 số 1] [ASTM] ENQ received
[2025-09-15T14:20:45.124Z] [Máy Cobas6000 số 1] [ASTM] ACK sent
[2025-09-15T14:20:45.200Z] [Máy Cobas6000 số 1] [ASTM] H|\\^&|||Cobas6000^123456||||||P||20250915
[2025-09-15T14:20:45.201Z] [Máy Cobas6000 số 1] [ASTM] P|1|||NguyenVanA^123456789||19900101|M
[2025-09-15T14:20:45.202Z] [Máy Cobas6000 số 1] [ASTM] O|1|Sample001||GLU^Glucose|||||||||||
[2025-09-15T14:20:45.203Z] [Máy Cobas6000 số 1] [ASTM] R|1|^^^GLU|120.5|mg/dL|70.0-110.0|H|||FBước 5: Broadcasting Events thông qua EventEmitter
// Trong tcp-server.service.ts:182-185
this.eventEmitter.emit('data.received', deviceData);
// Xử lý theo từng loại giao thức
switch (protocol) {
case 'astm':
this.eventEmitter.emit('astm.message', deviceData);
// Gửi ACK cho ASTM protocol
if (deviceData.data.includes('\u0005')) { // ENQ
socket.write('\u0006'); // ACK
}
break;
}Bước 6: WebSocket Broadcasting cho Real-time Monitoring
// Trong lab.gateway.ts:179-202
@OnEvent('astm.message')
handleAstmMessage(deviceData: DeviceData) {
// Gửi đến client đã subscribe 'astm.message'
this.server.to('astm.message').emit('astm.message', {
clientId: deviceData.clientId,
deviceName: deviceData.deviceInfo.deviceName,
data: deviceData.data,
timestamp: deviceData.timestamp,
sessionLogFile: deviceData.sessionLogFile,
});
// Broadcast tổng quát đến tất cả clients
this.server.emit('astm.message', {
type: 'astm_message',
data: {
deviceName: "Máy Cobas6000 số 1",
dataPreview: "H|\\^&|||Cobas6000^123456...",
timestamp: "2025-09-15T14:20:45.203Z"
}
});
}Bước 7: Frontend nhận real-time update
// Frontend WebSocket client
const socket = io('http://localhost:3000/lab');
socket.on('astm.message', (data) => {
console.log('🧪 Kết quả xét nghiệm mới từ:', data.deviceName);
console.log('📊 Dữ liệu:', data.dataPreview);
// Update UI real-time
updateLabResultsTable({
device: data.deviceName,
timestamp: data.timestamp,
preview: data.dataPreview
});
});Ví dụ cụ thể: Xử lý kết quả Glucose từ Cobas6000
1. Raw ASTM Message nhận được:
\u0005 # ENQ (Enquiry)
H|\\^&|||Cobas6000^123456||||||P||20250915\r # Header Record
P|1|||NguyenVanA^123456789||19900101|M\r # Patient Record
O|1|Sample001||GLU^Glucose||||||||||||\r # Order Record
R|1|^^^GLU|120.5|mg/dL|70.0-110.0|H|||F\r # Result Record
L|1|N\r # Terminator Record
\u0004 # EOT (End of Transmission)2. Parsing và extract thông tin:
// Parsing ASTM result record
const resultRecord = "R|1|^^^GLU|120.5|mg/dL|70.0-110.0|H|||F";
const fields = resultRecord.split('|');
const parsedResult = {
recordType: 'R', // Result Record
sequenceNumber: '1', // Sequence #1
testCode: 'GLU', // Glucose test
value: '120.5', // Result value
unit: 'mg/dL', // Unit
referenceRange: '70.0-110.0', // Normal range
abnormalFlag: 'H', // High (above normal)
resultStatus: 'F' // Final result
};3. Enriched data object được tạo:
const enrichedResult = {
...deviceData,
parsedData: {
patient: {
id: 'NguyenVanA',
sampleId: '123456789',
birthDate: '1990-01-01',
gender: 'M'
},
test: {
code: 'GLU',
name: 'Glucose',
value: 120.5,
unit: 'mg/dL',
normalRange: '70.0-110.0',
status: 'HIGH',
flag: 'H'
},
metadata: {
sampleId: 'Sample001',
resultStatus: 'Final',
testDate: '2025-09-15'
}
}
};4. Event cascade và notifications:
📡 Events được emit theo thứ tự:
1. 'device.connected' → UI hiển thị thiết bị online
2. 'protocol.detected' → UI hiển thị "ASTM detected"
3. 'data.received' → General data logging
4. 'astm.message' → Specific ASTM processing
5. WebSocket broadcast → Frontend update real-time
6. Session log update → File system loggingXử lý các trường hợp đặc biệt
Lỗi transmission:
// Nếu dữ liệu bị lỗi hoặc incomplete
socket.on('error', (error) => {
this.logger.error(`❌ Lỗi truyền dữ liệu từ ${clientInfo.deviceName}:`, error);
this.eventEmitter.emit('transmission.error', {
clientId: clientInfo.id,
deviceName: clientInfo.deviceName,
error: error.message,
timestamp: new Date()
});
});Timeout handling:
// Client timeout sau 30 giây không hoạt động
socket.setTimeout(30000);
socket.on('timeout', () => {
this.logger.warn(`⏱️ Timeout thiết bị: ${clientInfo.deviceName}`);
socket.destroy();
});Protocol ACK/NAK responses:
// ASTM cần ACK response
if (deviceData.data.includes('\u0005')) { // ENQ
socket.write('\u0006'); // Send ACK
this.logger.log(`✅ ACK sent to ${deviceInfo.deviceName}`);
} else if (deviceData.data.includes('\u0002')) { // STX
// Process data and send ACK
socket.write('\u0006');
}Luồng này đảm bảo mọi kết quả xét nghiệm được xử lý một cách đáng tin cậy, có thể truy vết và cung cấp monitoring real-time cho hệ thống lab.
⚡ Hướng dẫn cài đặt
1. Cài đặt dependencies
cd nestjs-server
npm install2. Cấu hình môi trường
Tạo file .env:
PORT=3000 # Port cho HTTP API
TCP_PORT=1008 # Port TCP cho thiết bị lab
TCP_HOST=0.0.0.0 # Listen trên tất cả interfaces
LOG_DIRECTORY=./logs # Thư mục lưu log files
DEBUG=true # Bật debug logging
CLIENT_TIMEOUT=30000 # Timeout cho client (ms)3. Chạy server
# Development mode
npm run start:dev
# Production mode
npm run build
npm run start:prod
# Debug mode
npm run start:debug4. Kết nối thiết bị
Cấu hình các thiết bị xét nghiệm để kết nối đến:
- IP: Địa chỉ IP của server
- Port: Port cụ thể cho từng thiết bị (xem bảng cấu hình thiết bị)
📋 Danh sách thiết bị được hỗ trợ
Server tự động nhận diện các thiết bị sau:
| Tên thiết bị | Địa chỉ IP | Port | |-------------|------------|------| | Máy XN HbA1c AdamA1C | 192.168.25.107 | 10001 | | Máy Cobas6000 số 1 | 192.168.25.107 | 10008 | | Máy điện giải Erba số 2 | 192.168.25.107 | 10003 | | Máy Cobas6000 số 2 | 192.168.3.127 | 10004 | | Máy XN đông máu CA600 số 1 | 192.168.3.127 | 10006 | | Máy Xn nước tiểu UraM | 192.168.3.127 | 10007 | | Máy điện giải Erba số 1 | 192.168.3.127 | 10001 | | Máy cobas E601 | 192.168.3.233 | 10002 | | Máy đông máu CA600 số 2 | 192.168.3.233 | 10003 | | Máy định danh KSĐ Vitek 2 | 192.168.3.233 | 10005 | | Máy Cobas 6000 | 10.10.4.215 | 10004 | | Máy điện giải Elyte | 10.10.4.215 | 10002 | | Máy Xn nước tiểu U411 | 10.10.4.215 | 30024 |
📊 API Endpoints
Monitoring APIs
GET /lab-server/status- Trạng thái tổng quan serverGET /lab-server/devices- Danh sách thiết bị đang kết nốiGET /lab-server/devices/:clientId- Thông tin chi tiết một thiết bịGET /lab-server/devices/by-ip/:ip- Thiết bị theo IPGET /lab-server/stats- Thống kê chi tiếtGET /lab-server/logs- Danh sách log filesGET /lab-server/logs/:filename- Nội dung log fileGET /lab-server/logs/:filename?tail=100- N dòng cuối của logGET /health- Health check cơ bản
🌐 WebSocket Integration
Kết nối WebSocket
const socket = io('http://localhost:3000/lab');
// Lắng nghe kết nối thành công
socket.on('connected', (data) => {
console.log('🧪 Kết nối thành công:', data.message);
});Đăng ký theo dõi sự kiện
// Đăng ký theo dõi các sự kiện cụ thể
socket.emit('subscribe', {
events: ['device.connected', 'astm.message', 'hl7.message']
});
// Lắng nghe thiết bị kết nối
socket.on('device.connected', (data) => {
console.log('📱 Thiết bị kết nối:', data.deviceName);
});
// Lắng nghe dữ liệu ASTM
socket.on('astm.message', (data) => {
console.log('🧪 Dữ liệu ASTM từ:', data.deviceName);
});
// Lấy trạng thái server
socket.emit('getStatus');
socket.on('status', (status) => {
console.log('📊 Trạng thái server:', status);
});📝 Format Log Files
Tên file log
TenThietBi_IP_Port_Timestamp.txt
May_Cobas6000_so_1_192.168.25.107_10008_2025-09-12T11-30-45.txtĐịnh dạng nội dung log
=== LOG SESSION ===
Thiết bị: Máy Cobas6000 số 1
IP: 192.168.25.107
Port: 10008
Kết nối lúc: 2025-09-12T11:30:45.123Z
=====================================
[2025-09-12T11:30:45.123Z] [Máy Cobas6000 số 1] <Dữ liệu ASTM>
[2025-09-12T11:30:50.456Z] [Máy Cobas6000 số 1] <Dữ liệu tiếp theo>🏗️ Kiến trúc hệ thống
Các Services chính
- TcpServerService: Xử lý TCP connections và protocol detection
- DeviceService: Quản lý thông tin thiết bị và client connections
- LoggingService: Ghi log và quản lý session data
- LabGateway: WebSocket gateway cho real-time communication
Event System
Sử dụng NestJS EventEmitter cho giao tiếp không đồng bộ:
- Kết nối/ngắt kết nối thiết bị
- Phát hiện giao thức
- Nhận và xử lý dữ liệu
- Xử lý lỗi và exception
Cơ chế hoạt động
- TCP Server lắng nghe trên port cấu hình
- Device Service nhận diện thiết bị khi có kết nối mới
- Protocol Detection tự động phát hiện giao thức từ dữ liệu
- Event Emitter phát sóng events đến các module khác
- WebSocket Gateway broadcast real-time updates
- Logging Service ghi lại toàn bộ session
🛠️ Development
Lệnh phát triển
npm run start:dev # Development với hot reload
npm run start:debug # Debug mode
npm run build # Build cho production
npm run test # Chạy tests
npm run lint # Lint code
npm run format # Format codeThêm thiết bị mới
Chỉnh sửa file src/config/device.config.ts:
export const labDeviceMapping: DeviceInfo[] = [
// Thêm thiết bị mới
{ "ip": "192.168.1.100", "name": "Tên thiết bị mới", "port": 10009 },
// ... các thiết bị hiện có
];Tạo Protocol Handler mới
Tạo handler mới trong src/services/ và đăng ký trong TCP server service.
Cấu trúc thư mục
src/
├── config/ # Cấu hình thiết bị và hệ thống
├── dto/ # Data Transfer Objects
├── gateways/ # WebSocket gateways
├── interfaces/ # TypeScript interfaces
├── lab-server/ # Lab server module
├── services/ # Business logic services
└── main.ts # Entry point🚀 Triển khai Production
Docker (Khuyến nghị)
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist ./dist
EXPOSE 3000 1008
CMD ["npm", "run", "start:prod"]PM2 Process Manager
npm install -g pm2
npm run build
pm2 start dist/main.js --name "astm-lab-server"
pm2 startup
pm2 saveSystemd Service
[Unit]
Description=Universal ASTM Lab Server
After=network.target
[Service]
Type=simple
User=labuser
WorkingDirectory=/opt/astm-lab-server
ExecStart=/usr/bin/node dist/main.js
Restart=always
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target📈 Monitoring và Logging
Các loại logs
- Application logs: Console output với timestamp
- Session logs: Thư mục
./logs/cho từng thiết bị - WebSocket events: Real-time events trong browser console
Health Checks
# Kiểm tra sức khỏe server
curl http://localhost:3000/health
# Trạng thái đầy đủ
curl http://localhost:3000/lab-server/status
# Thống kê chi tiết
curl http://localhost:3000/lab-server/statsReal-time Monitoring
Sử dụng WebSocket để theo dõi:
- Kết nối/ngắt kết nối thiết bị
- Dữ liệu đến từ thiết bị
- Trạng thái server
- Thống kê performance
🔒 Bảo mật
CORS Configuration
app.enableCors({
origin: true,
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
});Validation
Sử dụng class-validator và ValidationPipe để validate input data.
Khuyến nghị bảo mật
- Cấu hình firewall cho TCP ports
- Sử dụng SSL/TLS cho WebSocket trong production
- Implement authentication cho REST API nếu cần
- Monitor log file sizes và implement rotation
🚨 Xử lý lỗi và Troubleshooting
Graceful Shutdown
process.on('SIGINT', async () => {
logger.log('🛑 Received shutdown signal...');
// Cleanup resources
process.exit(0);
});Các lỗi thường gặp
- Xung đột port: Kiểm tra TCP_PORT không bị service khác sử dụng
- Thiết bị kết nối thất bại: Kiểm tra cấu hình IP/port trong thiết bị
- Lỗi WebSocket: Verify CORS settings và port accessibility
- Quyền thư mục log: Đảm bảo quyền ghi cho LOG_DIRECTORY
- Timeout detection: Tự động ngắt kết nối client không hoạt động
Debug Mode
Bật debug logging bằng cách set DEBUG=true trong file .env.
Client Error Handling
- Timeout detection và auto-disconnect
- Error logging cho debugging
- Event emission cho monitoring
📝 Ghi chú quan trọng
- Port Configuration: Mỗi thiết bị cần được cấu hình với IP và port cụ thể
- Protocol Detection: Tự động nhưng có thể override nếu cần
- Real-time Updates: WebSocket cung cấp updates tức thời
- Logging: Toàn bộ dữ liệu được ghi log để audit và debugging
- Scalability: Có thể mở rộng để hỗ trợ thêm nhiều giao thức
📞 Liên hệ và Hỗ trợ
Để được hỗ trợ kỹ thuật hoặc đóng góp vào dự án, vui lòng liên hệ team phát triển hoặc tạo issue trên repository.
📄 License
MIT License - Tự do sử dụng trong môi trường phòng thí nghiệm.
Universal ASTM Laboratory Server - Connecting Your Lab Equipment Seamlessly 🧪🔬
