v1.0.0
Initial release.
This commit is contained in:
393
funcs_responserecord.go
Normal file
393
funcs_responserecord.go
Normal file
@@ -0,0 +1,393 @@
|
||||
package wireproto
|
||||
|
||||
import (
|
||||
`bytes`
|
||||
`fmt`
|
||||
`io`
|
||||
`strings`
|
||||
)
|
||||
|
||||
// GetParent returns the parent RecordGroup.
|
||||
func (r *ResponseRecord) GetParent() (rg RecordGroup) {
|
||||
|
||||
rg = r.parent
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalBinary renders a ResponseRecord into a byte-packed format.
|
||||
func (r *ResponseRecord) MarshalBinary() (data []byte, err error) {
|
||||
|
||||
var b []byte
|
||||
var recSize int
|
||||
var buf *bytes.Buffer = new(bytes.Buffer)
|
||||
|
||||
_ = r.Size()
|
||||
|
||||
// KVP Count
|
||||
if _, err = buf.Write(PackInt(len(r.Pairs))); err != nil {
|
||||
return
|
||||
}
|
||||
for _, i := range r.Pairs {
|
||||
recSize += i.Size()
|
||||
}
|
||||
// KVP Size
|
||||
if _, err = buf.Write(PackInt(recSize)); err != nil {
|
||||
return
|
||||
}
|
||||
// Original/Request Size
|
||||
if _, err = buf.Write(PackInt(r.OriginalRecord.Size())); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, i := range r.Pairs {
|
||||
if b, err = i.MarshalBinary(); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = buf.Write(b); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if r.OriginalRecord != nil {
|
||||
if b, err = r.OriginalRecord.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 *ResponseRecord) Model() (out string) {
|
||||
|
||||
out = r.ModelCustom(IndentChars, SeparatorChars, indentRec)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ModelCustom is like Model with user-defined formatting.
|
||||
func (r *ResponseRecord) 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))
|
||||
// Request Record Size
|
||||
sb.WriteString(strings.Repeat(indent, int(level)))
|
||||
sb.WriteString(fmt.Sprintf("%x", PackUint32(uint32(r.OriginalRecord.Size()))))
|
||||
sb.WriteString(sep)
|
||||
sb.WriteString(fmt.Sprintf("// Request Record Size (%d)\n", r.OriginalRecord.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))
|
||||
}
|
||||
|
||||
// REQUEST
|
||||
sb.WriteString(strings.Repeat(indent, int(level)))
|
||||
if r.OriginalRecord == nil {
|
||||
sb.WriteString("// (No Original Request Record Attached)\n")
|
||||
} else {
|
||||
sb.WriteString(
|
||||
fmt.Sprintf("// Record Group %d, Record %d (REQUEST RECORD) (%d bytes)\n", r.rgIdx+1, r.rIdx+1, r.OriginalRecord.Size()),
|
||||
)
|
||||
sb.WriteString(r.OriginalRecord.ModelCustom(indent, sep, level+1))
|
||||
}
|
||||
|
||||
out = sb.String()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Resolve associates children with parents.
|
||||
func (r *ResponseRecord) 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 ResponseRecord's calculated size (in bytes) and updates the size field if 0.
|
||||
|
||||
Note that it *includes* the size of ResponseRecord.OriginalRecord and its allocator.
|
||||
*/
|
||||
func (r *ResponseRecord) Size() (size int) {
|
||||
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Count and Size uint32s, plus Size for response record.
|
||||
size += PackedNumSize * 3
|
||||
|
||||
for _, p := range r.Pairs {
|
||||
size += p.Size()
|
||||
}
|
||||
|
||||
if r.OriginalRecord != nil {
|
||||
size += r.OriginalRecord.Size()
|
||||
}
|
||||
|
||||
if r.common == nil {
|
||||
r.common = new(common)
|
||||
}
|
||||
|
||||
r.size = uint32(size)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SizeNoResp is like Size but does not include the size of the ResponseRecord.OriginalRecord nor its allocator.
|
||||
|
||||
It does *not* update the internal size field.
|
||||
*/
|
||||
func (r *ResponseRecord) SizeNoResp() (size int) {
|
||||
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Count and Size uint32s
|
||||
size += PackedNumSize * 2
|
||||
|
||||
for _, p := range r.Pairs {
|
||||
size += p.Size()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ToMap returns a slice of FVP maps for this Record.
|
||||
func (r *ResponseRecord) 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 ResponseRecord from packed bytes.
|
||||
func (r *ResponseRecord) UnmarshalBinary(data []byte) (err error) {
|
||||
|
||||
if data == nil || len(data) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var b []byte
|
||||
var cnt, size, reqSize int
|
||||
var fvpNmSize, fvpValSize int
|
||||
var fvpBuf *bytes.Buffer
|
||||
var recBuf *bytes.Buffer = new(bytes.Buffer)
|
||||
var origBuf *bytes.Buffer = new(bytes.Buffer)
|
||||
var buf *bytes.Reader = bytes.NewReader(data)
|
||||
|
||||
if r == nil {
|
||||
*r = ResponseRecord{}
|
||||
}
|
||||
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)
|
||||
|
||||
// Size of original record.
|
||||
b = make([]byte, PackedNumSize)
|
||||
if _, err = buf.Read(b); err != nil {
|
||||
return
|
||||
}
|
||||
reqSize = UnpackInt(b)
|
||||
|
||||
// And split out the FVPs and original record.
|
||||
if _, err = io.CopyN(recBuf, buf, int64(size)); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = io.CopyN(origBuf, buf, int64(reqSize)); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
r.Pairs = make([]*FieldValuePair, cnt)
|
||||
|
||||
for idx := 0; idx < cnt; idx++ {
|
||||
fvpBuf = new(bytes.Buffer)
|
||||
|
||||
// Field name size
|
||||
b = make([]byte, PackedNumSize)
|
||||
if _, err = recBuf.Read(b); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = fvpBuf.Write(b); err != nil {
|
||||
return
|
||||
}
|
||||
fvpNmSize = UnpackInt(b)
|
||||
|
||||
// Field value size
|
||||
b = make([]byte, PackedNumSize)
|
||||
if _, err = recBuf.Read(b); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = fvpBuf.Write(b); err != nil {
|
||||
return
|
||||
}
|
||||
fvpValSize = UnpackInt(b)
|
||||
|
||||
if _, err = io.CopyN(fvpBuf, recBuf, int64(fvpNmSize+fvpValSize)); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
r.Pairs[idx] = new(FieldValuePair)
|
||||
if err = r.Pairs[idx].UnmarshalBinary(fvpBuf.Bytes()); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if reqSize != 0 {
|
||||
r.OriginalRecord = new(RequestRecord)
|
||||
if err = r.OriginalRecord.UnmarshalBinary(origBuf.Bytes()); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_ = r.Size()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// getFvps returns this Record's FVP.
|
||||
func (r *ResponseRecord) 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 *ResponseRecord) getIdx() (idx int) {
|
||||
|
||||
idx = r.rIdx
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
recToFVPs returns a slice of FieldValuePair from a Record. Mostly used for ResponseFieldValuePair.OriginalRecord.
|
||||
|
||||
data should be a Record data structure.
|
||||
*/
|
||||
func (r *ResponseRecord) recToFVPs(data []byte) (fvps []*FieldValuePair, err error) {
|
||||
|
||||
var b []byte
|
||||
var fvpCnt, recSize int
|
||||
var fvpNmSize, fvpValSize int
|
||||
var fvpBuf *bytes.Buffer
|
||||
var buf *bytes.Reader = bytes.NewReader(data)
|
||||
|
||||
// Number of FVPs
|
||||
b = make([]byte, PackedNumSize)
|
||||
if _, err = buf.Read(b); err != nil {
|
||||
return
|
||||
}
|
||||
fvpCnt = UnpackInt(b)
|
||||
fvps = make([]*FieldValuePair, fvpCnt)
|
||||
|
||||
// Size of record
|
||||
b = make([]byte, PackedNumSize)
|
||||
if _, err = buf.Read(b); err != nil {
|
||||
return
|
||||
}
|
||||
recSize = UnpackInt(b)
|
||||
|
||||
// And create a new buffer from the remainder.
|
||||
b = make([]byte, recSize)
|
||||
if _, err = buf.Read(b); err != nil {
|
||||
return
|
||||
}
|
||||
buf = bytes.NewReader(b)
|
||||
|
||||
for idx := 0; idx < fvpCnt; idx++ {
|
||||
fvpBuf = new(bytes.Buffer)
|
||||
|
||||
// Get the fvp name size
|
||||
b = make([]byte, PackedNumSize)
|
||||
if _, err = buf.Read(b); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = fvpBuf.Write(b); err != nil {
|
||||
return
|
||||
}
|
||||
fvpNmSize = UnpackInt(b)
|
||||
|
||||
// Get the fvp value size
|
||||
b = make([]byte, PackedNumSize)
|
||||
if _, err = buf.Read(b); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = fvpBuf.Write(b); err != nil {
|
||||
return
|
||||
}
|
||||
fvpValSize = UnpackInt(b)
|
||||
|
||||
b = make([]byte, fvpNmSize+fvpValSize)
|
||||
if _, err = buf.Read(b); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = fvpBuf.Write(b); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fvps[idx] = new(FieldValuePair)
|
||||
if err = fvps[idx].UnmarshalBinary(fvpBuf.Bytes()); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user