func (nn *NNet) SendBytesRelayAsync(data, key []byte) (bool, error) {
	msg, err := nn.NewRelayBytesMessage(data, nn.GetLocalNode().Id, key)
	if err != nil {
		return false, err
	}
	return nn.SendMessageAsync(msg, protobuf.RELAY)
}
SendBytesRelayAsync sends bytes data to the remote node that has smallest
distance to the key, returns if send success (which is true if successfully
send message to at least one next hop), and aggregated error during message
sending
package nnet
import (
	"time"
	"github.com/gogo/protobuf/proto"
	"github.com/nknorg/nnet/message"
	"github.com/nknorg/nnet/node"
	"github.com/nknorg/nnet/protobuf"
)
func (nn *NNet) NewDirectBytesMessage(data []byte) (*protobuf.Message, error) {
	id, err := message.GenID(nn.GetLocalNode().MessageIDBytes)
	if err != nil {
		return nil, err
	}
	msgBody := &protobuf.Bytes{
		Data: data,
	}
	buf, err := proto.Marshal(msgBody)
	if err != nil {
		return nil, err
	}
	msg := &protobuf.Message{
		MessageType: protobuf.BYTES,
		RoutingType: protobuf.DIRECT,
		MessageId:   id,
		Message:     buf,
	}
	return msg, nil
}
func (nn *NNet) NewRelayBytesMessage(data, srcID, key []byte) (*protobuf.Message, error) {
	id, err := message.GenID(nn.GetLocalNode().MessageIDBytes)
	if err != nil {
		return nil, err
	}
	msgBody := &protobuf.Bytes{
		Data: data,
	}
	buf, err := proto.Marshal(msgBody)
	if err != nil {
		return nil, err
	}
	msg := &protobuf.Message{
		MessageType: protobuf.BYTES,
		RoutingType: protobuf.RELAY,
		MessageId:   id,
		Message:     buf,
		SrcId:       srcID,
		DestId:      key,
	}
	return msg, nil
}
func (nn *NNet) NewBroadcastBytesMessage(data, srcID []byte, routingType protobuf.RoutingType) (*protobuf.Message, error) {
	id, err := message.GenID(nn.GetLocalNode().MessageIDBytes)
	if err != nil {
		return nil, err
	}
	msgBody := &protobuf.Bytes{
		Data: data,
	}
	buf, err := proto.Marshal(msgBody)
	if err != nil {
		return nil, err
	}
	msg := &protobuf.Message{
		MessageType: protobuf.BYTES,
		RoutingType: routingType,
		MessageId:   id,
		Message:     buf,
		SrcId:       srcID,
	}
	return msg, nil
}
func (nn *NNet) SendBytesDirectAsync(data []byte, remoteNode *node.RemoteNode) error {
	msg, err := nn.NewDirectBytesMessage(data)
	if err != nil {
		return err
	}
	return remoteNode.SendMessageAsync(msg)
}
func (nn *NNet) SendBytesDirectSync(data []byte, remoteNode *node.RemoteNode) ([]byte, *node.RemoteNode, error) {
	return nn.SendBytesDirectSyncWithTimeout(data, remoteNode, 0)
}
func (nn *NNet) SendBytesDirectSyncWithTimeout(data []byte, remoteNode *node.RemoteNode, replyTimeout time.Duration) ([]byte, *node.RemoteNode, error) {
	msg, err := nn.NewDirectBytesMessage(data)
	if err != nil {
		return nil, nil, err
	}
	reply, err := remoteNode.SendMessageSync(msg, replyTimeout)
	if err != nil {
		return nil, nil, err
	}
	replyBody := &protobuf.Bytes{}
	err = proto.Unmarshal(reply.Msg.Message, replyBody)
	if err != nil {
		return nil, reply.RemoteNode, err
	}
	return replyBody.Data, reply.RemoteNode, nil
}
func (nn *NNet) SendBytesDirectReply(replyToID, data []byte, remoteNode *node.RemoteNode) error {
	msg, err := nn.NewDirectBytesMessage(data)
	if err != nil {
		return err
	}
	msg.ReplyToId = replyToID
	return remoteNode.SendMessageAsync(msg)
}