Skip to content

Instantly share code, notes, and snippets.

@truongluu
Created March 18, 2026 03:52
Show Gist options
  • Select an option

  • Save truongluu/3f4612ca41aaa7ab80e2574a973bbf03 to your computer and use it in GitHub Desktop.

Select an option

Save truongluu/3f4612ca41aaa7ab80e2574a973bbf03 to your computer and use it in GitHub Desktop.
import net from 'net';
import { BSON } from 'bson';
// Tạo kết nối TCP tới MongoDB server chạy ở localhost:27019.
const socket = net.connect(27019, 'localhost', () => {
// Callback này chạy khi TCP connect thành công.
// Bên trong, ta tự đóng gói gói tin theo MongoDB Wire Protocol (OP_MSG).
// Lệnh find tương đương: db.users.find({ age: 18 }) trên database "mysql".
// BSON.serialize biến object JS thành Buffer BSON để gửi qua mạng.
const doc = BSON.serialize({ find: 'users', filter: { age: 18 }, '$db': 'mysql' })
// Header OP_MSG có tổng 20 bytes: 16 bytes chuẩn + 4 bytes flagBits.
const header = Buffer.alloc(20)
// messageLength = header(20) + kind byte(1) + độ dài BSON body.
// Byte này nằm ở offset 0 trong header.
header.writeInt32LE(20 + 1 + doc.length, 0) // messageLength includes section kind byte
// requestID: id request hiện tại để match response nếu cần.
header.writeInt32LE(1, 4) // requestID
// responseTo của request luôn là 0.
header.writeInt32LE(0, 8) // responseTo
// opCode 2013 = OP_MSG (kiểu message hiện đại của MongoDB).
header.writeInt32LE(2013, 12) // opCode OP_MSG
// flagBits cho OP_MSG, 0 nghĩa không bật cờ đặc biệt nào.
header.writeUInt32LE(0, 16) // flagBits
// Section kind byte: 0 nghĩa "single BSON document section".
const kindByte = Buffer.from([0]) // kind = 0 (body section)
// Gửi gói tin hoàn chỉnh: header + kind byte + BSON command document.
socket.write(Buffer.concat([header, kindByte, doc]))
})
// Lắng nghe dữ liệu phản hồi từ server.
socket.on('data', (chunk) => {
// Trong TypeScript, chunk có thể là string hoặc Buffer.
// Chuẩn hóa về Buffer để dùng các hàm readInt32LE/readUInt8 an toàn.
const data = typeof chunk === 'string' ? Buffer.from(chunk) : chunk
// In raw data dạng hex để debug giao thức nhị phân.
console.log('Raw bytes:', data.toString('hex'))
// In dạng utf-8 chỉ để tham khảo; dữ liệu nhị phân thường sẽ khó đọc.
console.log('Raw bytes:', data.toString('utf-8'))
// Cần ít nhất 16 bytes để đọc được header cơ bản của MongoDB message.
if (data.length < 16) {
// Nếu chưa đủ header thì chờ gói tiếp theo.
console.log('Incomplete MongoDB header, waiting for more data')
return
}
// Parse OP_MSG response: 16-byte header + 4-byte flagBits + sections
// Đọc tổng độ dài message từ 4 bytes đầu.
const messageLength = data.readInt32LE(0)
// responseTo giúp biết response này trả cho request nào.
const responseTo = data.readInt32LE(8)
// opCode để xác định kiểu message nhận về.
const opCode = data.readInt32LE(12)
// Nếu data hiện tại chưa đủ messageLength thì chưa parse được đầy đủ.
if (data.length < messageLength) {
console.log(`Incomplete MongoDB message: got ${data.length}, expected ${messageLength}`)
return
}
// Chỉ xử lý OP_MSG; kiểu khác thì bỏ qua để tránh parse sai format.
if (opCode !== 2013) {
console.log('Unexpected opCode:', opCode)
return
}
// 4 bytes sau header cơ bản là flagBits của OP_MSG.
const flags = data.readUInt32LE(16)
// Bắt đầu đọc section từ offset 20 (16 header + 4 flagBits).
let offset = 20
// Mảng chứa các document đã deserialize từ response.
const docs: unknown[] = []
// Duyệt từng section cho đến hết message.
while (offset < messageLength) {
// Mỗi section bắt đầu bằng 1 byte kind.
const kind = data.readUInt8(offset)
// Sau khi đọc kind thì nhích con trỏ 1 byte.
offset += 1
// Kind 0: section chứa đúng 1 BSON document.
if (kind === 0) {
// 4 bytes đầu của BSON luôn là kích thước chính document đó.
const bsonSize = data.readInt32LE(offset)
// Tính vị trí kết thúc document BSON.
const bsonEnd = offset + bsonSize
// Chặn lỗi nếu buffer thực tế ngắn hơn BSON khai báo.
if (bsonEnd > data.length) {
throw new Error(`Truncated BSON document: end=${bsonEnd}, bufferLength=${data.length}`)
}
// Cắt đúng bytes của BSON document.
const bsonBuffer = data.slice(offset, bsonEnd)
// Deserialize BSON thành object JS và đưa vào danh sách kết quả.
docs.push(BSON.deserialize(bsonBuffer))
// Dời offset tới ngay sau document vừa đọc.
offset = bsonEnd
// Xử lý section tiếp theo.
continue
}
// Kind 1: document sequence (nhiều BSON docs trong cùng section).
if (kind === 1) {
// Section kind 1: document sequence = int32 size + cstring id + docs
// sectionSize là kích thước phần còn lại của section (không gồm byte kind).
const sectionSize = data.readInt32LE(offset)
// sectionEnd là vị trí kết thúc section này.
const sectionEnd = offset + sectionSize
// Skip cstring identifier
// Bỏ qua section size (4 bytes) để tới chuỗi cstring identifier.
offset += 4
// Bỏ qua cstring (kết thúc bằng byte 0).
while (offset < sectionEnd && data[offset] !== 0) {
offset += 1
}
// Bỏ byte 0 kết thúc cstring.
offset += 1
// Sau cstring là chuỗi các BSON docs liên tiếp.
while (offset < sectionEnd) {
// Đọc kích thước BSON kế tiếp.
const bsonSize = data.readInt32LE(offset)
// Tính vị trí kết thúc BSON đó.
const bsonEnd = offset + bsonSize
// Chặn lỗi nếu BSON vượt quá buffer đang có.
if (bsonEnd > data.length) {
throw new Error(`Truncated BSON in section 1: end=${bsonEnd}, bufferLength=${data.length}`)
}
// Cắt và deserialize từng BSON document trong sequence.
const bsonBuffer = data.slice(offset, bsonEnd)
docs.push(BSON.deserialize(bsonBuffer))
// Dịch con trỏ sang BSON kế tiếp.
offset = bsonEnd
}
// Xử lý section tiếp theo (nếu còn).
continue
}
// Nếu gặp kind lạ thì báo lỗi để debug protocol.
throw new Error(`Unknown OP_MSG section kind: ${kind}`)
}
// In thông tin metadata của response đã parse.
console.log('Parsed response:', { messageLength, responseTo, opCode, flags })
// In các BSON documents đã chuyển thành object JS.
console.log('Parsed BSON documents:', docs)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment