blob: 5739e12e3a6015295916d66a6e277ac127d758e0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package proxy_factory
import (
"context"
"reflect"
)
import (
"github.com/dubbogo/gost/log/logger"
perrors "github.com/pkg/errors"
)
import (
"dubbo.apache.org/dubbo-go/v3/common"
"dubbo.apache.org/dubbo-go/v3/common/constant"
"dubbo.apache.org/dubbo-go/v3/common/extension"
"dubbo.apache.org/dubbo-go/v3/protocol"
"dubbo.apache.org/dubbo-go/v3/proxy"
)
func init() {
extension.SetProxyFactory(constant.PassThroughProxyFactoryKey, NewPassThroughProxyFactory)
}
// PassThroughProxyFactory is the factory of PassThroughProxyInvoker
type PassThroughProxyFactory struct {
}
// NewPassThroughProxyFactory returns a proxy factory instance
func NewPassThroughProxyFactory(_ ...proxy.Option) proxy.ProxyFactory {
return &PassThroughProxyFactory{}
}
// GetProxy gets a proxy
func (factory *PassThroughProxyFactory) GetProxy(invoker protocol.Invoker, url *common.URL) *proxy.Proxy {
return factory.GetAsyncProxy(invoker, nil, url)
}
// GetAsyncProxy gets a async proxy
func (factory *PassThroughProxyFactory) GetAsyncProxy(invoker protocol.Invoker, callBack interface{}, url *common.URL) *proxy.Proxy {
//create proxy
attachments := map[string]string{}
attachments[constant.AsyncKey] = url.GetParam(constant.AsyncKey, "false")
return proxy.NewProxy(invoker, callBack, attachments)
}
// GetInvoker gets a invoker
func (factory *PassThroughProxyFactory) GetInvoker(url *common.URL) protocol.Invoker {
return &PassThroughProxyInvoker{
ProxyInvoker: &ProxyInvoker{
BaseInvoker: *protocol.NewBaseInvoker(url),
},
}
}
// PassThroughProxyInvoker is a invoker struct, it calls service with specific method 'Serivce' and params:
// Service(method string, argsTypes []string, args [][]byte, attachment map[string]interface{})
// PassThroughProxyInvoker pass through raw invocation data and method name to service, which will deal with them.
type PassThroughProxyInvoker struct {
*ProxyInvoker
}
// Invoke is used to call service method by invocation
func (pi *PassThroughProxyInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
result := &protocol.RPCResult{}
result.SetAttachments(invocation.Attachments())
url := getProviderURL(pi.GetURL())
arguments := invocation.Arguments()
srv := common.ServiceMap.GetServiceByServiceKey(url.Protocol, url.ServiceKey())
var args [][]byte
if len(arguments) > 0 {
args = make([][]byte, 0, len(arguments))
for _, arg := range arguments {
if v, ok := arg.([]byte); ok {
args = append(args, v)
} else {
result.Err = perrors.New("the param type is not []byte")
return result
}
}
}
method := srv.Method()["Service"]
in := make([]reflect.Value, 5)
in = append(in, srv.Rcvr())
in = append(in, reflect.ValueOf(invocation.MethodName()))
in = append(in, reflect.ValueOf(invocation.GetAttachmentInterface(constant.ParamsTypeKey)))
in = append(in, reflect.ValueOf(args))
in = append(in, reflect.ValueOf(invocation.Attachments()))
var replyv reflect.Value
var retErr interface{}
returnValues, callErr := callLocalMethod(method.Method(), in)
if callErr != nil {
logger.Errorf("Invoke function error: %+v, service: %#v", callErr, url)
result.SetError(callErr)
return result
}
replyv = returnValues[0]
retErr = returnValues[1].Interface()
if retErr != nil {
result.SetError(retErr.(error))
return result
}
if replyv.IsValid() && (replyv.Kind() != reflect.Ptr || replyv.Kind() == reflect.Ptr && replyv.Elem().IsValid()) {
result.SetResult(replyv.Interface())
}
return result
}