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  }