Skip to content
Snippets Groups Projects
Commit 8d3329f5 authored by vito.he's avatar vito.he
Browse files

Merge branch 'develop' into metadata_report

parents 0b0fde89 bda0ddc3
No related branches found
No related tags found
No related merge requests found
Showing
with 119 additions and 56 deletions
......@@ -16,6 +16,8 @@ Apache License, Version 2.0
## Release note ##
[v1.4.0-rc1 - Mar 12, 2020](https://github.com/apache/dubbo-go/releases/tag/v1.4.0-rc1)
[v1.3.0 - Mar 1, 2020](https://github.com/apache/dubbo-go/releases/tag/v1.3.0)
[v1.2.0 - Nov 15, 2019](https://github.com/apache/dubbo-go/releases/tag/v1.2.0)
......@@ -28,7 +30,7 @@ Apache License, Version 2.0
Both extension module and layered project architecture is according to Apache Dubbo (including protocol layer, registry layer, cluster layer, config layer and so on), the advantage of this arch is as following: you can implement these layered interfaces in your own way, override the default implementation of dubbo-go by calling 'extension.SetXXX' of extension, complete your special needs without modifying the source code. At the same time, you are welcome to contribute implementation of useful extension to the community.
![frame design](https://raw.githubusercontent.com/wiki/dubbo/dubbo-go/dubbo-go%E4%BB%A3%E7%A0%81%E5%88%86%E5%B1%82%E8%AE%BE%E8%AE%A1.png)
![dubbo go extend](./doc/pic/arch/dubbo-go-ext.png)
If you wanna know more about dubbo-go, please visit this reference [Project Architeture design](https://github.com/apache/dubbo-go/wiki/dubbo-go-V1.0-design)
......
......@@ -15,6 +15,8 @@ Apache License, Version 2.0
## 发布日志 ##
[v1.4.0-rc1 - 2020年3月12日](https://github.com/apache/dubbo-go/releases/tag/v1.4.0-rc1)
[v1.3.0 - 2020年3月1日](https://github.com/apache/dubbo-go/releases/tag/v1.3.0)
[v1.2.0 - 2019年11月15日](https://github.com/apache/dubbo-go/releases/tag/v1.2.0)
......@@ -27,7 +29,7 @@ Apache License, Version 2.0
基于dubbo的extension模块和分层的代码设计(包括 protocol layer, registry layer, cluster layer, config 等等)。我们的目标是:你可以对这些分层接口进行新的实现,并通过调用 extension 模块的“ extension.SetXXX ”方法来覆盖 dubbo-go [同 go-for-apache-dubbo ]的默认实现,以完成自己的特殊需求而无需修改源代码。同时,欢迎你为社区贡献有用的拓展实现。
![框架设计](https://raw.githubusercontent.com/wiki/dubbo/dubbo-go/dubbo-go%E4%BB%A3%E7%A0%81%E5%88%86%E5%B1%82%E8%AE%BE%E8%AE%A1.png)
![dubbo go extend](./doc/pic/arch/dubbo-go-ext.png)
关于详细设计请阅读 [code layered design](https://github.com/apache/dubbo-go/wiki/dubbo-go-V1.0-design)
......
......@@ -71,7 +71,8 @@ var (
// ServiceMap ...
// todo: lowerecas?
ServiceMap = &serviceMap{
serviceMap: make(map[string]map[string]*Service),
serviceMap: make(map[string]map[string]*Service),
interfaceMap: make(map[string][]*Service),
}
)
......@@ -152,10 +153,12 @@ func (s *Service) Rcvr() reflect.Value {
//////////////////////////
type serviceMap struct {
mutex sync.RWMutex // protects the serviceMap
serviceMap map[string]map[string]*Service // protocol -> service name -> service
mutex sync.RWMutex // protects the serviceMap
serviceMap map[string]map[string]*Service // protocol -> service name -> service
interfaceMap map[string][]*Service // interface -> service
}
// GetService get a service defination by protocol and name
func (sm *serviceMap) GetService(protocol, name string) *Service {
sm.mutex.RLock()
defer sm.mutex.RUnlock()
......@@ -168,10 +171,24 @@ func (sm *serviceMap) GetService(protocol, name string) *Service {
return nil
}
func (sm *serviceMap) Register(protocol string, rcvr RPCService) (string, error) {
// GetInterface get an interface defination by interface name
func (sm *serviceMap) GetInterface(interfaceName string) []*Service {
sm.mutex.RLock()
defer sm.mutex.RUnlock()
if s, ok := sm.interfaceMap[interfaceName]; ok {
return s
}
return nil
}
// Register register a service by @interfaceName and @protocol
func (sm *serviceMap) Register(interfaceName, protocol string, rcvr RPCService) (string, error) {
if sm.serviceMap[protocol] == nil {
sm.serviceMap[protocol] = make(map[string]*Service)
}
if sm.interfaceMap[interfaceName] == nil {
sm.interfaceMap[interfaceName] = make([]*Service, 0, 16)
}
s := new(Service)
s.rcvrType = reflect.TypeOf(rcvr)
......@@ -206,32 +223,65 @@ func (sm *serviceMap) Register(protocol string, rcvr RPCService) (string, error)
}
sm.mutex.Lock()
sm.serviceMap[protocol][s.name] = s
sm.interfaceMap[interfaceName] = append(sm.interfaceMap[interfaceName], s)
sm.mutex.Unlock()
return strings.TrimSuffix(methods, ","), nil
}
func (sm *serviceMap) UnRegister(protocol, serviceId string) error {
// UnRegister cancel a service by @interfaceName, @protocol and @serviceId
func (sm *serviceMap) UnRegister(interfaceName, protocol, serviceId string) error {
if protocol == "" || serviceId == "" {
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)
var (
err error
index = -1
svcs map[string]*Service
svrs []*Service
ok bool
)
f := func() error {
sm.mutex.RLock()
defer sm.mutex.RUnlock()
svcs, ok = sm.serviceMap[protocol]
if !ok {
return perrors.New("no services for " + protocol)
}
s, ok := svcs[serviceId]
if !ok {
return perrors.New("no service for " + serviceId)
}
svrs, ok = sm.interfaceMap[interfaceName]
if !ok {
return perrors.New("no service for " + interfaceName)
}
for i, svr := range svrs {
if svr == s {
index = i
}
}
return nil
}
_, ok = svcs[serviceId]
if !ok {
sm.mutex.RUnlock()
return perrors.New("no service for " + serviceId)
if err = f(); err != nil {
return err
}
sm.mutex.RUnlock()
sm.mutex.Lock()
defer sm.mutex.Unlock()
sm.interfaceMap[interfaceName] = make([]*Service, 0, len(svrs))
for i, _ := range svrs {
if i != index {
sm.interfaceMap[interfaceName] = append(sm.interfaceMap[interfaceName], svrs[i])
}
}
delete(svcs, serviceId)
delete(sm.serviceMap, protocol)
if len(sm.serviceMap) == 0 {
delete(sm.serviceMap, protocol)
}
return nil
}
......
......@@ -77,46 +77,48 @@ func TestServiceMap_Register(t *testing.T) {
// lowercase
s0 := &testService{}
// methods, err := ServiceMap.Register("testporotocol", s0)
_, err := ServiceMap.Register("testporotocol", s0)
_, err := ServiceMap.Register("testService", "testporotocol", s0)
assert.EqualError(t, err, "type testService is not exported")
// succ
s := &TestService{}
methods, err := ServiceMap.Register("testporotocol", s)
methods, err := ServiceMap.Register("testService", "testporotocol", s)
assert.NoError(t, err)
assert.Equal(t, "MethodOne,MethodThree,methodTwo", methods)
// repeat
_, err = ServiceMap.Register("testporotocol", s)
_, err = ServiceMap.Register("testService", "testporotocol", s)
assert.EqualError(t, err, "service already defined: com.test.Path")
// no method
s1 := &TestService1{}
_, err = ServiceMap.Register("testporotocol", s1)
_, err = ServiceMap.Register("testService", "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),
serviceMap: make(map[string]map[string]*Service),
interfaceMap: make(map[string][]*Service),
}
}
func TestServiceMap_UnRegister(t *testing.T) {
s := &TestService{}
_, err := ServiceMap.Register("testprotocol", s)
_, err := ServiceMap.Register("TestService", "testprotocol", s)
assert.NoError(t, err)
assert.NotNil(t, ServiceMap.GetService("testprotocol", "com.test.Path"))
assert.Equal(t, 1, len(ServiceMap.GetInterface("TestService")))
err = ServiceMap.UnRegister("", "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")
err = ServiceMap.UnRegister("", "protocol", "com.test.Path")
assert.EqualError(t, err, "no services for protocol")
err = ServiceMap.UnRegister("testprotocol", "com.test.Path1")
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")
err = ServiceMap.UnRegister("TestService", "testprotocol", "com.test.Path")
assert.NoError(t, err)
}
......
......@@ -200,7 +200,7 @@ func Load() {
svs.Implement(rpcService)
svs.Protocols = providerConfig.Protocols
if err := svs.Export(); err != nil {
panic(fmt.Sprintf("service %s export failed! ", key))
panic(fmt.Sprintf("service %s export failed! err: %#v", key, err))
}
}
}
......
......@@ -82,7 +82,8 @@ func TestLoad(t *testing.T) {
conServices = map[string]common.RPCService{}
proServices = map[string]common.RPCService{}
common.ServiceMap.UnRegister("mock", "MockService")
err := common.ServiceMap.UnRegister("com.MockService", "mock", "MockService")
assert.Nil(t, err)
consumerConfig = nil
providerConfig = nil
}
......@@ -110,7 +111,7 @@ func TestLoadWithSingleReg(t *testing.T) {
conServices = map[string]common.RPCService{}
proServices = map[string]common.RPCService{}
common.ServiceMap.UnRegister("mock", "MockService")
common.ServiceMap.UnRegister("com.MockService", "mock", "MockService")
consumerConfig = nil
providerConfig = nil
}
......@@ -139,7 +140,7 @@ func TestWithNoRegLoad(t *testing.T) {
conServices = map[string]common.RPCService{}
proServices = map[string]common.RPCService{}
common.ServiceMap.UnRegister("mock", "MockService")
common.ServiceMap.UnRegister("com.MockService", "mock", "MockService")
consumerConfig = nil
providerConfig = nil
}
......
......@@ -188,7 +188,7 @@ func (c *ReferenceConfig) getUrlMap() url.Values {
urlMap.Set(constant.VERSION_KEY, c.Version)
urlMap.Set(constant.GENERIC_KEY, strconv.FormatBool(c.Generic))
urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER))
urlMap.Set(constant.CATEGORY_KEY, (common.RoleType(common.CONSUMER)).String())
urlMap.Set(constant.RELEASE_KEY, "dubbo-golang-"+constant.Version)
urlMap.Set(constant.SIDE_KEY, (common.RoleType(common.CONSUMER)).Role())
......
......@@ -138,7 +138,7 @@ func (c *ServiceConfig) Export() error {
}
for _, proto := range protocolConfigs {
// registry the service reflect
methods, err := common.ServiceMap.Register(proto.Name, c.rpcService)
methods, err := common.ServiceMap.Register(c.InterfaceName, proto.Name, c.rpcService)
if err != nil {
err := perrors.Errorf("The service %v export the protocol %v error! Error message is %v .", c.InterfaceName, proto.Name, err.Error())
logger.Errorf(err.Error())
......@@ -225,7 +225,6 @@ func (c *ServiceConfig) getUrlMap() url.Values {
urlMap.Set(constant.GROUP_KEY, c.Group)
urlMap.Set(constant.VERSION_KEY, c.Version)
urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))
urlMap.Set(constant.CATEGORY_KEY, (common.RoleType(common.PROVIDER)).String())
urlMap.Set(constant.RELEASE_KEY, "dubbo-golang-"+constant.Version)
urlMap.Set(constant.SIDE_KEY, (common.RoleType(common.PROVIDER)).Role())
......
......@@ -76,7 +76,7 @@ func newZookeeperDynamicConfiguration(url *common.URL) (*zookeeperDynamicConfigu
c.cacheListener = NewCacheListener(c.rootPath)
err = c.client.Create(c.rootPath)
c.listener.ListenServiceEvent(c.rootPath, c.cacheListener)
c.listener.ListenServiceEvent(url, c.rootPath, c.cacheListener)
return c, err
}
......@@ -102,7 +102,7 @@ func newMockZookeeperDynamicConfiguration(url *common.URL, opts ...zookeeper.Opt
c.cacheListener = NewCacheListener(c.rootPath)
err = c.client.Create(c.rootPath)
go c.listener.ListenServiceEvent(c.rootPath, c.cacheListener)
go c.listener.ListenServiceEvent(url, c.rootPath, c.cacheListener)
return tc, c, err
}
......
doc/pic/arch/dubbo-go-arch.png

211 KiB | W: | H:

doc/pic/arch/dubbo-go-arch.png

128 KiB | W: | H:

doc/pic/arch/dubbo-go-arch.png
doc/pic/arch/dubbo-go-arch.png
doc/pic/arch/dubbo-go-arch.png
doc/pic/arch/dubbo-go-arch.png
  • 2-up
  • Swipe
  • Onion skin
doc/pic/arch/dubbo-go-ext.png

119 KiB

......@@ -96,7 +96,7 @@ func TestGenericServiceFilter_Invoke(t *testing.T) {
hessian.Object("222")},
}
s := &TestService{}
_, _ = common.ServiceMap.Register("testprotocol", s)
_, _ = common.ServiceMap.Register("TestService", "testprotocol", s)
rpcInvocation := invocation.NewRPCInvocation(methodName, aurguments, nil)
filter := GetGenericServiceFilter()
url, _ := common.NewURL("testprotocol://127.0.0.1:20000/com.test.Path")
......
......@@ -162,7 +162,7 @@ func InitTest(t *testing.T) (protocol.Protocol, common.URL) {
hessian.RegisterPOJO(&User{})
methods, err := common.ServiceMap.Register("dubbo", &UserProvider{})
methods, err := common.ServiceMap.Register("com.ikurento.user.UserProvider", "dubbo", &UserProvider{})
assert.NoError(t, err)
assert.Equal(t, "GetBigPkg,GetUser,GetUser0,GetUser1,GetUser2,GetUser3,GetUser4,GetUser5,GetUser6", methods)
......
......@@ -43,8 +43,9 @@ func NewDubboExporter(key string, invoker protocol.Invoker, exporterMap *sync.Ma
// Unexport ...
func (de *DubboExporter) Unexport() {
serviceId := de.GetInvoker().GetUrl().GetParam(constant.BEAN_NAME_KEY, "")
interfaceName := de.GetInvoker().GetUrl().GetParam(constant.INTERFACE_KEY, "")
de.BaseExporter.Unexport()
err := common.ServiceMap.UnRegister(DUBBO, serviceId)
err := common.ServiceMap.UnRegister(interfaceName, DUBBO, serviceId)
if err != nil {
logger.Errorf("[DubboExporter.Unexport] error: %v", err)
}
......
......@@ -43,8 +43,9 @@ func NewGrpcExporter(key string, invoker protocol.Invoker, exporterMap *sync.Map
// Unexport ...
func (gg *GrpcExporter) Unexport() {
serviceId := gg.GetInvoker().GetUrl().GetParam(constant.BEAN_NAME_KEY, "")
interfaceName := gg.GetInvoker().GetUrl().GetParam(constant.INTERFACE_KEY, "")
gg.BaseExporter.Unexport()
err := common.ServiceMap.UnRegister(GRPC, serviceId)
err := common.ServiceMap.UnRegister(interfaceName, GRPC, serviceId)
if err != nil {
logger.Errorf("[GrpcExporter.Unexport] error: %v", err)
}
......
......@@ -50,7 +50,7 @@ type (
func TestHTTPClient_Call(t *testing.T) {
methods, err := common.ServiceMap.Register("jsonrpc", &UserProvider{})
methods, err := common.ServiceMap.Register("com.ikurento.user.UserProvider", "jsonrpc", &UserProvider{})
assert.NoError(t, err)
assert.Equal(t, "GetUser,GetUser0,GetUser1,GetUser2,GetUser3,GetUser4", methods)
......
......@@ -43,8 +43,9 @@ func NewJsonrpcExporter(key string, invoker protocol.Invoker, exporterMap *sync.
// Unexport ...
func (je *JsonrpcExporter) Unexport() {
serviceId := je.GetInvoker().GetUrl().GetParam(constant.BEAN_NAME_KEY, "")
interfaceName := je.GetInvoker().GetUrl().GetParam(constant.INTERFACE_KEY, "")
je.BaseExporter.Unexport()
err := common.ServiceMap.UnRegister(JSONRPC, serviceId)
err := common.ServiceMap.UnRegister(interfaceName, JSONRPC, serviceId)
if err != nil {
logger.Errorf("[JsonrpcExporter.Unexport] error: %v", err)
}
......
......@@ -36,7 +36,7 @@ import (
func TestJsonrpcInvoker_Invoke(t *testing.T) {
methods, err := common.ServiceMap.Register("jsonrpc", &UserProvider{})
methods, err := common.ServiceMap.Register("UserProvider", "jsonrpc", &UserProvider{})
assert.NoError(t, err)
assert.Equal(t, "GetUser,GetUser0,GetUser1,GetUser2,GetUser3,GetUser4", methods)
......
......@@ -40,10 +40,12 @@ func init() {
extension.SetRestClient(constant.DEFAULT_REST_CLIENT, NewRestyClient)
}
// RestyClient a rest client implement by Resty
type RestyClient struct {
client *resty.Client
}
// NewRestyClient a constructor of RestyClient
func NewRestyClient(restOption *client.RestOptions) client.RestClient {
client := resty.New()
client.SetTransport(
......@@ -65,21 +67,21 @@ func NewRestyClient(restOption *client.RestOptions) client.RestClient {
}
}
func (rc *RestyClient) Do(restRequest *client.RestRequest, res interface{}) error {
r, err := rc.client.R().
SetHeader("Content-Type", restRequest.Consumes).
SetHeader("Accept", restRequest.Produces).
// Do send request by RestyClient
func (rc *RestyClient) Do(restRequest *client.RestClientRequest, res interface{}) error {
req := rc.client.R()
req.Header = restRequest.Header
resp, err := req.
SetPathParams(restRequest.PathParams).
SetQueryParams(restRequest.QueryParams).
SetHeaders(restRequest.Headers).
SetBody(restRequest.Body).
SetResult(res).
Execute(restRequest.Method, "http://"+path.Join(restRequest.Location, restRequest.Path))
if err != nil {
return perrors.WithStack(err)
}
if r.IsError() {
return perrors.New(r.String())
if resp.IsError() {
return perrors.New(resp.String())
}
return nil
}
......@@ -18,26 +18,28 @@
package client
import (
"net/http"
"time"
)
// RestOptions
type RestOptions struct {
RequestTimeout time.Duration
ConnectTimeout time.Duration
}
type RestRequest struct {
// RestClientRequest
type RestClientRequest struct {
Header http.Header
Location string
Path string
Produces string
Consumes string
Method string
PathParams map[string]string
QueryParams map[string]string
Body interface{}
Headers map[string]string
}
// RestClient user can implement this client interface to send request
type RestClient interface {
Do(request *RestRequest, res interface{}) error
Do(request *RestClientRequest, res interface{}) error
}
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