2 // Copyright 2019 AT&T Intellectual Property
3 // Copyright 2019 Nokia
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
21 "github.com/pkg/errors"
35 func SendJsonRmrMessage(command models.JsonCommand /*the copy is modified locally*/, xAction *[]byte, r *rmr.Service) error {
37 _, err := fmt.Sscanf(command.PackedPayload, "%x", &payload)
39 return errors.New(fmt.Sprintf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err))
41 command.PackedPayload = string(payload)
42 command.TransactionId = expandTransactionId(command.TransactionId)
43 if len(command.TransactionId) == 0 {
44 command.TransactionId = string(*xAction)
46 command.PayloadHeader = expandPayloadHeader(command.PayloadHeader, &command)
47 log.Printf("#jsonSender.SendJsonRmrMessage - command payload header: %s", command.PayloadHeader)
48 rmrMsgId, err := rmr.MessageIdToUint(command.RmrMessageType)
50 return errors.New(fmt.Sprintf("invalid rmr message id: %s", command.RmrMessageType))
52 _, err = r.SendMessage(int(rmrMsgId), command.Meid, append([]byte(command.PayloadHeader), payload...), []byte(command.TransactionId))
57 * transactionId (xAction): The value may have a fixed value or $ or <prefix>$.
58 * $ is replaced by a value generated at runtime (possibly unique per message sent).
59 * If the tag does not exist, then the mock shall use the value taken from the incoming message.
61 func expandTransactionId(id string) string {
62 if len(id) == 1 && id[0] == '$' {
63 return fmt.Sprintf("%d", incAndGetCounter())
65 if len(id) > 1 && id[len(id)-1] == '$' {
66 return fmt.Sprintf("%s%d", id[:len(id)-1], incAndGetCounter())
72 * payloadHeader: A prefix to combine with the payload that will be the message’s payload. The value may include variables of the format $<name> or #<name> where:
73 * $<name> expands to the value of <name> if it exists or the empty string if not.
74 * #<name> expands to the length of the value of <name> if it exists or omitted if not.
75 * The intention is to allow the Mock to construct the payload header required by the setup messages (ranIp|ranPort|ranName|payload len|<payload>).
76 * Example: “payloadHeader”: “$ranIp|$ranPort|$ranName|#packedPayload|”
79 func expandPayloadHeader(header string, command *models.JsonCommand) string {
80 var name strings.Builder
81 var expandedHeader strings.Builder
83 r := strings.NewReader(header)
84 ch, err := r.ReadByte()
93 ch, err = r.ReadByte() //on error ch == 0
94 if unicode.IsDigit(rune(ch)) || unicode.IsLetter(rune(ch)) {
96 name.WriteByte(byte(unicode.ToUpper(rune(ch))))
101 if fieldValue := reflect.Indirect(reflect.ValueOf(command)).FieldByName(name.String()); fieldValue.IsValid() {
102 switch fieldValue.Kind() {
104 expandedHeader.WriteString(fieldValue.String())
105 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
106 expandedHeader.WriteString(strconv.FormatInt(fieldValue.Int(), 10))
108 expandedHeader.WriteString(strconv.FormatBool(fieldValue.Bool()))
109 case reflect.Float64, reflect.Float32:
110 expandedHeader.WriteString(fmt.Sprintf("%g", fieldValue.Float()))
112 log.Fatalf("#jsonSender.expandPayloadHeader - invalid type for $%s, value must be a string, an int, a bool or a float", name.String())
121 ch, err = r.ReadByte() //on error ch == 0
122 if unicode.IsDigit(rune(ch)) || unicode.IsLetter(rune(ch)) {
124 name.WriteByte(byte(unicode.ToUpper(rune(ch))))
129 if fieldValue := reflect.Indirect(reflect.ValueOf(command)).FieldByName(name.String()); fieldValue.IsValid() {
130 if fieldValue.Kind() == reflect.String {
131 expandedHeader.WriteString(strconv.FormatInt(int64(len(fieldValue.String())), 10))
133 log.Fatalf("#jsonSender.expandPayloadHeader - invalid type for #%s, value must be a string", name.String())
141 if unicode.IsPrint(rune(ch)) {
142 expandedHeader.WriteByte(ch)
144 ch, err = r.ReadByte()
147 return expandedHeader.String()
150 func incAndGetCounter() uint64 {
151 return atomic.AddUint64(&counter, 1)
155 counter = uint64(time.Now().Unix() - 1572000000)