package wireproto import ( `bytes` `fmt` `io` `strings` `github.com/google/uuid` ) // ConnId returns a copy of the connection ID. func (r *RequestRecord) ConnId() (conn uuid.UUID) { conn = r.connId return } // GetParent returns the parent RecordGroup. func (r *RequestRecord) GetParent() (rg RecordGroup) { rg = r.parent return } // MarshalBinary renders a RequestRecord into a byte-packed format. func (r *RequestRecord) MarshalBinary() (data []byte, err error) { var b []byte var recSize int var buf *bytes.Buffer = new(bytes.Buffer) _ = r.Size() if _, err = buf.Write(PackInt(len(r.Pairs))); err != nil { return } for _, i := range r.Pairs { recSize += i.Size() } if _, err = buf.Write(PackInt(recSize)); err != nil { return } for _, i := range r.Pairs { if b, err = i.MarshalBinary(); err != nil { return } if _, err = buf.Write(b); err != nil { return } } data = buf.Bytes() return } // Model returns an indented string representation of the model. func (r *RequestRecord) Model() (out string) { out = r.ModelCustom(IndentChars, SeparatorChars, indentRec) return } // ModelCustom is like Model with user-defined formatting. func (r *RequestRecord) ModelCustom(indent, sep string, level uint) (out string) { var size int var sb strings.Builder for _, p := range r.Pairs { size += p.Size() } // Count sb.WriteString(strings.Repeat(indent, int(level))) sb.WriteString(fmt.Sprintf("%x", PackUint32(uint32(len(r.Pairs))))) sb.WriteString(sep) sb.WriteString(fmt.Sprintf("// Field/Value Count (%d)\n", len(r.Pairs))) // Size sb.WriteString(strings.Repeat(indent, int(level))) sb.WriteString(fmt.Sprintf("%x", PackUint32(uint32(size)))) sb.WriteString(sep) sb.WriteString(fmt.Sprintf("// Record Size (%d)\n", size)) // VALUES for idx, p := range r.Pairs { sb.WriteString(strings.Repeat(indent, int(level))) sb.WriteString( fmt.Sprintf( "// Record Group %d, Record %d, Field/Value %d (%d bytes)\n", r.rgIdx+1, r.rIdx+1, idx+1, p.Size(), ), ) sb.WriteString(p.ModelCustom(indent, sep, level+1)) } out = sb.String() return } // Resolve associates children with parents. func (r *RequestRecord) Resolve() { for idx, i := range r.Pairs { i.parent = r i.rgIdx = r.rgIdx i.rIdx = idx i.fvpidx = idx // KVP have no Resolve() method. } } // Size returns the RequestRecord's calculated size (in bytes) and updates the size field if 0. func (r *RequestRecord) Size() (size int) { if r == nil { return } // Count and Size uint32s size += PackedNumSize * 2 for _, i := range r.Pairs { size += i.Size() } if r.common == nil || r.size == 0 { r.common = &common{ size: uint32(size), } } r.size = uint32(size) return } // ToMap returns a slice of FVP maps for this Record. func (r *RequestRecord) ToMap() (m []map[string]interface{}) { m = make([]map[string]interface{}, len(r.Pairs)) for idx, p := range r.Pairs { m[idx] = p.ToMap() } return } // UnmarshalBinary populates a RequestRecord from packed bytes. func (r *RequestRecord) UnmarshalBinary(data []byte) (err error) { if data == nil || len(data) == 0 { return } var b []byte var cnt, size int var fvpNmSize, fvpValSize int var fvpBuf *bytes.Buffer var buf *bytes.Reader = bytes.NewReader(data) if r == nil { *r = RequestRecord{} } if r.common == nil { r.common = new(common) } r.size = 0 // FVP count. b = make([]byte, PackedNumSize) if _, err = buf.Read(b); err != nil { return } cnt = UnpackInt(b) // Size of record. b = make([]byte, PackedNumSize) if _, err = buf.Read(b); err != nil { return } size = UnpackInt(b) // And now we handle the FVPs themselves. b = make([]byte, size) if _, err = buf.Read(b); err != nil { return } buf = bytes.NewReader(b) r.Pairs = make([]*FieldValuePair, cnt) for idx := 0; idx < cnt; idx++ { fvpBuf = new(bytes.Buffer) // Unlike parents, the FVP needs both allocators because they're both size allocators. // FVP Name b = make([]byte, PackedNumSize) if _, err = buf.Read(b); err != nil { return } if _, err = fvpBuf.Write(b); err != nil { return } fvpNmSize = UnpackInt(b) // FVP Value b = make([]byte, PackedNumSize) if _, err = buf.Read(b); err != nil { return } if _, err = fvpBuf.Write(b); err != nil { return } fvpValSize = UnpackInt(b) if _, err = io.CopyN(fvpBuf, buf, int64(fvpNmSize+fvpValSize)); err != nil { return } r.Pairs[idx] = new(FieldValuePair) if err = r.Pairs[idx].UnmarshalBinary(fvpBuf.Bytes()); err != nil { return } } _ = r.Size() _ = size return } // getFvps returns this Record's FVP. func (r *RequestRecord) getFvps() (fvp []FVP) { fvp = make([]FVP, len(r.Pairs)) for idx, p := range r.Pairs { fvp[idx] = p } return } // getIdx returns the Record index in the parent RecordGroup. func (r *RequestRecord) getIdx() (idx int) { idx = r.rIdx return }