From a8936d92a5a9e8c33da7ea9642f90416265bad2a Mon Sep 17 00:00:00 2001 From: adman Date: Sun, 10 May 2026 18:41:04 +0200 Subject: [PATCH] add replay reader and writer for handling tmcpr files --- cmd/strom/print_replay/main.go | 3 +- proto/replay/reader.go | 67 ++++++++++++++++++++++++++++++++++ proto/replay/writer.go | 39 ++++++++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 proto/replay/reader.go create mode 100644 proto/replay/writer.go diff --git a/cmd/strom/print_replay/main.go b/cmd/strom/print_replay/main.go index 39379bd..8700fba 100644 --- a/cmd/strom/print_replay/main.go +++ b/cmd/strom/print_replay/main.go @@ -82,7 +82,7 @@ func UnpackPacket(r io.Reader) (packet proto_base.EncodeDecodeAble, err error) { // Calculate position after reading the packet ID // indexafterid represents how many bytes we've read so far - indexafterid := int(b.Size()) - int(b.Len()) + indexafterid := int(b.Size()) - b.Len() i, ok := proto.LookUpTypeByPacketInfo(proto_base.ToClient, state, packetId, int32(*ProtocolVersion)) if !ok { @@ -103,6 +103,7 @@ func UnpackPacket(r io.Reader) (packet proto_base.EncodeDecodeAble, err error) { } return } + func Run(args []string) (err error) { err = cmd.Parse(args) if err != nil { diff --git a/proto/replay/reader.go b/proto/replay/reader.go new file mode 100644 index 0000000..4409230 --- /dev/null +++ b/proto/replay/reader.go @@ -0,0 +1,67 @@ +package replay + +import ( + "bytes" + "encoding/binary" + "io" + "reflect" + + "github.com/admin-else/strom/proto" + "github.com/admin-else/strom/proto_base" +) + +type Reader struct { + r io.Reader + State proto_base.State + Version int32 +} + +func NewReader(r io.Reader) *Reader { + return &Reader{r: r} +} + +func (r *Reader) ReadRaw() (packetData []byte, timestamp, length uint32, err error) { + err = binary.Read(r.r, binary.BigEndian, ×tamp) + if err != nil { + return + } + err = binary.Read(r.r, binary.BigEndian, &length) + if err != nil { + return + } + + // Read the packet data into a byte slice + packetData = make([]byte, length) + _, err = io.ReadFull(r.r, packetData) + return +} + +func (r *Reader) ReadPacket() (packet proto_base.EncodeDecodeAble, err error) { + packetData, _, _, err := r.ReadRaw() + if err != nil { + return + } + b := bytes.NewReader(packetData) + + packetId, err := proto_base.DecodeVarInt(b) + if err != nil { + return + } + + // Calculate position after reading the packet ID + // indexafterid represents how many bytes we've read so far + indexafterid := int(b.Size()) - b.Len() + + i, ok := proto.LookUpTypeByPacketInfo(proto_base.ToClient, r.State, packetId, r.Version) + if !ok { + packet = &proto.UnCodablePacket{Err: proto.BadPacketIdErr, Data: packetData, Info: i} + return + } + packet = reflect.New(reflect.TypeOf(i.Type).Elem()).Interface().(proto_base.EncodeDecodeAble) + err = packet.Decode(b) + if err != nil { + packet = &proto.UnCodablePacket{Err: err, Data: packetData[indexafterid:], Info: i} + return + } + return +} diff --git a/proto/replay/writer.go b/proto/replay/writer.go new file mode 100644 index 0000000..805ddd5 --- /dev/null +++ b/proto/replay/writer.go @@ -0,0 +1,39 @@ +package replay + +import ( + "bytes" + "encoding/binary" + "io" + + "github.com/admin-else/strom/proto_base" +) + +type Writer struct { + w io.Writer +} + +func NewWriter(w io.Writer) *Writer { + return &Writer{w} +} + +func (w *Writer) WriteRaw(p []byte, timestamp uint32) (err error) { + err = binary.Write(w.w, binary.BigEndian, timestamp) + if err != nil { + return + } + err = binary.Write(w.w, binary.BigEndian, uint32(len(p))) + if err != nil { + return + } + _, err = w.w.Write(p) + return +} + +func (w *Writer) WritePacket(packet proto_base.EncodeDecodeAble, timestamp uint32) (err error) { + b := bytes.NewBuffer(nil) + err = packet.Encode(b) + if err != nil { + return + } + return w.WriteRaw(b.Bytes(), timestamp) +}