Skip to content
Snippets Groups Projects
Unverified Commit 7cbe7c38 authored by Xin.Zh's avatar Xin.Zh Committed by GitHub
Browse files

Merge pull request #55 from dubbo/develop

Rft: refactoring code
parents e17bddf7 8962cdd9
No related branches found
No related tags found
No related merge requests found
Showing
with 2100 additions and 0 deletions
// Copyright 2016-2019 Yincheng Fang
//
// Licensed 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 logger
import (
"io/ioutil"
"log"
"os"
"path"
)
import (
"github.com/dubbogo/getty"
perrors "github.com/pkg/errors"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/yaml.v2"
)
import (
"github.com/dubbo/go-for-apache-dubbo/common/constant"
)
var (
logger Logger
)
type Logger interface {
Info(args ...interface{})
Warn(args ...interface{})
Error(args ...interface{})
Debug(args ...interface{})
Infof(fmt string, args ...interface{})
Warnf(fmt string, args ...interface{})
Errorf(fmt string, args ...interface{})
Debugf(fmt string, args ...interface{})
}
func init() {
logConfFile := os.Getenv(constant.APP_LOG_CONF_FILE)
err := InitLog(logConfFile)
if err != nil {
log.Printf("[InitLog] error: %v", err)
}
}
func InitLog(logConfFile string) error {
if logConfFile == "" {
InitLogger(nil)
return perrors.New("log configure file name is nil")
}
if path.Ext(logConfFile) != ".yml" {
InitLogger(nil)
return perrors.Errorf("log configure file name{%s} suffix must be .yml", logConfFile)
}
confFileStream, err := ioutil.ReadFile(logConfFile)
if err != nil {
InitLogger(nil)
return perrors.Errorf("ioutil.ReadFile(file:%s) = error:%v", logConfFile, err)
}
conf := &zap.Config{}
err = yaml.Unmarshal(confFileStream, conf)
if err != nil {
InitLogger(nil)
return perrors.Errorf("[Unmarshal]init logger error: %v", err)
}
InitLogger(conf)
// set getty log
getty.SetLogger(logger)
return nil
}
func InitLogger(conf *zap.Config) {
var zapLoggerConfig zap.Config
if conf == nil {
zapLoggerConfig = zap.NewDevelopmentConfig()
zapLoggerEncoderConfig := zapcore.EncoderConfig{
TimeKey: "time",
LevelKey: "level",
NameKey: "logger",
CallerKey: "caller",
MessageKey: "message",
StacktraceKey: "stacktrace",
EncodeLevel: zapcore.CapitalColorLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
zapLoggerConfig.EncoderConfig = zapLoggerEncoderConfig
} else {
zapLoggerConfig = *conf
}
zapLogger, _ := zapLoggerConfig.Build()
logger = zapLogger.Sugar()
}
func SetLogger(log Logger) {
logger = log
getty.SetLogger(logger)
}
package logger
import (
"github.com/stretchr/testify/assert"
"path/filepath"
"testing"
)
func TestInitLog(t *testing.T) {
var (
err error
path string
)
err = InitLog("")
assert.EqualError(t, err, "log configure file name is nil")
path, err = filepath.Abs("./log.xml")
assert.NoError(t, err)
err = InitLog(path)
assert.EqualError(t, err, "log configure file name{"+path+"} suffix must be .yml")
path, err = filepath.Abs("./logger.yml")
assert.NoError(t, err)
err = InitLog(path)
assert.EqualError(t, err, "ioutil.ReadFile(file:"+path+") = error:open "+path+": no such file or directory")
err = InitLog("./log.yml")
assert.NoError(t, err)
Debug("debug")
Info("info")
Warn("warn")
Error("error")
Debugf("%s", "debug")
Infof("%s", "info")
Warnf("%s", "warn")
Errorf("%s", "error")
}
// Copyright 2016-2019 Yincheng Fang
//
// Licensed 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 logger
func Info(args ...interface{}) {
logger.Info(args...)
}
func Warn(args ...interface{}) {
logger.Warn(args...)
}
func Error(args ...interface{}) {
logger.Error(args...)
}
func Debug(args ...interface{}) {
logger.Debug(args...)
}
func Infof(fmt string, args ...interface{}) {
logger.Infof(fmt, args...)
}
func Warnf(fmt string, args ...interface{}) {
logger.Warnf(fmt, args...)
}
func Errorf(fmt string, args ...interface{}) {
logger.Errorf(fmt, args...)
}
func Debugf(fmt string, args ...interface{}) {
logger.Debugf(fmt, args...)
}
// Copyright 2016-2019 hxmhlt
//
// Licensed 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 common
type Node interface {
GetUrl() URL
IsAvailable() bool
Destroy()
}
// Copyright 2016-2019 Yincheng Fang
//
// Licensed 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
import (
"reflect"
)
import (
"github.com/dubbo/go-for-apache-dubbo/common"
"github.com/dubbo/go-for-apache-dubbo/common/logger"
"github.com/dubbo/go-for-apache-dubbo/protocol"
invocation_impl "github.com/dubbo/go-for-apache-dubbo/protocol/invocation"
)
// Proxy struct
type Proxy struct {
rpc common.RPCService
invoke protocol.Invoker
callBack interface{}
attachments map[string]string
}
var typError = reflect.Zero(reflect.TypeOf((*error)(nil)).Elem()).Type()
func NewProxy(invoke protocol.Invoker, callBack interface{}, attachments map[string]string) *Proxy {
return &Proxy{
invoke: invoke,
callBack: callBack,
attachments: attachments,
}
}
// proxy implement
// In consumer, RPCService like:
// type XxxProvider struct {
// Yyy func(ctx context.Context, args []interface{}, rsp *Zzz) error
// }
func (p *Proxy) Implement(v common.RPCService) {
// check parameters, incoming interface must be a elem's pointer.
valueOf := reflect.ValueOf(v)
logger.Debugf("[Implement] reflect.TypeOf: %s", valueOf.String())
valueOfElem := valueOf.Elem()
typeOf := valueOfElem.Type()
// check incoming interface, incoming interface's elem must be a struct.
if typeOf.Kind() != reflect.Struct {
logger.Errorf("%s must be a struct ptr", valueOf.String())
return
}
makeDubboCallProxy := func(methodName string, outs []reflect.Type) func(in []reflect.Value) []reflect.Value {
return func(in []reflect.Value) []reflect.Value {
var (
err error
inv *invocation_impl.RPCInvocation
inArr []interface{}
reply reflect.Value
)
if methodName == "Echo" {
methodName = "$echo"
}
start := 0
end := len(in)
if in[0].Type().String() == "context.Context" {
start += 1
}
if len(outs) == 1 {
end -= 1
reply = in[len(in)-1]
} else {
if outs[0].Kind() == reflect.Ptr {
reply = reflect.New(outs[0].Elem())
} else {
reply = reflect.New(outs[0])
}
}
if v, ok := in[start].Interface().([]interface{}); ok && end-start == 1 {
inArr = v
} else {
inArr = make([]interface{}, end-start)
index := 0
for i := start; i < end; i++ {
inArr[index] = in[i].Interface()
index++
}
}
inv = invocation_impl.NewRPCInvocationForConsumer(methodName, nil, inArr, reply.Interface(), p.callBack, common.URL{}, nil)
for k, value := range p.attachments {
inv.SetAttachments(k, value)
}
result := p.invoke.Invoke(inv)
err = result.Error()
logger.Infof("[makeDubboCallProxy] result: %v, err: %v", result.Result(), err)
if len(outs) == 1 {
return []reflect.Value{reflect.ValueOf(&err).Elem()}
}
if len(outs) == 2 && outs[0].Kind() != reflect.Ptr {
return []reflect.Value{reply.Elem(), reflect.ValueOf(&err).Elem()}
}
return []reflect.Value{reply, reflect.ValueOf(&err).Elem()}
}
}
numField := valueOfElem.NumField()
for i := 0; i < numField; i++ {
t := typeOf.Field(i)
methodName := t.Tag.Get("dubbo")
if methodName == "" {
methodName = t.Name
}
f := valueOfElem.Field(i)
if f.Kind() == reflect.Func && f.IsValid() && f.CanSet() {
inNum := t.Type.NumIn()
outNum := t.Type.NumOut()
if outNum != 1 && outNum != 2 {
logger.Warnf("method %s of mtype %v has wrong number of in out parameters %d; needs exactly 1/2",
t.Name, t.Type.String(), outNum)
continue
}
// The latest return type of the method must be error.
if returnType := t.Type.Out(outNum - 1); returnType != typError {
logger.Warnf("the latest return type %s of method %q is not error", returnType, t.Name)
continue
}
// reply must be Ptr when outNum == 1
if outNum == 1 && t.Type.In(inNum-1).Kind() != reflect.Ptr {
logger.Warnf("reply type of method %q is not a pointer", t.Name)
continue
}
var funcOuts = make([]reflect.Type, outNum)
for i := 0; i < outNum; i++ {
funcOuts[i] = t.Type.Out(i)
}
// do method proxy here:
f.Set(reflect.MakeFunc(f.Type(), makeDubboCallProxy(methodName, funcOuts)))
logger.Debugf("set method [%s]", methodName)
}
}
p.rpc = v
}
func (p *Proxy) Get() common.RPCService {
return p.rpc
}
// Copyright 2016-2019 hxmhlt
//
// Licensed 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
import (
"github.com/dubbo/go-for-apache-dubbo/common"
"github.com/dubbo/go-for-apache-dubbo/protocol"
)
type ProxyFactory interface {
GetProxy(invoker protocol.Invoker, url *common.URL) *Proxy
GetInvoker(url common.URL) protocol.Invoker
}
type Option func(ProxyFactory)
// Copyright 2016-2019 hxmhlt
//
// Licensed 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 (
"github.com/dubbo/go-for-apache-dubbo/common"
"github.com/dubbo/go-for-apache-dubbo/common/constant"
"github.com/dubbo/go-for-apache-dubbo/common/extension"
"github.com/dubbo/go-for-apache-dubbo/common/proxy"
"github.com/dubbo/go-for-apache-dubbo/protocol"
)
func init() {
extension.SetProxyFactory("default", NewDefaultProxyFactory)
}
type DefaultProxyFactory struct {
//delegate ProxyFactory
}
//you can rewrite DefaultProxyFactory in extension and delegate the default proxy factory like below
//func WithDelegate(delegateProxyFactory ProxyFactory) Option {
// return func(proxy ProxyFactory) {
// proxy.(*DefaultProxyFactory).delegate = delegateProxyFactory
// }
//}
func NewDefaultProxyFactory(options ...proxy.Option) proxy.ProxyFactory {
return &DefaultProxyFactory{}
}
func (factory *DefaultProxyFactory) GetProxy(invoker protocol.Invoker, url *common.URL) *proxy.Proxy {
//create proxy
attachments := map[string]string{}
attachments[constant.ASYNC_KEY] = url.GetParam(constant.ASYNC_KEY, "false")
return proxy.NewProxy(invoker, nil, attachments)
}
func (factory *DefaultProxyFactory) GetInvoker(url common.URL) protocol.Invoker {
//TODO:yincheng need to do the service invoker refactor
return protocol.NewBaseInvoker(url)
}
// Copyright 2016-2019 hxmhlt
//
// Licensed 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 (
"github.com/dubbo/go-for-apache-dubbo/common"
"github.com/dubbo/go-for-apache-dubbo/protocol"
"github.com/stretchr/testify/assert"
"testing"
)
func Test_GetProxy(t *testing.T) {
proxyFactory := NewDefaultProxyFactory()
url := common.NewURLWithOptions("testservice")
proxy := proxyFactory.GetProxy(protocol.NewBaseInvoker(*url), url)
assert.NotNil(t, proxy)
}
func Test_GetInvoker(t *testing.T) {
proxyFactory := NewDefaultProxyFactory()
url := common.NewURLWithOptions("testservice")
invoker := proxyFactory.GetInvoker(*url)
assert.True(t, invoker.IsAvailable())
}
// Copyright 2016-2019 Yincheng Fang
//
// Licensed 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
import (
"context"
"reflect"
"testing"
)
import (
perrors "github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
import (
"github.com/dubbo/go-for-apache-dubbo/common"
"github.com/dubbo/go-for-apache-dubbo/common/constant"
"github.com/dubbo/go-for-apache-dubbo/protocol"
)
type TestService struct {
MethodOne func(context.Context, int, bool, *interface{}) error
MethodTwo func([]interface{}, *interface{}) error
MethodThree func(int, bool) (interface{}, error)
MethodFour func(int, bool) (*interface{}, error) `dubbo:"methodFour"`
Echo func(interface{}, *interface{}) error
}
func (s *TestService) Service() string {
return "com.test.Path"
}
func (s *TestService) Version() string {
return ""
}
type TestServiceInt int
func (s *TestServiceInt) Service() string {
return "com.test.TestServiceInt"
}
func (s *TestServiceInt) Version() string {
return ""
}
func TestProxy_Implement(t *testing.T) {
invoker := protocol.NewBaseInvoker(common.URL{})
p := NewProxy(invoker, nil, map[string]string{constant.ASYNC_KEY: "false"})
s := &TestService{}
p.Implement(s)
err := p.Get().(*TestService).MethodOne(nil, 0, false, nil)
assert.NoError(t, err)
err = p.Get().(*TestService).MethodTwo(nil, nil)
assert.NoError(t, err)
ret, err := p.Get().(*TestService).MethodThree(0, false)
assert.NoError(t, err)
assert.Nil(t, ret) // ret is nil, because it doesn't be injection yet
ret2, err := p.Get().(*TestService).MethodFour(0, false)
assert.NoError(t, err)
assert.Equal(t, "*interface {}", reflect.TypeOf(ret2).String())
err = p.Get().(*TestService).Echo(nil, nil)
assert.NoError(t, err)
// inherit & lowercase
p.rpc = nil
type S1 struct {
TestService
methodOne func(context.Context, interface{}, *struct{}) error
}
s1 := &S1{TestService: *s, methodOne: func(i context.Context, i2 interface{}, i3 *struct{}) error {
return perrors.New("errors")
}}
p.Implement(s1)
err = s1.MethodOne(nil, 0, false, nil)
assert.NoError(t, err)
err = s1.methodOne(nil, nil, nil)
assert.EqualError(t, err, "errors")
// no struct
p.rpc = nil
it := TestServiceInt(1)
p.Implement(&it)
assert.Nil(t, p.rpc)
// return number
p.rpc = nil
type S2 struct {
TestService
MethodOne func([]interface{}) (*struct{}, int, error)
}
s2 := &S2{TestService: *s}
p.Implement(s2)
assert.Nil(t, s2.MethodOne)
// reply type
p.rpc = nil
type S3 struct {
TestService
MethodOne func(context.Context, []interface{}, struct{}) error
}
s3 := &S3{TestService: *s}
p.Implement(s3)
assert.Nil(t, s3.MethodOne)
// returns type
p.rpc = nil
type S4 struct {
TestService
MethodOne func(context.Context, []interface{}, *struct{}) interface{}
}
s4 := &S4{TestService: *s}
p.Implement(s4)
assert.Nil(t, s4.MethodOne)
}
// Copyright 2016-2019 Yincheng Fang
//
// Licensed 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 common
import (
"context"
"reflect"
"strings"
"sync"
"unicode"
"unicode/utf8"
)
import (
perrors "github.com/pkg/errors"
)
import (
"github.com/dubbo/go-for-apache-dubbo/common/logger"
)
// rpc service interface
type RPCService interface {
Service() string // Path InterfaceName
Version() string
}
var (
// Precompute the reflect type for error. Can't use error directly
// because Typeof takes an empty interface value. This is annoying.
typeOfError = reflect.TypeOf((*error)(nil)).Elem()
// todo: lowerecas?
ServiceMap = &serviceMap{
serviceMap: make(map[string]map[string]*Service),
}
)
//////////////////////////
// info of method
//////////////////////////
type MethodType struct {
method reflect.Method
ctxType reflect.Type // request context
argsType []reflect.Type // args except ctx, include replyType if existing
replyType reflect.Type // return value, otherwise it is nil
}
func (m *MethodType) Method() reflect.Method {
return m.method
}
func (m *MethodType) CtxType() reflect.Type {
return m.ctxType
}
func (m *MethodType) ArgsType() []reflect.Type {
return m.argsType
}
func (m *MethodType) ReplyType() reflect.Type {
return m.replyType
}
func (m *MethodType) SuiteContext(ctx context.Context) reflect.Value {
if contextv := reflect.ValueOf(ctx); contextv.IsValid() {
return contextv
}
return reflect.Zero(m.ctxType)
}
//////////////////////////
// info of service interface
//////////////////////////
type Service struct {
name string
rcvr reflect.Value
rcvrType reflect.Type
methods map[string]*MethodType
}
func (s *Service) Method() map[string]*MethodType {
return s.methods
}
func (s *Service) RcvrType() reflect.Type {
return s.rcvrType
}
func (s *Service) Rcvr() reflect.Value {
return s.rcvr
}
//////////////////////////
// serviceMap
//////////////////////////
type serviceMap struct {
mutex sync.RWMutex // protects the serviceMap
serviceMap map[string]map[string]*Service // protocol -> service name -> service
}
func (sm *serviceMap) GetService(protocol, name string) *Service {
sm.mutex.RLock()
defer sm.mutex.RUnlock()
if s, ok := sm.serviceMap[protocol]; ok {
if srv, ok := s[name]; ok {
return srv
}
return nil
}
return nil
}
func (sm *serviceMap) Register(protocol string, rcvr RPCService) (string, error) {
if sm.serviceMap[protocol] == nil {
sm.serviceMap[protocol] = make(map[string]*Service)
}
s := new(Service)
s.rcvrType = reflect.TypeOf(rcvr)
s.rcvr = reflect.ValueOf(rcvr)
sname := reflect.Indirect(s.rcvr).Type().Name()
if sname == "" {
s := "no service name for type " + s.rcvrType.String()
logger.Errorf(s)
return "", perrors.New(s)
}
if !isExported(sname) {
s := "type " + sname + " is not exported"
logger.Errorf(s)
return "", perrors.New(s)
}
sname = rcvr.Service()
if server := sm.GetService(protocol, sname); server != nil {
return "", perrors.New("service already defined: " + sname)
}
s.name = sname
s.methods = make(map[string]*MethodType)
// Install the methods
methods := ""
methods, s.methods = suitableMethods(s.rcvrType)
if len(s.methods) == 0 {
s := "type " + sname + " has no exported methods of suitable type"
logger.Errorf(s)
return "", perrors.New(s)
}
sm.mutex.Lock()
sm.serviceMap[protocol][s.name] = s
sm.mutex.Unlock()
return strings.TrimSuffix(methods, ","), nil
}
func (sm *serviceMap) UnRegister(protocol, serviceName string) error {
if protocol == "" || serviceName == "" {
return perrors.New("protocol or serviceName is nil")
}
sm.mutex.RLock()
svcs, ok := sm.serviceMap[protocol]
if !ok {
sm.mutex.RUnlock()
return perrors.New("no services for " + protocol)
}
_, ok = svcs[serviceName]
if !ok {
sm.mutex.RUnlock()
return perrors.New("no service for " + serviceName)
}
sm.mutex.RUnlock()
sm.mutex.Lock()
defer sm.mutex.Unlock()
delete(svcs, serviceName)
delete(sm.serviceMap, protocol)
return nil
}
// Is this an exported - upper case - name
func isExported(name string) bool {
rune, _ := utf8.DecodeRuneInString(name)
return unicode.IsUpper(rune)
}
// Is this type exported or a builtin?
func isExportedOrBuiltinType(t reflect.Type) bool {
for t.Kind() == reflect.Ptr {
t = t.Elem()
}
// PkgPath will be non-empty even for an exported type,
// so we need to check the type name as well.
return isExported(t.Name()) || t.PkgPath() == ""
}
// suitableMethods returns suitable Rpc methods of typ
func suitableMethods(typ reflect.Type) (string, map[string]*MethodType) {
methods := make(map[string]*MethodType)
mts := ""
logger.Debugf("[%s] NumMethod is %d", typ.String(), typ.NumMethod())
for m := 0; m < typ.NumMethod(); m++ {
method := typ.Method(m)
if mt := suiteMethod(method); mt != nil {
methods[method.Name] = mt
if m == 0 {
mts += method.Name
} else {
mts += "," + method.Name
}
}
}
return mts, methods
}
// suiteMethod returns a suitable Rpc methodType
func suiteMethod(method reflect.Method) *MethodType {
mtype := method.Type
mname := method.Name
inNum := mtype.NumIn()
outNum := mtype.NumOut()
// Method must be exported.
if method.PkgPath != "" {
return nil
}
var (
replyType, ctxType reflect.Type
argsType []reflect.Type
)
if outNum != 1 && outNum != 2 {
logger.Warnf("method %s of mtype %v has wrong number of in out parameters %d; needs exactly 1/2",
mname, mtype.String(), outNum)
return nil
}
// The latest return type of the method must be error.
if returnType := mtype.Out(outNum - 1); returnType != typeOfError {
logger.Warnf("the latest return type %s of method %q is not error", returnType, mname)
return nil
}
// replyType
if outNum == 1 {
if mtype.In(inNum-1).Kind() != reflect.Ptr {
logger.Errorf("reply type of method %q is not a pointer %v", mname, replyType)
return nil
}
} else {
replyType = mtype.Out(0)
if !isExportedOrBuiltinType(replyType) {
logger.Errorf("reply type of method %s not exported{%v}", mname, replyType)
return nil
}
}
index := 1
// ctxType
if mtype.In(1).String() == "context.Context" {
ctxType = mtype.In(1)
index = 2
}
for ; index < inNum; index++ {
argsType = append(argsType, mtype.In(index))
// need not be a pointer.
if !isExportedOrBuiltinType(mtype.In(index)) {
logger.Errorf("argument type of method %q is not exported %v", mname, mtype.In(index))
return nil
}
}
return &MethodType{method: method, argsType: argsType, replyType: replyType, ctxType: ctxType}
}
// Copyright 2016-2019 Yincheng Fang
//
// Licensed 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 common
import (
"context"
"reflect"
"testing"
)
import (
"github.com/stretchr/testify/assert"
)
type TestService struct {
}
func (s *TestService) MethodOne(ctx context.Context, args []interface{}, rsp *struct{}) error {
return nil
}
func (s *TestService) MethodTwo(args []interface{}) (struct{}, error) {
return struct{}{}, nil
}
func (s *TestService) Service() string {
return "com.test.Path"
}
func (s *TestService) Version() string {
return ""
}
type testService struct {
}
func (s *testService) Method1(ctx context.Context, args testService, rsp *struct{}) error {
return nil
}
func (s *testService) Method2(ctx context.Context, args []interface{}, rsp struct{}) error {
return nil
}
func (s *testService) Method3(ctx context.Context, args []interface{}) (testService, error) {
return testService{}, nil
}
func (s *testService) Method4(ctx context.Context, args []interface{}, rsp *struct{}) {
}
func (s *testService) Method5(ctx context.Context, args []interface{}, rsp *struct{}) *testService {
return nil
}
func (s *testService) Service() string {
return "com.test.Path"
}
func (s *testService) Version() string {
return ""
}
type TestService1 struct {
}
func (s *TestService1) Service() string {
return "com.test.Path1"
}
func (s *TestService1) Version() string {
return ""
}
func TestServiceMap_Register(t *testing.T) {
// lowercase
s0 := &testService{}
methods, err := ServiceMap.Register("testporotocol", s0)
assert.EqualError(t, err, "type testService is not exported")
// succ
s := &TestService{}
methods, err = ServiceMap.Register("testporotocol", s)
assert.NoError(t, err)
assert.Equal(t, "MethodOne,MethodTwo", methods)
// repeat
methods, err = ServiceMap.Register("testporotocol", s)
assert.EqualError(t, err, "service already defined: com.test.Path")
// no method
s1 := &TestService1{}
methods, err = ServiceMap.Register("testporotocol", s1)
assert.EqualError(t, err, "type com.test.Path1 has no exported methods of suitable type")
ServiceMap = &serviceMap{
serviceMap: make(map[string]map[string]*Service),
}
}
func TestServiceMap_UnRegister(t *testing.T) {
s := &TestService{}
_, err := ServiceMap.Register("testprotocol", s)
assert.NoError(t, err)
assert.NotNil(t, ServiceMap.GetService("testprotocol", "com.test.Path"))
err = ServiceMap.UnRegister("", "com.test.Path")
assert.EqualError(t, err, "protocol or serviceName is nil")
err = ServiceMap.UnRegister("protocol", "com.test.Path")
assert.EqualError(t, err, "no services for protocol")
err = ServiceMap.UnRegister("testprotocol", "com.test.Path1")
assert.EqualError(t, err, "no service for com.test.Path1")
// succ
err = ServiceMap.UnRegister("testprotocol", "com.test.Path")
assert.NoError(t, err)
}
func TestMethodType_SuiteContext(t *testing.T) {
mt := &MethodType{ctxType: reflect.TypeOf(context.TODO())}
c := context.TODO()
c = context.WithValue(c, "key", "value")
assert.Equal(t, reflect.ValueOf(c), mt.SuiteContext(c))
assert.Equal(t, reflect.Zero(mt.ctxType), mt.SuiteContext(nil))
}
func TestSuiteMethod(t *testing.T) {
s := &TestService{}
method, ok := reflect.TypeOf(s).MethodByName("MethodOne")
assert.True(t, ok)
methodType := suiteMethod(method)
method = methodType.Method()
assert.Equal(t, "func(*common.TestService, context.Context, []interface {}, *struct {}) error", method.Type.String())
at := methodType.ArgsType()
assert.Equal(t, "[]interface {}", at[0].String())
assert.Equal(t, "*struct {}", at[1].String())
ct := methodType.CtxType()
assert.Equal(t, "context.Context", ct.String())
rt := methodType.ReplyType()
assert.Nil(t, rt)
method, ok = reflect.TypeOf(s).MethodByName("MethodTwo")
assert.True(t, ok)
methodType = suiteMethod(method)
method = methodType.Method()
assert.Equal(t, "func(*common.TestService, []interface {}) (struct {}, error)", method.Type.String())
at = methodType.ArgsType()
assert.Equal(t, "[]interface {}", at[0].String())
assert.Nil(t, methodType.CtxType())
rt = methodType.ReplyType()
assert.Equal(t, "struct {}", rt.String())
// wrong number of in return
s1 := &testService{}
method, ok = reflect.TypeOf(s1).MethodByName("Version")
assert.True(t, ok)
methodType = suiteMethod(method)
assert.Nil(t, methodType)
// args not exported
method, ok = reflect.TypeOf(s1).MethodByName("Method1")
assert.True(t, ok)
methodType = suiteMethod(method)
assert.Nil(t, methodType)
// replyType != Ptr
method, ok = reflect.TypeOf(s1).MethodByName("Method2")
assert.True(t, ok)
methodType = suiteMethod(method)
assert.Nil(t, methodType)
// Reply not exported
method, ok = reflect.TypeOf(s1).MethodByName("Method3")
assert.True(t, ok)
methodType = suiteMethod(method)
assert.Nil(t, methodType)
// no return
method, ok = reflect.TypeOf(s1).MethodByName("Method4")
assert.True(t, ok)
methodType = suiteMethod(method)
assert.Nil(t, methodType)
// return value is not error
method, ok = reflect.TypeOf(s1).MethodByName("Method5")
assert.True(t, ok)
methodType = suiteMethod(method)
assert.Nil(t, methodType)
}
// Copyright 2016-2019 hxmhlt
//
// Licensed 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 common
import (
"context"
"fmt"
"net"
"net/url"
"strconv"
"strings"
)
import (
perrors "github.com/pkg/errors"
)
import (
"github.com/dubbo/go-for-apache-dubbo/common/constant"
)
/////////////////////////////////
// dubbo role type
/////////////////////////////////
const (
CONSUMER = iota
CONFIGURATOR
ROUTER
PROVIDER
)
var (
DubboNodes = [...]string{"consumers", "configurators", "routers", "providers"}
DubboRole = [...]string{"consumer", "", "", "provider"}
)
type RoleType int
func (t RoleType) String() string {
return DubboNodes[t]
}
func (t RoleType) Role() string {
return DubboRole[t]
}
type baseUrl struct {
Protocol string
Location string // ip+port
Ip string
Port string
Params url.Values
PrimitiveURL string
ctx context.Context
}
type URL struct {
baseUrl
Path string // like /com.ikurento.dubbo.UserProvider3
Username string
Password string
Methods []string
//special for registry
SubURL *URL
}
type option func(*URL)
func WithUsername(username string) option {
return func(url *URL) {
url.Username = username
}
}
func WithPassword(pwd string) option {
return func(url *URL) {
url.Password = pwd
}
}
func WithMethods(methods []string) option {
return func(url *URL) {
url.Methods = methods
}
}
func WithParams(params url.Values) option {
return func(url *URL) {
url.Params = params
}
}
func WithParamsValue(key, val string) option {
return func(url *URL) {
url.Params.Set(key, val)
}
}
func WithProtocol(proto string) option {
return func(url *URL) {
url.Protocol = proto
}
}
func WithIp(ip string) option {
return func(url *URL) {
url.Ip = ip
}
}
func WithPort(port string) option {
return func(url *URL) {
url.Port = port
}
}
//func WithPath(path string) option {
// return func(url *URL) {
// url.Path = path
// }
//}
func NewURLWithOptions(service string, opts ...option) *URL {
url := &URL{
Path: "/" + service,
}
for _, opt := range opts {
opt(url)
}
url.Location = url.Ip + ":" + url.Port
return url
}
func NewURL(ctx context.Context, urlString string, opts ...option) (URL, error) {
var (
err error
rawUrlString string
serviceUrl *url.URL
s = URL{baseUrl: baseUrl{ctx: ctx}}
)
// new a null instance
if urlString == "" {
return s, nil
}
rawUrlString, err = url.QueryUnescape(urlString)
if err != nil {
return s, perrors.Errorf("url.QueryUnescape(%s), error{%v}", urlString, err)
}
//rawUrlString = "//" + rawUrlString
serviceUrl, err = url.Parse(rawUrlString)
if err != nil {
return s, perrors.Errorf("url.Parse(url string{%s}), error{%v}", rawUrlString, err)
}
s.Params, err = url.ParseQuery(serviceUrl.RawQuery)
if err != nil {
return s, perrors.Errorf("url.ParseQuery(raw url string{%s}), error{%v}", serviceUrl.RawQuery, err)
}
s.PrimitiveURL = urlString
s.Protocol = serviceUrl.Scheme
s.Username = serviceUrl.User.Username()
s.Password, _ = serviceUrl.User.Password()
s.Location = serviceUrl.Host
s.Path = serviceUrl.Path
if strings.Contains(s.Location, ":") {
s.Ip, s.Port, err = net.SplitHostPort(s.Location)
if err != nil {
return s, perrors.Errorf("net.SplitHostPort(Url.Host{%s}), error{%v}", s.Location, err)
}
}
//
//timeoutStr := s.Params.Get("timeout")
//if len(timeoutStr) == 0 {
// timeoutStr = s.Params.Get("default.timeout")
//}
//if len(timeoutStr) != 0 {
// timeout, err := strconv.Atoi(timeoutStr)
// if err == nil && timeout != 0 {
// s.Timeout = time.Duration(timeout * 1e6) // timeout unit is millisecond
// }
//}
for _, opt := range opts {
opt(&s)
}
//fmt.Println(s.String())
return s, nil
}
//
//func (c URL) Key() string {
// return fmt.Sprintf(
// "%s://%s:%s@%s:%s/%s",
// c.Protocol, c.Username, c.Password, c.Ip, c.Port, c.Path)
//}
func (c URL) URLEqual(url URL) bool {
c.Ip = ""
c.Port = ""
url.Ip = ""
url.Port = ""
if c.Key() != url.Key() {
return false
}
return true
}
//func (c SubURL) String() string {
// return fmt.Sprintf(
// "DefaultServiceURL{protocol:%s, Location:%s, Path:%s, Ip:%s, Port:%s, "+
// "Timeout:%s, Version:%s, Group:%s, Params:%+v}",
// c.protocol, c.Location, c.Path, c.Ip, c.Port,
// c.Timeout, c.Version, c.Group, c.Params)
//}
func (c URL) String() string {
buildString := fmt.Sprintf(
"%s://%s:%s@%s:%s%s?",
c.Protocol, c.Username, c.Password, c.Ip, c.Port, c.Path)
buildString += c.Params.Encode()
return buildString
}
func (c URL) Key() string {
buildString := fmt.Sprintf(
"%s://%s:%s@%s:%s/%s?group=%s&version=%s",
c.Protocol, c.Username, c.Password, c.Ip, c.Port, c.GetParam(constant.INTERFACE_KEY, strings.TrimPrefix(c.Path, "/")), c.GetParam(constant.GROUP_KEY, ""), c.GetParam(constant.VERSION_KEY, constant.DEFAULT_VERSION))
return buildString
}
func (c URL) Context() context.Context {
return c.ctx
}
func (c URL) Service() string {
service := strings.TrimPrefix(c.Path, "/")
if service != "" {
return service
} else if c.SubURL != nil {
service = strings.TrimPrefix(c.SubURL.Path, "/")
if service != "" { //if url.path is "" then return suburl's path, special for registry Url
return service
}
}
return ""
}
func (c URL) GetParam(s string, d string) string {
var r string
if r = c.Params.Get(s); r == "" {
r = d
}
return r
}
func (c URL) GetParamInt(s string, d int64) int64 {
var r int
var err error
if r, err = strconv.Atoi(c.Params.Get(s)); r == 0 || err != nil {
return d
}
return int64(r)
}
func (c URL) GetMethodParamInt(method string, key string, d int64) int64 {
var r int
var err error
if r, err = strconv.Atoi(c.Params.Get("methods." + method + "." + key)); r == 0 || err != nil {
return d
}
return int64(r)
}
func (c URL) GetMethodParam(method string, key string, d string) string {
var r string
if r = c.Params.Get("methods." + method + "." + key); r == "" {
r = d
}
return r
}
// Copyright 2016-2019 hxmhlt
//
// Licensed 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 common
import (
"context"
"net/url"
"testing"
)
import (
"github.com/stretchr/testify/assert"
)
func TestNewURLWithOptions(t *testing.T) {
methods := []string{"Methodone,methodtwo"}
params := url.Values{}
params.Set("key", "value")
u := NewURLWithOptions("com.test.Service",
WithUsername("username"),
WithPassword("password"),
WithProtocol("testprotocol"),
WithIp("127.0.0.1"),
WithPort("8080"),
WithMethods(methods),
WithParams(params),
WithParamsValue("key2", "value2"))
assert.Equal(t, "/com.test.Service", u.Path)
assert.Equal(t, "username", u.Username)
assert.Equal(t, "password", u.Password)
assert.Equal(t, "testprotocol", u.Protocol)
assert.Equal(t, "127.0.0.1", u.Ip)
assert.Equal(t, "8080", u.Port)
assert.Equal(t, methods, u.Methods)
assert.Equal(t, params, u.Params)
}
func TestURL(t *testing.T) {
u, err := NewURL(context.TODO(), "dubbo://:@127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+
"application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+
"environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+
"module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+
"side=provider&timeout=3000&timestamp=1556509797245")
assert.NoError(t, err)
assert.Equal(t, "/com.ikurento.user.UserProvider", u.Path)
assert.Equal(t, "127.0.0.1:20000", u.Location)
assert.Equal(t, "dubbo", u.Protocol)
assert.Equal(t, "127.0.0.1", u.Ip)
assert.Equal(t, "20000", u.Port)
assert.Equal(t, URL{}.Methods, u.Methods)
assert.Equal(t, "", u.Username)
assert.Equal(t, "", u.Password)
assert.Equal(t, "anyhost=true&application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-"+
"provider-golang-1.0.0&environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%"+
"2C&module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&side=provider&timeout=3000&t"+
"imestamp=1556509797245", u.Params.Encode())
assert.Equal(t, "dubbo://:@127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&application=BDTServi"+
"ce&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&environment=dev&interface=com.ikure"+
"nto.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&module=dubbogo+user-info+server&org=ikurento.com&owner="+
"ZX&pid=1447&revision=0.0.1&side=provider&timeout=3000&timestamp=1556509797245", u.String())
}
func TestURL_URLEqual(t *testing.T) {
u1, err := NewURL(context.TODO(), "dubbo://:@127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0")
assert.NoError(t, err)
u2, err := NewURL(context.TODO(), "dubbo://:@127.0.0.2:20001/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0")
assert.NoError(t, err)
assert.True(t, u1.URLEqual(u2))
u3, err := NewURL(context.TODO(), "dubbo://:@127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0")
assert.NoError(t, err)
assert.False(t, u1.URLEqual(u3))
}
func TestURL_GetParam(t *testing.T) {
params := url.Values{}
params.Set("key", "value")
u := URL{baseUrl: baseUrl{Params: params}}
v := u.GetParam("key", "default")
assert.Equal(t, "value", v)
u = URL{}
v = u.GetParam("key", "default")
assert.Equal(t, "default", v)
}
func TestURL_GetParamInt(t *testing.T) {
params := url.Values{}
params.Set("key", "3")
u := URL{baseUrl: baseUrl{Params: params}}
v := u.GetParamInt("key", 1)
assert.Equal(t, int64(3), v)
u = URL{}
v = u.GetParamInt("key", 1)
assert.Equal(t, int64(1), v)
}
func TestURL_GetMethodParamInt(t *testing.T) {
params := url.Values{}
params.Set("methods.GetValue.timeout", "3")
u := URL{baseUrl: baseUrl{Params: params}}
v := u.GetMethodParamInt("GetValue", "timeout", 1)
assert.Equal(t, int64(3), v)
u = URL{}
v = u.GetMethodParamInt("GetValue", "timeout", 1)
assert.Equal(t, int64(1), v)
}
func TestURL_GetMethodParam(t *testing.T) {
params := url.Values{}
params.Set("methods.GetValue.timeout", "3s")
u := URL{baseUrl: baseUrl{Params: params}}
v := u.GetMethodParam("GetValue", "timeout", "1s")
assert.Equal(t, "3s", v)
u = URL{}
v = u.GetMethodParam("GetValue", "timeout", "1s")
assert.Equal(t, "1s", v)
}
// Copyright 2016-2019 Alex Stocks
//
// Licensed 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 utils
import (
"net"
)
import (
perrors "github.com/pkg/errors"
)
var (
privateBlocks []*net.IPNet
)
func init() {
for _, b := range []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"} {
if _, block, err := net.ParseCIDR(b); err == nil {
privateBlocks = append(privateBlocks, block)
}
}
}
// ref: https://stackoverflow.com/questions/23558425/how-do-i-get-the-local-ip-address-in-go
func GetLocalIP() (string, error) {
ifs, err := net.Interfaces()
if err != nil {
return "", perrors.WithStack(err)
}
var ipAddr []byte
for _, i := range ifs {
addrs, err := i.Addrs()
if err != nil {
return "", perrors.WithStack(err)
}
var ip net.IP
for _, addr := range addrs {
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
if !ip.IsLoopback() && ip.To4() != nil && isPrivateIP(ip.String()) {
ipAddr = ip
break
}
}
}
if ipAddr == nil {
return "", perrors.Errorf("can not get local IP")
}
return net.IP(ipAddr).String(), nil
}
func isPrivateIP(ipAddr string) bool {
ip := net.ParseIP(ipAddr)
for _, priv := range privateBlocks {
if priv.Contains(ip) {
return true
}
}
return false
}
package utils
import (
"testing"
)
import (
"github.com/stretchr/testify/assert"
)
func TestGetLocalIP(t *testing.T) {
ip, err := GetLocalIP()
assert.NoError(t, err)
t.Log(ip)
}
// Copyright 2016-2019 hxmhlt
//
// Licensed 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 config
type ApplicationConfig struct {
Organization string `yaml:"organization" json:"organization,omitempty"`
Name string `yaml:"name" json:"name,omitempty"`
Module string `yaml:"module" json:"module,omitempty"`
Version string `yaml:"version" json:"version,omitempty"`
Owner string `yaml:"owner" json:"owner,omitempty"`
Environment string `yaml:"environment" json:"environment,omitempty"`
}
// Copyright 2016-2019 Yincheng Fang
//
// Licensed 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 config
import (
"fmt"
"io/ioutil"
"log"
"os"
"path"
"strings"
"time"
)
import (
perrors "github.com/pkg/errors"
"gopkg.in/yaml.v2"
)
import (
"github.com/dubbo/go-for-apache-dubbo/common/constant"
"github.com/dubbo/go-for-apache-dubbo/common/logger"
"github.com/dubbo/go-for-apache-dubbo/version"
)
var (
consumerConfig *ConsumerConfig
providerConfig *ProviderConfig
maxWait = 3
)
// loaded comsumer & provider config from xxx.yml, and log config from xxx.xml
// Namely: dubbo.comsumer.xml & dubbo.provider.xml in java dubbo
func init() {
var (
confConFile, confProFile string
)
confConFile = os.Getenv(constant.CONF_CONSUMER_FILE_PATH)
confProFile = os.Getenv(constant.CONF_PROVIDER_FILE_PATH)
if errCon := consumerInit(confConFile); errCon != nil {
log.Printf("[consumerInit] %#v", errCon)
consumerConfig = nil
}
if errPro := providerInit(confProFile); errPro != nil {
log.Printf("[providerInit] %#v", errPro)
providerConfig = nil
}
}
func consumerInit(confConFile string) error {
if confConFile == "" {
return perrors.Errorf("application configure(consumer) file name is nil")
}
if path.Ext(confConFile) != ".yml" {
return perrors.Errorf("application configure file name{%v} suffix must be .yml", confConFile)
}
confFileStream, err := ioutil.ReadFile(confConFile)
if err != nil {
return perrors.Errorf("ioutil.ReadFile(file:%s) = error:%v", confConFile, perrors.WithStack(err))
}
consumerConfig = &ConsumerConfig{}
err = yaml.Unmarshal(confFileStream, consumerConfig)
if err != nil {
return perrors.Errorf("yaml.Unmarshal() = error:%v", perrors.WithStack(err))
}
if consumerConfig.RequestTimeout, err = time.ParseDuration(consumerConfig.Request_Timeout); err != nil {
return perrors.WithMessagef(err, "time.ParseDuration(Request_Timeout{%#v})", consumerConfig.Request_Timeout)
}
if consumerConfig.ConnectTimeout, err = time.ParseDuration(consumerConfig.Connect_Timeout); err != nil {
return perrors.WithMessagef(err, "time.ParseDuration(Connect_Timeout{%#v})", consumerConfig.Connect_Timeout)
}
logger.Debugf("consumer config{%#v}\n", consumerConfig)
return nil
}
func providerInit(confProFile string) error {
if confProFile == "" {
return perrors.Errorf("application configure(provider) file name is nil")
}
if path.Ext(confProFile) != ".yml" {
return perrors.Errorf("application configure file name{%v} suffix must be .yml", confProFile)
}
confFileStream, err := ioutil.ReadFile(confProFile)
if err != nil {
return perrors.Errorf("ioutil.ReadFile(file:%s) = error:%v", confProFile, perrors.WithStack(err))
}
providerConfig = &ProviderConfig{}
err = yaml.Unmarshal(confFileStream, providerConfig)
if err != nil {
return perrors.Errorf("yaml.Unmarshal() = error:%v", perrors.WithStack(err))
}
logger.Debugf("provider config{%#v}\n", providerConfig)
return nil
}
/////////////////////////
// consumerConfig
/////////////////////////
type ConsumerConfig struct {
Filter string `yaml:"filter" json:"filter,omitempty"`
// client
Connect_Timeout string `default:"100ms" yaml:"connect_timeout" json:"connect_timeout,omitempty"`
ConnectTimeout time.Duration
Request_Timeout string `yaml:"request_timeout" default:"5s" json:"request_timeout,omitempty"`
RequestTimeout time.Duration
ProxyFactory string `yaml:"proxy_factory" default:"default" json:"proxy_factory,omitempty"`
Check *bool `yaml:"check" json:"check,omitempty"`
// application
ApplicationConfig ApplicationConfig `yaml:"application_config" json:"application_config,omitempty"`
Registries []RegistryConfig `yaml:"registries" json:"registries,omitempty"`
References []ReferenceConfig `yaml:"references" json:"references,omitempty"`
ProtocolConf interface{} `yaml:"protocol_conf" json:"protocol_conf,omitempty"`
}
type ReferenceConfigTmp struct {
Service string `required:"true" yaml:"service" json:"service,omitempty"`
Registries []RegistryConfig `required:"true" yaml:"registries" json:"registries,omitempty"`
URLs []map[string]string
}
func SetConsumerConfig(c ConsumerConfig) {
consumerConfig = &c
}
func GetConsumerConfig() ConsumerConfig {
if consumerConfig == nil {
logger.Warnf("consumerConfig is nil!")
return ConsumerConfig{}
}
return *consumerConfig
}
/////////////////////////
// providerConfig
/////////////////////////
type ProviderConfig struct {
Filter string `yaml:"filter" json:"filter,omitempty"`
ProxyFactory string `yaml:"proxy_factory" default:"default" json:"proxy_factory,omitempty"`
ApplicationConfig ApplicationConfig `yaml:"application_config" json:"application_config,omitempty"`
Registries []RegistryConfig `yaml:"registries" json:"registries,omitempty"`
Services []ServiceConfig `yaml:"services" json:"services,omitempty"`
Protocols []ProtocolConfig `yaml:"protocols" json:"protocols,omitempty"`
ProtocolConf interface{} `yaml:"protocol_conf" json:"protocol_conf,omitempty"`
}
func GetProviderConfig() ProviderConfig {
if providerConfig == nil {
logger.Warnf("providerConfig is nil!")
return ProviderConfig{}
}
return *providerConfig
}
type ProtocolConfig struct {
Name string `required:"true" yaml:"name" json:"name,omitempty"`
Ip string `required:"true" yaml:"ip" json:"ip,omitempty"`
Port string `required:"true" yaml:"port" json:"port,omitempty"`
ContextPath string `required:"true" yaml:"contextPath" json:"contextPath,omitempty"`
}
func loadProtocol(protocolsIds string, protocols []ProtocolConfig) []ProtocolConfig {
returnProtocols := []ProtocolConfig{}
for _, v := range strings.Split(protocolsIds, ",") {
for _, prot := range protocols {
if v == prot.Name {
returnProtocols = append(returnProtocols, prot)
}
}
}
return returnProtocols
}
// Dubbo Init
func Load() (map[string]*ReferenceConfig, map[string]*ServiceConfig) {
var refMap map[string]*ReferenceConfig
var srvMap map[string]*ServiceConfig
// reference config
if consumerConfig == nil {
logger.Warnf("consumerConfig is nil!")
} else {
refMap = make(map[string]*ReferenceConfig)
length := len(consumerConfig.References)
for index := 0; index < length; index++ {
con := &consumerConfig.References[index]
rpcService := GetConsumerService(con.InterfaceName)
if rpcService == nil {
logger.Warnf("%s is not exsist!", con.InterfaceName)
continue
}
con.Refer()
con.Implement(rpcService)
refMap[con.InterfaceName] = con
}
//wait for invoker is available, if wait over default 3s, then panic
var count int
checkok := true
for {
for _, refconfig := range consumerConfig.References {
if (refconfig.Check != nil && *refconfig.Check) ||
(refconfig.Check == nil && consumerConfig.Check != nil && *consumerConfig.Check) ||
(refconfig.Check == nil && consumerConfig.Check == nil) { //default to true
if refconfig.invoker != nil &&
!refconfig.invoker.IsAvailable() {
checkok = false
count++
if count > maxWait {
panic(fmt.Sprintf("Failed to check the status of the service %v . No provider available for the service to the consumer use dubbo version %v", refconfig.InterfaceName, version.Version))
}
time.Sleep(time.Second * 1)
break
}
if refconfig.invoker == nil {
logger.Warnf("The interface %s invoker not exsist , may you should check your interface config.", refconfig.InterfaceName)
}
}
}
if checkok {
break
}
checkok = true
}
}
// service config
if providerConfig == nil {
logger.Warnf("providerConfig is nil!")
} else {
srvMap = make(map[string]*ServiceConfig)
length := len(providerConfig.Services)
for index := 0; index < length; index++ {
pro := &providerConfig.Services[index]
rpcService := GetProviderService(pro.InterfaceName)
if rpcService == nil {
logger.Warnf("%s is not exsist!", pro.InterfaceName)
continue
}
pro.Implement(rpcService)
if err := pro.Export(); err != nil {
panic(fmt.Sprintf("service %s export failed! ", pro.InterfaceName))
}
srvMap[pro.InterfaceName] = pro
}
}
return refMap, srvMap
}
// Copyright 2016-2019 Yincheng Fang
//
// Licensed 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 config
import (
"github.com/dubbo/go-for-apache-dubbo/common/proxy/proxy_factory"
"path/filepath"
"testing"
)
import (
"github.com/stretchr/testify/assert"
)
import (
"github.com/dubbo/go-for-apache-dubbo/cluster/cluster_impl"
"github.com/dubbo/go-for-apache-dubbo/common"
"github.com/dubbo/go-for-apache-dubbo/common/extension"
)
func TestConfigLoader(t *testing.T) {
conPath, err := filepath.Abs("./testdata/consumer_config.yml")
assert.NoError(t, err)
proPath, err := filepath.Abs("./testdata/provider_config.yml")
assert.NoError(t, err)
assert.Nil(t, consumerConfig)
assert.Equal(t, ConsumerConfig{}, GetConsumerConfig())
assert.Nil(t, providerConfig)
assert.Equal(t, ProviderConfig{}, GetProviderConfig())
err = consumerInit(conPath)
assert.NoError(t, err)
err = providerInit(proPath)
assert.NoError(t, err)
assert.NotNil(t, consumerConfig)
assert.NotEqual(t, ConsumerConfig{}, GetConsumerConfig())
assert.NotNil(t, providerConfig)
assert.NotEqual(t, ProviderConfig{}, GetProviderConfig())
}
func TestLoad(t *testing.T) {
doInit()
doinit()
SetConsumerService(&MockService{})
SetProviderService(&MockService{})
extension.SetProtocol("registry", GetProtocol)
extension.SetCluster("registryAware", cluster_impl.NewRegistryAwareCluster)
extension.SetProxyFactory("default", proxy_factory.NewDefaultProxyFactory)
consumerConfig.References[0].Registries = []ConfigRegistry{"shanghai_reg1"}
refConfigs, svcConfigs := Load()
assert.NotEqual(t, 0, len(refConfigs))
assert.NotEqual(t, 0, len(svcConfigs))
conServices = map[string]common.RPCService{}
proServices = map[string]common.RPCService{}
common.ServiceMap.UnRegister("mock", "MockService")
consumerConfig = nil
providerConfig = nil
}
package config
import (
"regexp"
"strings"
)
import (
"github.com/dubbo/go-for-apache-dubbo/common/constant"
)
func mergeValue(str1, str2, def string) string {
if str1 == "" && str2 == "" {
return def
}
str := "," + strings.Trim(str1, ",")
if str1 == "" {
str = "," + strings.Trim(str2, ",")
} else if str2 != "" {
str = str + "," + strings.Trim(str2, ",")
}
defKey := strings.Contains(str, ","+constant.DEFAULT_KEY)
if !defKey {
str = "," + constant.DEFAULT_KEY + str
}
str = strings.TrimPrefix(strings.Replace(str, ","+constant.DEFAULT_KEY, ","+def, -1), ",")
strArr := strings.Split(str, ",")
strMap := make(map[string][]int)
for k, v := range strArr {
add := true
if strings.HasPrefix(v, "-") {
v = v[1:]
add = false
}
if _, ok := strMap[v]; !ok {
if add {
strMap[v] = []int{1, k}
}
} else {
if add {
strMap[v][0] += 1
strMap[v] = append(strMap[v], k)
} else {
strMap[v][0] -= 1
strMap[v] = strMap[v][:len(strMap[v])-1]
}
}
}
strArr = make([]string, len(strArr))
for key, value := range strMap {
if value[0] == 0 {
continue
}
for i := 1; i < len(value); i++ {
strArr[value[i]] = key
}
}
reg := regexp.MustCompile("[,]+")
str = reg.ReplaceAllString(strings.Join(strArr, ","), ",")
return strings.Trim(str, ",")
}
package config
import (
"testing"
)
import (
"github.com/stretchr/testify/assert"
)
func TestMergeValue(t *testing.T) {
str := mergeValue("", "", "a,b")
assert.Equal(t, "a,b", str)
str = mergeValue("c,d", "e,f", "a,b")
assert.Equal(t, "a,b,c,d,e,f", str)
str = mergeValue("c,d", "e,d,f", "a,b")
assert.Equal(t, "a,b,c,d,e,d,f", str)
str = mergeValue("c,default,d", "-c,-a,e,f", "a,b")
assert.Equal(t, "b,d,e,f", str)
str = mergeValue("", "default,-b,e,f", "a,b")
assert.Equal(t, "a,e,f", str)
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment