dubbo.apache.org/dubbo-go/v3@v3.1.1/proxy/proxy_factory/default.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 proxy_factory
    19  
    20  import (
    21  	"context"
    22  	"reflect"
    23  	"strings"
    24  )
    25  
    26  import (
    27  	"github.com/dubbogo/gost/log/logger"
    28  
    29  	perrors "github.com/pkg/errors"
    30  )
    31  
    32  import (
    33  	"dubbo.apache.org/dubbo-go/v3/common"
    34  	"dubbo.apache.org/dubbo-go/v3/common/constant"
    35  	"dubbo.apache.org/dubbo-go/v3/common/extension"
    36  	"dubbo.apache.org/dubbo-go/v3/protocol"
    37  	"dubbo.apache.org/dubbo-go/v3/proxy"
    38  )
    39  
    40  func init() {
    41  	extension.SetProxyFactory("default", NewDefaultProxyFactory)
    42  }
    43  
    44  // DefaultProxyFactory is the default proxy factory
    45  type DefaultProxyFactory struct { // delegate ProxyFactory
    46  }
    47  
    48  // you can rewrite DefaultProxyFactory in extension and delegate the default proxy factory like below
    49  
    50  //func WithDelegate(delegateProxyFactory ProxyFactory) Option {
    51  //	return func(proxy ProxyFactory) {
    52  //		proxy.(*DefaultProxyFactory).delegate = delegateProxyFactory
    53  //	}
    54  //}
    55  
    56  // NewDefaultProxyFactory returns a proxy factory instance
    57  func NewDefaultProxyFactory(_ ...proxy.Option) proxy.ProxyFactory {
    58  	return &DefaultProxyFactory{}
    59  }
    60  
    61  // GetProxy gets a proxy
    62  func (factory *DefaultProxyFactory) GetProxy(invoker protocol.Invoker, url *common.URL) *proxy.Proxy {
    63  	return factory.GetAsyncProxy(invoker, nil, url)
    64  }
    65  
    66  // GetAsyncProxy gets a async proxy
    67  func (factory *DefaultProxyFactory) GetAsyncProxy(invoker protocol.Invoker, callBack interface{}, url *common.URL) *proxy.Proxy {
    68  	// create proxy
    69  	attachments := map[string]string{}
    70  	attachments[constant.AsyncKey] = url.GetParam(constant.AsyncKey, "false")
    71  	attachments[constant.EnvironmentKey] = url.GetParam(constant.EnvironmentKey, "dev")
    72  	return proxy.NewProxy(invoker, callBack, attachments)
    73  }
    74  
    75  // GetInvoker gets a invoker
    76  func (factory *DefaultProxyFactory) GetInvoker(url *common.URL) protocol.Invoker {
    77  	return &ProxyInvoker{
    78  		BaseInvoker: *protocol.NewBaseInvoker(url),
    79  	}
    80  }
    81  
    82  // ProxyInvoker is a invoker struct
    83  type ProxyInvoker struct {
    84  	protocol.BaseInvoker
    85  }
    86  
    87  // Invoke is used to call service method by invocation
    88  func (pi *ProxyInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
    89  	result := &protocol.RPCResult{}
    90  	result.SetAttachments(invocation.Attachments())
    91  
    92  	// get providerUrl. The origin url may be is registry URL.
    93  	url := getProviderURL(pi.GetURL())
    94  
    95  	methodName := invocation.MethodName()
    96  	proto := url.Protocol
    97  	path := strings.TrimPrefix(url.Path, "/")
    98  	args := invocation.Arguments()
    99  
   100  	// get service
   101  	svc := common.ServiceMap.GetServiceByServiceKey(proto, url.ServiceKey())
   102  	if svc == nil {
   103  		logger.Errorf("cannot find service [%s] in %s", path, proto)
   104  		result.SetError(perrors.Errorf("cannot find service [%s] in %s", path, proto))
   105  		return result
   106  	}
   107  
   108  	// get method
   109  	method := svc.Method()[methodName]
   110  	if method == nil {
   111  		logger.Errorf("cannot find method [%s] of service [%s] in %s", methodName, path, proto)
   112  		result.SetError(perrors.Errorf("cannot find method [%s] of service [%s] in %s", methodName, path, proto))
   113  		return result
   114  	}
   115  
   116  	in := []reflect.Value{svc.Rcvr()}
   117  	if method.CtxType() != nil {
   118  		ctx = context.WithValue(ctx, constant.AttachmentKey, invocation.Attachments())
   119  		in = append(in, method.SuiteContext(ctx))
   120  	}
   121  
   122  	// prepare argv
   123  	if (len(method.ArgsType()) == 1 || len(method.ArgsType()) == 2 && method.ReplyType() == nil) && method.ArgsType()[0].String() == "[]interface {}" {
   124  		in = append(in, reflect.ValueOf(args))
   125  	} else {
   126  		for i := 0; i < len(args); i++ {
   127  			t := reflect.ValueOf(args[i])
   128  			if !t.IsValid() {
   129  				at := method.ArgsType()[i]
   130  				if at.Kind() == reflect.Ptr {
   131  					at = at.Elem()
   132  				}
   133  				t = reflect.New(at)
   134  			}
   135  			in = append(in, t)
   136  		}
   137  	}
   138  
   139  	// prepare replyv
   140  	var replyv reflect.Value
   141  	var retErr interface{}
   142  
   143  	returnValues, callErr := callLocalMethod(method.Method(), in)
   144  
   145  	if callErr != nil {
   146  		logger.Errorf("Invoke function error: %+v, service: %#v", callErr, url)
   147  		result.SetError(callErr)
   148  		return result
   149  	}
   150  
   151  	if len(returnValues) == 1 {
   152  		retErr = returnValues[0].Interface()
   153  	} else {
   154  		replyv = returnValues[0]
   155  		retErr = returnValues[1].Interface()
   156  	}
   157  
   158  	if retErr != nil {
   159  		result.SetError(retErr.(error))
   160  		return result
   161  	}
   162  	if replyv.IsValid() && (replyv.Kind() != reflect.Ptr || replyv.Kind() == reflect.Ptr && replyv.Elem().IsValid()) {
   163  		result.SetResult(replyv.Interface())
   164  	}
   165  
   166  	return result
   167  }
   168  
   169  func getProviderURL(url *common.URL) *common.URL {
   170  	if url.SubURL == nil {
   171  		return url
   172  	}
   173  	return url.SubURL
   174  }