dubbo.apache.org/dubbo-go/v3@v3.1.1/protocol/invocation/rpcinvocation.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 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. 16 */ 17 18 package invocation 19 20 import ( 21 "context" 22 "reflect" 23 "strings" 24 "sync" 25 ) 26 27 import ( 28 "google.golang.org/grpc/metadata" 29 ) 30 31 import ( 32 "dubbo.apache.org/dubbo-go/v3/common" 33 "dubbo.apache.org/dubbo-go/v3/common/constant" 34 "dubbo.apache.org/dubbo-go/v3/protocol" 35 ) 36 37 var _ protocol.Invocation = (*RPCInvocation)(nil) 38 39 // todo: is it necessary to separate fields of consumer(provider) from RPCInvocation 40 // nolint 41 type RPCInvocation struct { 42 methodName string 43 // Parameter Type Names. It is used to specify the parameterType 44 parameterTypeNames []string 45 parameterTypes []reflect.Type 46 47 parameterValues []reflect.Value 48 arguments []interface{} 49 reply interface{} 50 callBack interface{} 51 attachments map[string]interface{} 52 // Refer to dubbo 2.7.6. It is different from attachment. It is used in internal process. 53 attributes map[string]interface{} 54 invoker protocol.Invoker 55 lock sync.RWMutex 56 } 57 58 // NewRPCInvocation creates a RPC invocation. 59 func NewRPCInvocation(methodName string, arguments []interface{}, attachments map[string]interface{}) *RPCInvocation { 60 return &RPCInvocation{ 61 methodName: methodName, 62 arguments: arguments, 63 attachments: attachments, 64 attributes: make(map[string]interface{}, 8), 65 } 66 } 67 68 // NewRPCInvocationWithOptions creates a RPC invocation with @opts. 69 func NewRPCInvocationWithOptions(opts ...option) *RPCInvocation { 70 invo := &RPCInvocation{} 71 for _, opt := range opts { 72 opt(invo) 73 } 74 if invo.attributes == nil { 75 invo.attributes = make(map[string]interface{}) 76 } 77 return invo 78 } 79 80 // MethodName gets RPC invocation method name. 81 func (r *RPCInvocation) MethodName() string { 82 return r.methodName 83 } 84 85 // ActualMethodName gets actual invocation method name. It returns the method name been called if it's a generic call 86 func (r *RPCInvocation) ActualMethodName() string { 87 if r.IsGenericInvocation() { 88 return r.Arguments()[0].(string) 89 } else { 90 return r.MethodName() 91 } 92 } 93 94 // IsGenericInvocation gets if this is a generic invocation 95 func (r *RPCInvocation) IsGenericInvocation() bool { 96 return (r.MethodName() == constant.Generic || 97 r.MethodName() == constant.GenericAsync) && 98 r.Arguments() != nil && 99 len(r.Arguments()) == 3 100 } 101 102 // ParameterTypes gets RPC invocation parameter types. 103 func (r *RPCInvocation) ParameterTypes() []reflect.Type { 104 return r.parameterTypes 105 } 106 107 // ParameterTypeNames gets RPC invocation parameter types of string expression. 108 func (r *RPCInvocation) ParameterTypeNames() []string { 109 return r.parameterTypeNames 110 } 111 112 // ParameterValues gets RPC invocation parameter values. 113 func (r *RPCInvocation) ParameterValues() []reflect.Value { 114 return r.parameterValues 115 } 116 117 // Arguments gets RPC arguments. 118 func (r *RPCInvocation) Arguments() []interface{} { 119 return r.arguments 120 } 121 122 // Reply gets response of RPC request. 123 func (r *RPCInvocation) Reply() interface{} { 124 return r.reply 125 } 126 127 // SetReply sets response of RPC request. 128 func (r *RPCInvocation) SetReply(reply interface{}) { 129 r.reply = reply 130 } 131 132 // Attachments gets all attachments of RPC. 133 func (r *RPCInvocation) Attachments() map[string]interface{} { 134 return r.attachments 135 } 136 137 // GetAttachmentInterface returns the corresponding value from dubbo's attachment with the given key. 138 func (r *RPCInvocation) GetAttachmentInterface(key string) interface{} { 139 r.lock.RLock() 140 defer r.lock.RUnlock() 141 if r.attachments == nil { 142 return nil 143 } 144 return r.attachments[key] 145 } 146 147 // Attributes gets all attributes of RPC. 148 func (r *RPCInvocation) Attributes() map[string]interface{} { 149 return r.attributes 150 } 151 152 // Invoker gets the invoker in current context. 153 func (r *RPCInvocation) Invoker() protocol.Invoker { 154 return r.invoker 155 } 156 157 // nolint 158 func (r *RPCInvocation) SetInvoker(invoker protocol.Invoker) { 159 r.lock.Lock() 160 defer r.lock.Unlock() 161 r.invoker = invoker 162 } 163 164 // CallBack sets RPC callback method. 165 func (r *RPCInvocation) CallBack() interface{} { 166 return r.callBack 167 } 168 169 // SetCallBack sets RPC callback method. 170 func (r *RPCInvocation) SetCallBack(c interface{}) { 171 r.callBack = c 172 } 173 174 func (r *RPCInvocation) ServiceKey() string { 175 return common.ServiceKey(strings.TrimPrefix(r.GetAttachmentWithDefaultValue(constant.PathKey, r.GetAttachmentWithDefaultValue(constant.InterfaceKey, "")), "/"), 176 r.GetAttachmentWithDefaultValue(constant.GroupKey, ""), r.GetAttachmentWithDefaultValue(constant.VersionKey, "")) 177 } 178 179 func (r *RPCInvocation) SetAttachment(key string, value interface{}) { 180 r.lock.Lock() 181 defer r.lock.Unlock() 182 if r.attachments == nil { 183 r.attachments = make(map[string]interface{}) 184 } 185 r.attachments[key] = value 186 } 187 188 func (r *RPCInvocation) GetAttachment(key string) (string, bool) { 189 r.lock.RLock() 190 defer r.lock.RUnlock() 191 if r.attachments == nil { 192 return "", false 193 } 194 if value, existed := r.attachments[key]; existed { 195 if str, strOK := value.(string); strOK { 196 return str, true 197 } else if strArr, strArrOK := value.([]string); strArrOK && len(strArr) > 0 { 198 // For triple protocol, the attachment value is wrapped by an array. 199 return strArr[0], true 200 } 201 } 202 return "", false 203 } 204 205 func (r *RPCInvocation) GetAttachmentWithDefaultValue(key string, defaultValue string) string { 206 if value, ok := r.GetAttachment(key); ok { 207 return value 208 } 209 return defaultValue 210 } 211 212 func (r *RPCInvocation) SetAttribute(key string, value interface{}) { 213 r.lock.Lock() 214 defer r.lock.Unlock() 215 if r.attributes == nil { 216 r.attributes = make(map[string]interface{}) 217 } 218 r.attributes[key] = value 219 } 220 221 func (r *RPCInvocation) GetAttribute(key string) (interface{}, bool) { 222 r.lock.RLock() 223 defer r.lock.RUnlock() 224 if r.attributes == nil { 225 return nil, false 226 } 227 value, ok := r.attributes[key] 228 return value, ok 229 } 230 231 func (r *RPCInvocation) GetAttributeWithDefaultValue(key string, defaultValue interface{}) interface{} { 232 r.lock.RLock() 233 defer r.lock.RUnlock() 234 if r.attributes == nil { 235 return defaultValue 236 } 237 if value, ok := r.attributes[key]; ok { 238 return value 239 } 240 return defaultValue 241 } 242 243 func (r *RPCInvocation) GetAttachmentAsContext() context.Context { 244 gRPCMD := make(metadata.MD, 0) 245 ctx := context.Background() 246 for k, v := range r.Attachments() { 247 if str, ok := v.(string); ok { 248 gRPCMD.Set(k, str) 249 continue 250 } 251 if str, ok := v.([]string); ok { 252 gRPCMD.Set(k, str...) 253 continue 254 } 255 } 256 return metadata.NewOutgoingContext(ctx, gRPCMD) 257 } 258 259 // ///////////////////////// 260 // option 261 // ///////////////////////// 262 263 type option func(invo *RPCInvocation) 264 265 // WithMethodName creates option with @methodName. 266 func WithMethodName(methodName string) option { 267 return func(invo *RPCInvocation) { 268 invo.methodName = methodName 269 } 270 } 271 272 // WithParameterTypes creates option with @parameterTypes. 273 func WithParameterTypes(parameterTypes []reflect.Type) option { 274 return func(invo *RPCInvocation) { 275 invo.parameterTypes = parameterTypes 276 } 277 } 278 279 // WithParameterTypeNames creates option with @parameterTypeNames. 280 func WithParameterTypeNames(parameterTypeNames []string) option { 281 return func(invo *RPCInvocation) { 282 if len(parameterTypeNames) == 0 { 283 return 284 } 285 parameterTypeNamesTmp := make([]string, len(parameterTypeNames)) 286 copy(parameterTypeNamesTmp, parameterTypeNames) 287 invo.parameterTypeNames = parameterTypeNamesTmp 288 } 289 } 290 291 // WithParameterValues creates option with @parameterValues 292 func WithParameterValues(parameterValues []reflect.Value) option { 293 return func(invo *RPCInvocation) { 294 invo.parameterValues = parameterValues 295 } 296 } 297 298 // WithArguments creates option with @arguments function. 299 func WithArguments(arguments []interface{}) option { 300 return func(invo *RPCInvocation) { 301 invo.arguments = arguments 302 } 303 } 304 305 // WithReply creates option with @reply function. 306 func WithReply(reply interface{}) option { 307 return func(invo *RPCInvocation) { 308 invo.reply = reply 309 } 310 } 311 312 // WithCallBack creates option with @callback function. 313 func WithCallBack(callBack interface{}) option { 314 return func(invo *RPCInvocation) { 315 invo.callBack = callBack 316 } 317 } 318 319 // WithAttachments creates option with @attachments. 320 func WithAttachments(attachments map[string]interface{}) option { 321 return func(invo *RPCInvocation) { 322 invo.attachments = attachments 323 } 324 } 325 326 // WithInvoker creates option with @invoker. 327 func WithInvoker(invoker protocol.Invoker) option { 328 return func(invo *RPCInvocation) { 329 invo.invoker = invoker 330 } 331 }