github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/p2p/p2putil/message.go (about) 1 package p2putil 2 3 import ( 4 "encoding/json" 5 "math/rand" 6 "time" 7 8 peer "github.com/libp2p/go-libp2p-core/peer" 9 ) 10 11 // MsgType indicates the type of message being sent 12 type MsgType string 13 14 // String implements the Stringer interface for MsgType 15 func (mt MsgType) String() string { 16 return string(mt) 17 } 18 19 // Message is a serializable/encodable object that we send & receive on a Stream. 20 type Message struct { 21 Type MsgType 22 ID string 23 Created time.Time 24 Deadline time.Time 25 // peer that originated this message 26 Initiator peer.ID 27 // Headers proxies the concept of HTTP headers, but with no 28 // mandatory fields. It's intended to be small & simple on purpose 29 // In the future we can upgrade this to map[string]interface{} while keeping 30 // backward compatibility 31 Headers map[string]string 32 // Body carries the payload of a message, if any 33 Body []byte 34 // provider is who sent this message 35 // not transmitted over the wire, but 36 // instead populated by WrapStream 37 provider peer.ID 38 } 39 40 // Update returns a new message with an updated body 41 func (m Message) Update(body []byte) Message { 42 return Message{ 43 Type: m.Type, 44 ID: m.ID, 45 Headers: m.Headers, 46 Created: m.Created, 47 Deadline: m.Deadline, 48 Initiator: m.Initiator, 49 Body: body, 50 } 51 } 52 53 // UpdateJSON updates a messages by JSON-encoding a body 54 func (m Message) UpdateJSON(body interface{}) (Message, error) { 55 data, err := json.Marshal(body) 56 return m.Update(data), err 57 } 58 59 // NewMessage creates a message. provided initiator should always be the peerID 60 // of the local node 61 func NewMessage(initiator peer.ID, t MsgType, body []byte) Message { 62 return Message{ 63 ID: NewMessageID(), 64 Initiator: initiator, 65 Created: time.Now(), 66 Deadline: time.Now().Add(time.Minute * 2), 67 Type: t, 68 Headers: map[string]string{}, 69 Body: body, 70 } 71 } 72 73 // WithHeaders adds a sequence of key,value,key,value as headers 74 func (m Message) WithHeaders(keyval ...string) Message { 75 headers := map[string]string{} 76 for i := 0; i < len(keyval)-1; i = i + 2 { 77 headers[keyval[i]] = keyval[i+1] 78 } 79 return Message{ 80 ID: m.ID, 81 Initiator: m.Initiator, 82 Type: m.Type, 83 Headers: headers, 84 Body: m.Body, 85 } 86 } 87 88 // Header gets a header value for a given key 89 func (m Message) Header(key string) (value string) { 90 if m.Headers == nil { 91 return "" 92 } 93 return m.Headers[key] 94 } 95 96 // NewJSONBodyMessage is a convenience wrapper for json-encoding a message 97 func NewJSONBodyMessage(initiator peer.ID, t MsgType, body interface{}) (Message, error) { 98 data, err := json.Marshal(body) 99 return NewMessage(initiator, t, data), err 100 } 101 102 var alpharunes = []rune("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") 103 104 // NewMessageID generates a random message identifier 105 // TODO - replace with UUIDs 106 func NewMessageID() string { 107 b := make([]rune, 10) 108 for i := range b { 109 b[i] = alpharunes[rand.Intn(len(alpharunes))] 110 } 111 return string(b) 112 }