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  }