github.com/safing/portbase@v0.19.5/api/client/message.go (about)

     1  package client
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  
     7  	"github.com/tevino/abool"
     8  
     9  	"github.com/safing/portbase/container"
    10  	"github.com/safing/portbase/formats/dsd"
    11  )
    12  
    13  // ErrMalformedMessage is returned when a malformed message was encountered.
    14  var ErrMalformedMessage = errors.New("malformed message")
    15  
    16  // Message is an API message.
    17  type Message struct {
    18  	OpID     string
    19  	Type     string
    20  	Key      string
    21  	RawValue []byte
    22  	Value    interface{}
    23  	sent     *abool.AtomicBool
    24  }
    25  
    26  // ParseMessage parses the given raw data and returns a Message.
    27  func ParseMessage(data []byte) (*Message, error) {
    28  	parts := bytes.SplitN(data, apiSeperatorBytes, 4)
    29  	if len(parts) < 2 {
    30  		return nil, ErrMalformedMessage
    31  	}
    32  
    33  	m := &Message{
    34  		OpID: string(parts[0]),
    35  		Type: string(parts[1]),
    36  	}
    37  
    38  	switch m.Type {
    39  	case MsgOk, MsgUpdate, MsgNew:
    40  		// parse key and data
    41  		//    127|ok|<key>|<data>
    42  		//    127|upd|<key>|<data>
    43  		//    127|new|<key>|<data>
    44  		if len(parts) != 4 {
    45  			return nil, ErrMalformedMessage
    46  		}
    47  		m.Key = string(parts[2])
    48  		m.RawValue = parts[3]
    49  	case MsgDelete:
    50  		// parse key
    51  		//    127|del|<key>
    52  		if len(parts) != 3 {
    53  			return nil, ErrMalformedMessage
    54  		}
    55  		m.Key = string(parts[2])
    56  	case MsgWarning, MsgError:
    57  		// parse message
    58  		//    127|error|<message>
    59  		//    127|warning|<message> // error with single record, operation continues
    60  		if len(parts) != 3 {
    61  			return nil, ErrMalformedMessage
    62  		}
    63  		m.Key = string(parts[2])
    64  	case MsgDone, MsgSuccess:
    65  		// nothing more to do
    66  		//    127|success
    67  		//    127|done
    68  	}
    69  
    70  	return m, nil
    71  }
    72  
    73  // Pack serializes a message into a []byte slice.
    74  func (m *Message) Pack() ([]byte, error) {
    75  	c := container.New([]byte(m.OpID), apiSeperatorBytes, []byte(m.Type))
    76  
    77  	if m.Key != "" {
    78  		c.Append(apiSeperatorBytes)
    79  		c.Append([]byte(m.Key))
    80  		if len(m.RawValue) > 0 {
    81  			c.Append(apiSeperatorBytes)
    82  			c.Append(m.RawValue)
    83  		} else if m.Value != nil {
    84  			var err error
    85  			m.RawValue, err = dsd.Dump(m.Value, dsd.JSON)
    86  			if err != nil {
    87  				return nil, err
    88  			}
    89  			c.Append(apiSeperatorBytes)
    90  			c.Append(m.RawValue)
    91  		}
    92  	}
    93  
    94  	return c.CompileData(), nil
    95  }