blob: f471203b2b048c3130d9688d86d14e940c6deb15 [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package iggcon
import (
"bytes"
"encoding/binary"
"errors"
"io"
)
const MaxNodesPerCluster = 64
type ClusterMetadata struct {
Name string
Nodes []ClusterNode
}
// BufferSize returns total serialized size.
func (m *ClusterMetadata) BufferSize() int {
nodesSize := 0
for i := range m.Nodes {
nodesSize += m.Nodes[i].BufferSize()
}
return 4 + len(m.Name) + 4 + nodesSize
}
// MarshalBinary implements encoding.BinaryMarshaler.
func (m *ClusterMetadata) MarshalBinary() ([]byte, error) {
buf := bytes.NewBuffer(make([]byte, 0, m.BufferSize()))
nameBytes := []byte(m.Name)
if err := binary.Write(buf, binary.LittleEndian, uint32(len(nameBytes))); err != nil {
return nil, err
}
if _, err := buf.Write(nameBytes); err != nil {
return nil, err
}
if err := binary.Write(buf, binary.LittleEndian, uint32(len(m.Nodes))); err != nil {
return nil, err
}
for i := range m.Nodes {
data, err := m.Nodes[i].MarshalBinary()
if err != nil {
return nil, err
}
buf.Write(data)
}
return buf.Bytes(), nil
}
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
func (m *ClusterMetadata) UnmarshalBinary(data []byte) error {
if len(data) < 8 {
return errors.New("data too short for ClusterMetadata")
}
r := bytes.NewReader(data)
var nameLen uint32
if err := binary.Read(r, binary.LittleEndian, &nameLen); err != nil {
return err
}
if int(nameLen) > r.Len() {
return errors.New("invalid name length")
}
nameb := make([]byte, nameLen)
if _, err := r.Read(nameb); err != nil {
return err
}
m.Name = string(nameb)
var nodesCount uint32
if err := binary.Read(r, binary.LittleEndian, &nodesCount); err != nil {
return err
}
if nodesCount > MaxNodesPerCluster {
return errors.New("invalid number of nodes per cluster")
}
m.Nodes = make([]ClusterNode, 0, nodesCount)
for i := uint32(0); i < nodesCount; i++ {
// remaining bytes for this node are unknown up-front; parse via ClusterNode.UnmarshalBinary on the remaining slice
remaining := data[len(data)-r.Len():]
var node ClusterNode
if err := node.UnmarshalBinary(remaining); err != nil {
return err
}
m.Nodes = append(m.Nodes, node)
// advance reader by the node's serialized size
if _, err := r.Seek(int64(node.BufferSize()), io.SeekCurrent); err != nil {
return err
}
}
return nil
}