import (
"encoding/binary"
- "github.com/jhalter/mobius/concat"
+ "io"
+ "slices"
)
// List of Hotline protocol field types taken from the official 1.9 protocol document
)
type Field struct {
- ID []byte // Type of field
- FieldSize []byte // Size of the data part
- Data []byte // Actual field content
+ ID [2]byte // Type of field
+ FieldSize [2]byte // Size of the data part
+ Data []byte // Actual field content
+
+ readOffset int // Internal offset to track read progress
}
type requiredField struct {
}
func NewField(id uint16, data []byte) Field {
- idBytes := make([]byte, 2)
- binary.BigEndian.PutUint16(idBytes, id)
+ f := Field{Data: data}
+ binary.BigEndian.PutUint16(f.ID[:], id)
+ binary.BigEndian.PutUint16(f.FieldSize[:], uint16(len(data)))
+
+ return f
+}
- bs := make([]byte, 2)
- binary.BigEndian.PutUint16(bs, uint16(len(data)))
+// fieldScanner implements bufio.SplitFunc for parsing byte slices into complete tokens
+func fieldScanner(data []byte, _ bool) (advance int, token []byte, err error) {
+ if len(data) < minFieldLen {
+ return 0, nil, nil
+ }
- return Field{
- ID: idBytes,
- FieldSize: bs,
- Data: data,
+ // tranLen represents the length of bytes that are part of the transaction
+ neededSize := minFieldLen + int(binary.BigEndian.Uint16(data[2:4]))
+ if neededSize > len(data) {
+ return 0, nil, nil
}
+
+ return neededSize, data[0:neededSize], nil
}
-func (f Field) Payload() []byte {
- return concat.Slices(f.ID, f.FieldSize, f.Data)
+// Read implements io.Reader for Field
+func (f *Field) Read(p []byte) (int, error) {
+ buf := slices.Concat(f.ID[:], f.FieldSize[:], f.Data)
+
+ if f.readOffset >= len(buf) {
+ return 0, io.EOF // All bytes have been read
+ }
+
+ n := copy(p, buf[f.readOffset:])
+ f.readOffset += n
+
+ return n, nil
+}
+
+// Write implements io.Writer for Field
+func (f *Field) Write(p []byte) (int, error) {
+ f.ID = [2]byte(p[0:2])
+ f.FieldSize = [2]byte(p[2:4])
+
+ i := int(binary.BigEndian.Uint16(f.FieldSize[:]))
+ f.Data = p[4 : 4+i]
+
+ return minFieldLen + i, nil
}
func getField(id int, fields *[]Field) *Field {
for _, field := range *fields {
- if id == int(binary.BigEndian.Uint16(field.ID)) {
+ if id == int(binary.BigEndian.Uint16(field.ID[:])) {
return &field
}
}