fix OP_Query parse
This commit is contained in:
parent
c70cfad89c
commit
fdd3a2e7c7
|
@ -47,6 +47,7 @@ func (s *Server) handleConnection(conn net.Conn) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.WriteOpMsgToFile("opbin.log", uint8(2), buffer[:n])
|
||||||
// 解析MongoDB协议消息
|
// 解析MongoDB协议消息
|
||||||
message, err := protocol.ParseMessage(buffer[:n])
|
message, err := protocol.ParseMessage(buffer[:n])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -174,6 +174,20 @@ func parseBSONValue(elementType byte, data []byte, pos int) (interface{}, int, e
|
||||||
}
|
}
|
||||||
|
|
||||||
return subDoc, docLength, nil
|
return subDoc, docLength, nil
|
||||||
|
case 0x04: // Array
|
||||||
|
if len(data) < 4 {
|
||||||
|
return nil, 0, fmt.Errorf("data too short for Array length")
|
||||||
|
}
|
||||||
|
// 读取数组长度
|
||||||
|
arrayLength := int(binary.LittleEndian.Uint32(data[0:4]))
|
||||||
|
if len(data) < arrayLength {
|
||||||
|
return nil, 0, fmt.Errorf("data too short for Array")
|
||||||
|
}
|
||||||
|
subDoc, _, err := parseBSON(data[0:arrayLength])
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("failed to parse array: %v", err)
|
||||||
|
}
|
||||||
|
return subDoc, arrayLength, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, 0, fmt.Errorf("unsupported BSON element type: 0x%02X", elementType)
|
return nil, 0, fmt.Errorf("unsupported BSON element type: 0x%02X", elementType)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UpdateFlags are the flags for OP_UPDATE
|
// UpdateFlags are the flags for OP_UPDATE
|
||||||
|
@ -190,20 +191,30 @@ func parseQuery(data []byte) (interface{}, error) {
|
||||||
if dbEnd == -1 {
|
if dbEnd == -1 {
|
||||||
return nil, fmt.Errorf("database name not null terminated")
|
return nil, fmt.Errorf("database name not null terminated")
|
||||||
}
|
}
|
||||||
dbName := string(data[4 : dbEnd+4])
|
dbcolName := string(data[4 : dbEnd+4])
|
||||||
|
dcnames := strings.Split(dbcolName, ".")
|
||||||
|
dbName := dcnames[0]
|
||||||
|
collName := dcnames[1]
|
||||||
|
|
||||||
// 剩余数据包含集合名和查询条件
|
// 剩余数据包含集合名和查询条件
|
||||||
remaining := data[dbEnd+5:] // 跳过终止符
|
remaining := data[dbEnd+5:] // 跳过终止符
|
||||||
|
var numberToSkip, numberToReturn int32
|
||||||
|
binary.Read(bytes.NewReader(remaining[0:4]), binary.LittleEndian, &numberToSkip)
|
||||||
|
binary.Read(bytes.NewReader(remaining[4:8]), binary.LittleEndian, &numberToReturn)
|
||||||
// 提取集合名
|
// 提取集合名
|
||||||
collEnd := bytes.IndexByte(remaining, 0)
|
// collEnd := bytes.IndexByte(remaining, 0)
|
||||||
if collEnd == -1 {
|
// if collEnd == -1 {
|
||||||
return nil, fmt.Errorf("collection name not null terminated")
|
// return nil, fmt.Errorf("collection name not null terminated")
|
||||||
}
|
// }
|
||||||
collName := string(remaining[:collEnd])
|
// if collEnd == 0 {
|
||||||
|
// collEnd = bytes.IndexFunc(remaining, func(r rune) bool {
|
||||||
|
// return r != 0
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// collName := string(remaining[:collEnd])
|
||||||
|
|
||||||
// 解析查询条件
|
// 解析查询条件
|
||||||
queryDoc, _, err := parseBSON(remaining[collEnd+1:])
|
queryDoc, _, err := parseBSON(remaining[8:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse query conditions: %v", err)
|
return nil, fmt.Errorf("failed to parse query conditions: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -212,6 +223,8 @@ func parseQuery(data []byte) (interface{}, error) {
|
||||||
Flags: flags,
|
Flags: flags,
|
||||||
DatabaseName: dbName,
|
DatabaseName: dbName,
|
||||||
CollName: collName,
|
CollName: collName,
|
||||||
|
NumberToSkip: numberToSkip,
|
||||||
|
NumberToReturn: numberToReturn,
|
||||||
Query: queryDoc,
|
Query: queryDoc,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -268,6 +281,8 @@ type QueryMessage struct {
|
||||||
Flags uint32 // 查询标志
|
Flags uint32 // 查询标志
|
||||||
DatabaseName string // 数据库名称
|
DatabaseName string // 数据库名称
|
||||||
CollName string // 集合名称
|
CollName string // 集合名称
|
||||||
|
NumberToSkip int32
|
||||||
|
NumberToReturn int32
|
||||||
Query map[string]interface{} // 查询条件
|
Query map[string]interface{} // 查询条件
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,22 @@ package protocol
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"git.pyer.club/kingecg/goaidb/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestParseQuery(t *testing.T) {
|
||||||
|
_, data, err := log.ReadOpMsgFromFile("/home/kingecg/code/goaidb/opbin.log")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ReadOpMsgFromFile failed: %v", err)
|
||||||
|
}
|
||||||
|
msg, err := ParseMessage(data)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ParseMessage failed: %v", err)
|
||||||
|
}
|
||||||
|
log.Info(msg.Body)
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseUpdate(t *testing.T) {
|
func TestParseUpdate(t *testing.T) {
|
||||||
// 构造测试数据(最小有效Update消息)
|
// 构造测试数据(最小有效Update消息)
|
||||||
data := []byte{
|
data := []byte{
|
||||||
|
|
Loading…
Reference in New Issue