github.com/ronaksoft/rony@v0.16.26-0.20230807065236-1743dbfe6959/msg.go (about) 1 package rony 2 3 import ( 4 "fmt" 5 6 "github.com/goccy/go-json" 7 "github.com/ronaksoft/rony/pools" 8 "github.com/ronaksoft/rony/registry" 9 "google.golang.org/protobuf/proto" 10 "google.golang.org/protobuf/reflect/protoreflect" 11 ) 12 13 /* 14 Creation Time: 2020 - Jan - 27 15 Created by: (ehsan) 16 Maintainers: 17 1. Ehsan N. Moosa (E2) 18 Auditor: Ehsan N. Moosa (E2) 19 Copyright Ronak Software Group 2020 20 */ 21 22 //go:generate protoc -I=. -I=$GOPATH --go_out=paths=source_relative:. msg.proto options.proto 23 //go:generate protoc -I=. -I=$GOPATH --gorony_out=paths=source_relative,rony_opt=no_edge_dep:. msg.proto 24 func init() {} 25 26 /* 27 Extra methods for MessageEnvelope 28 */ 29 30 func (x *MessageEnvelope) Fill(reqID uint64, constructor uint64, p proto.Message, kvs ...*KeyValue) { 31 x.RequestID = reqID 32 x.Constructor = constructor 33 34 // Fill Header 35 if cap(x.Header) >= len(kvs) { 36 x.Header = x.Header[:len(kvs)] 37 } else { 38 x.Header = make([]*KeyValue, len(kvs)) 39 } 40 for idx, kv := range kvs { 41 if x.Header[idx] == nil { 42 x.Header[idx] = &KeyValue{} 43 } 44 kv.DeepCopy(x.Header[idx]) 45 } 46 47 // Fill Message 48 buf := pools.Buffer.FromProto(p) 49 x.Message = append(x.Message[:0], *buf.Bytes()...) 50 pools.Buffer.Put(buf) 51 } 52 53 func (x *MessageEnvelope) Get(key, defaultVal string) string { 54 for _, kv := range x.Header { 55 if kv.Key == key { 56 return kv.Value 57 } 58 } 59 60 return defaultVal 61 } 62 63 func (x *MessageEnvelope) Set(KVs ...*KeyValue) { 64 x.Header = append(x.Header[:0], KVs...) 65 } 66 67 func (x *MessageEnvelope) Append(key, val string) { 68 x.Header = append(x.Header, &KeyValue{ 69 Key: key, 70 Value: val, 71 }) 72 } 73 74 func (x *MessageEnvelope) Unwrap() (protoreflect.Message, error) { 75 var ( 76 m IMessage 77 err error 78 ) 79 if x.JsonEncoded { 80 m, err = registry.UnwrapJSON(x) 81 } else { 82 m, err = registry.Unwrap(x) 83 } 84 if err != nil { 85 return nil, err 86 } 87 88 return m.ProtoReflect(), nil 89 } 90 91 // Carrier wraps the MessageEnvelope into an envelope carrier which is useful for cross-cutting 92 // tracing. With this method, instrumentation packages can pass the trace info into the wire. 93 // Rony has builtin support, and you do not need to use this function explicitly. 94 // Check edge.WithTracer option to enable tracing 95 func (x *MessageEnvelope) Carrier() *envelopeCarrier { 96 return &envelopeCarrier{ 97 e: x, 98 } 99 } 100 101 func (x *MessageEnvelope) MarshalJSON() ([]byte, error) { 102 var ( 103 m registry.Message 104 err error 105 ) 106 if x.JsonEncoded { 107 m, err = registry.UnwrapJSON(x) 108 } else { 109 m, err = registry.Unwrap(x) 110 } 111 if err != nil { 112 return nil, err 113 } 114 115 je := MessageEnvelopeJSON{ 116 RequestID: x.RequestID, 117 Constructor: registry.C(x.Constructor), 118 } 119 120 if len(x.Header) > 0 { 121 je.Header = map[string]string{} 122 for _, kv := range x.Header { 123 je.Header[kv.Key] = kv.Value 124 } 125 } 126 127 je.Message, err = m.MarshalJSON() 128 if err != nil { 129 return nil, err 130 } 131 132 return json.Marshal(je) 133 } 134 135 func (x *MessageEnvelope) UnmarshalJSON(b []byte) error { 136 je := MessageEnvelopeJSON{} 137 if err := json.Unmarshal(b, &je); err != nil { 138 return err 139 } 140 141 x.RequestID = je.RequestID 142 x.Constructor = registry.N(je.Constructor) 143 x.Message = je.Message 144 x.JsonEncoded = true 145 for k, v := range je.Header { 146 x.Append(k, v) 147 } 148 149 return nil 150 } 151 152 // envelopeCarrier is an adapted for MessageEnvelope to implement propagation.TextMapCarrier interface 153 type envelopeCarrier struct { 154 e *MessageEnvelope 155 } 156 157 func (e envelopeCarrier) Get(key string) string { 158 return e.e.Get(key, "") 159 } 160 161 func (e envelopeCarrier) Set(key string, value string) { 162 e.e.Append(key, value) 163 } 164 165 func (e envelopeCarrier) Keys() []string { 166 var keys = make([]string, len(e.e.Header)) 167 for idx := range e.e.Header { 168 keys[idx] = e.e.Header[idx].Key 169 } 170 171 return keys 172 } 173 174 /* 175 Extra methods for MessageContainer 176 */ 177 func (x *MessageContainer) Add(reqID uint64, constructor uint64, p proto.Message, kvs ...*KeyValue) { 178 me := PoolMessageEnvelope.Get() 179 me.Fill(reqID, constructor, p, kvs...) 180 x.Envelopes = append(x.Envelopes, me) 181 x.Length += 1 182 } 183 184 /* 185 Extra methods for Error 186 */ 187 func (x *Error) Error() string { 188 if len(x.Description) > 0 { 189 return fmt.Sprintf("%s:%s (%s)", x.Code, x.Items, x.Description) 190 } else { 191 return fmt.Sprintf("%s:%s", x.Code, x.Items) 192 } 193 } 194 195 func (x *Error) Expand() (string, string) { 196 return x.Code, x.Items 197 } 198 199 func (x *Error) ToEnvelope(me *MessageEnvelope) { 200 // me.Fill(me.RequestID, C_Error, x) 201 } 202 203 // MessageEnvelopeJSON is the JSON representation of MessageEnvelope. 204 type MessageEnvelopeJSON struct { 205 RequestID uint64 `json:"requestId"` 206 Header map[string]string `json:"header,omitempty"` 207 Constructor string `json:"cmd"` 208 Message json.RawMessage `json:"message"` 209 }