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 }