github.com/vmware/transport-go@v1.3.4/model/message.go (about) 1 // Copyright 2019-2020 VMware, Inc. 2 // SPDX-License-Identifier: BSD-2-Clause 3 4 package model 5 6 import ( 7 "encoding/json" 8 "errors" 9 "fmt" 10 "github.com/google/uuid" 11 "github.com/mitchellh/mapstructure" 12 "reflect" 13 ) 14 15 // Direction int defining which way messages are travelling on a Channel. 16 type Direction int 17 18 const ( 19 RequestDir Direction = 0 20 ResponseDir Direction = 1 21 ErrorDir Direction = 2 22 ) 23 24 // A Message is the encapsulation of the event sent on the bus. 25 // It holds a Direction, errors, a Payload and more. 26 type Message struct { 27 Id *uuid.UUID `json:"id"` // message identifier 28 DestinationId *uuid.UUID `json:"destinationId"` // destinationId (targeted recipient) 29 Channel string `json:"channel"` // reference to channel message was sent on. 30 Destination string `json:"destination"` // destination message was sent to (if galactic) 31 Payload interface{} `json:"payload"` 32 Error error `json:"error"` 33 Direction Direction `json:"direction"` 34 Headers []MessageHeader `json:"headers"` 35 } 36 37 // A Message header can contain any meta data. 38 type MessageHeader struct { 39 Label string 40 Value string 41 } 42 43 // CastPayloadToType converts the raw interface{} typed Payload into the 44 // specified object passed as an argument. 45 func (m *Message) CastPayloadToType(typ interface{}) error { 46 var unwrappedResponse Response 47 48 // assert pointer type 49 typVal := reflect.ValueOf(typ) 50 if typVal.Kind() != reflect.Ptr { 51 return fmt.Errorf("CastPayloadToType: invalid argument. argument should be the address of an object") 52 } 53 54 // nil-check 55 if typVal.IsNil() { 56 return fmt.Errorf("CastPayloadToType: cannot cast to nil") 57 } 58 59 // if message.Payload is already of *Response type, handle it here. 60 if resp, ok := m.Payload.(*Response); ok { 61 return decodeResponsePaylod(resp, typ) 62 } 63 64 // otherwise, unmrashal message.Payload into Response, then decode response.Payload 65 if err := json.Unmarshal(m.Payload.([]byte), &unwrappedResponse); err != nil { 66 return fmt.Errorf("CastPayloadToType: failed to unmarshal payload %v: %w", m.Payload, err) 67 } 68 69 return decodeResponsePaylod(&unwrappedResponse, typ) 70 } 71 72 // decodeResponsePaylod tries to unpack Response.Payload into typ. 73 func decodeResponsePaylod(resp *Response, typ interface{}) error { 74 if resp.Error { 75 return errors.New(resp.ErrorMessage) 76 } 77 return mapstructure.Decode(resp.Payload, typ) 78 }