github.com/cyverse/go-irodsclient@v0.13.2/irods/message/message.go (about)

     1  package message
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/xml"
     6  
     7  	"golang.org/x/xerrors"
     8  )
     9  
    10  // MessageType is a message type
    11  type MessageType string
    12  
    13  // IRODSMessageHeader defines a message header
    14  type IRODSMessageHeader struct {
    15  	XMLName    xml.Name    `xml:"MsgHeader_PI"`
    16  	Type       MessageType `xml:"type"`
    17  	MessageLen uint32      `xml:"msgLen"`
    18  	ErrorLen   uint32      `xml:"errorLen"`
    19  	BsLen      uint32      `xml:"bsLen"`
    20  	IntInfo    int32       `xml:"intInfo"`
    21  }
    22  
    23  // IRODSMessageBody defines a message body
    24  type IRODSMessageBody struct {
    25  	Type    MessageType
    26  	Message []byte
    27  	Error   []byte
    28  	Bs      []byte
    29  	IntInfo int32
    30  }
    31  
    32  // IRODSMessage defines a message
    33  type IRODSMessage struct {
    34  	Header *IRODSMessageHeader
    35  	Body   *IRODSMessageBody
    36  }
    37  
    38  // IRODSMessageSerializationInterface is an interface for serializaing/deserializing of message
    39  type IRODSMessageSerializationInterface interface {
    40  	GetBytes() ([]byte, error)
    41  	FromBytes(bodyBytes []byte, bsBytes []byte) error
    42  }
    43  
    44  // MakeIRODSMessageHeader makes a message header
    45  func MakeIRODSMessageHeader(messageType MessageType, messageLen uint32, errorLen uint32, bsLen uint32, intInfo int32) *IRODSMessageHeader {
    46  	return &IRODSMessageHeader{
    47  		Type:       messageType,
    48  		MessageLen: messageLen,
    49  		ErrorLen:   errorLen,
    50  		BsLen:      bsLen,
    51  		IntInfo:    intInfo,
    52  	}
    53  }
    54  
    55  // GetBytes returns byte array
    56  func (header *IRODSMessageHeader) GetBytes() ([]byte, error) {
    57  	xmlBytes, err := xml.Marshal(header)
    58  	if err != nil {
    59  		return nil, xerrors.Errorf("failed to marshal irods message to xml: %w", err)
    60  	}
    61  	return xmlBytes, nil
    62  }
    63  
    64  // FromBytes returns struct from bytes
    65  func (header *IRODSMessageHeader) FromBytes(bytes []byte) error {
    66  	err := xml.Unmarshal(bytes, header)
    67  	if err != nil {
    68  		return xerrors.Errorf("failed to unmarshal xml to irods message: %w", err)
    69  	}
    70  	return nil
    71  }
    72  
    73  // GetBytes returns byte array
    74  func (body *IRODSMessageBody) GetBytes() ([]byte, error) {
    75  	messageBuffer := &bytes.Buffer{}
    76  	if body.Message != nil {
    77  		_, err := messageBuffer.Write(body.Message)
    78  		if err != nil {
    79  			return nil, xerrors.Errorf("failed to write to message buffer: %w", err)
    80  		}
    81  	}
    82  
    83  	if body.Error != nil {
    84  		_, err := messageBuffer.Write(body.Error)
    85  		if err != nil {
    86  			return nil, xerrors.Errorf("failed to write to message buffer: %w", err)
    87  		}
    88  	}
    89  
    90  	if body.Bs != nil {
    91  		_, err := messageBuffer.Write(body.Bs)
    92  		if err != nil {
    93  			return nil, xerrors.Errorf("failed to write to message buffer: %w", err)
    94  		}
    95  	}
    96  
    97  	return messageBuffer.Bytes(), nil
    98  }
    99  
   100  // GetBytesWithoutBS returns byte array of body without BS
   101  func (body *IRODSMessageBody) GetBytesWithoutBS() ([]byte, error) {
   102  	messageBuffer := new(bytes.Buffer)
   103  	if body.Message != nil {
   104  		_, err := messageBuffer.Write(body.Message)
   105  		if err != nil {
   106  			return nil, xerrors.Errorf("failed to write to message buffer: %w", err)
   107  		}
   108  	}
   109  
   110  	if body.Error != nil {
   111  		_, err := messageBuffer.Write(body.Error)
   112  		if err != nil {
   113  			return nil, xerrors.Errorf("failed to write to message buffer: %w", err)
   114  		}
   115  	}
   116  
   117  	return messageBuffer.Bytes(), nil
   118  }
   119  
   120  // FromBytes returns struct from bytes
   121  func (body *IRODSMessageBody) FromBytes(header *IRODSMessageHeader, bodyBytes []byte, bsBytes []byte) error {
   122  	if len(bodyBytes) < (int(header.MessageLen) + int(header.ErrorLen)) {
   123  		return xerrors.Errorf("bodyBytes given is too short to be parsed")
   124  	}
   125  
   126  	if len(bsBytes) < int(header.BsLen) {
   127  		return xerrors.Errorf("bsBytes given is too short to be parsed")
   128  	}
   129  
   130  	offset := 0
   131  	body.Message = bodyBytes[offset : offset+int(header.MessageLen)]
   132  
   133  	offset += int(header.MessageLen)
   134  	body.Error = bodyBytes[offset : offset+int(header.ErrorLen)]
   135  
   136  	offset += int(header.ErrorLen)
   137  	body.Bs = bsBytes[:int(header.BsLen)]
   138  
   139  	return nil
   140  }
   141  
   142  // BuildHeader returns IRODSMessageHeader
   143  func (body *IRODSMessageBody) BuildHeader() (*IRODSMessageHeader, error) {
   144  	messageLen := 0
   145  	errorLen := 0
   146  	bsLen := 0
   147  
   148  	if body.Message != nil {
   149  		messageLen = len(body.Message)
   150  	}
   151  
   152  	if body.Error != nil {
   153  		errorLen = len(body.Error)
   154  	}
   155  
   156  	if body.Bs != nil {
   157  		bsLen = len(body.Bs)
   158  	}
   159  
   160  	h := MakeIRODSMessageHeader(body.Type, uint32(messageLen), uint32(errorLen), uint32(bsLen), body.IntInfo)
   161  	return h, nil
   162  }