refactor to support other rpc clients

This commit is contained in:
smallnest
2021-04-09 21:01:11 +08:00
parent 7cece5b70e
commit fa5e5976dc
3 changed files with 88 additions and 38 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

+7
View File
@@ -94,6 +94,8 @@ type RPCClient interface {
IsClosing() bool IsClosing() bool
IsShutdown() bool IsShutdown() bool
GetConn() net.Conn
} }
// Client represents a RPC client. // Client represents a RPC client.
@@ -129,6 +131,11 @@ func (c *Client) RemoteAddr() string {
return c.Conn.RemoteAddr().String() return c.Conn.RemoteAddr().String()
} }
// GetConn returns the underlying conn.
func (c *Client) GetConn() net.Conn {
return c.Conn
}
// Option contains all options for creating clients. // Option contains all options for creating clients.
type Option struct { type Option struct {
// Group is used to select the services in the same group. Services set group info in their meta. // Group is used to select the services in the same group. Services set group info in their meta.
+81 -38
View File
@@ -53,6 +53,15 @@ type XClient interface {
DownloadFile(ctx context.Context, requestFileName string, saveTo io.Writer, meta map[string]string) error DownloadFile(ctx context.Context, requestFileName string, saveTo io.Writer, meta map[string]string) error
Stream(ctx context.Context, meta map[string]string) (net.Conn, error) Stream(ctx context.Context, meta map[string]string) (net.Conn, error)
Close() error Close() error
RegisterCacheClientBuilder(network string, builder CacheClientBuilder)
}
type CacheClientBuilder interface {
setCachedClient(client RPCClient, k, servicePath, serviceMethod string)
findCachedClient(k, servicePath, serviceMethod string) RPCClient
deleteCachedClient(client RPCClient, k, servicePath, serviceMethod string)
generateClient(k, servicePath, serviceMethod string) (client RPCClient, err error)
} }
// KVPair contains a key and a string. // KVPair contains a key and a string.
@@ -84,10 +93,11 @@ type xClient struct {
servicePath string servicePath string
option Option option Option
mu sync.RWMutex mu sync.RWMutex
servers map[string]string servers map[string]string
discovery ServiceDiscovery discovery ServiceDiscovery
selector Selector selector Selector
cacheClientBuilders map[string]CacheClientBuilder
slGroup singleflight.Group slGroup singleflight.Group
@@ -106,12 +116,13 @@ type xClient struct {
// NewXClient creates a XClient that supports service discovery and service governance. // NewXClient creates a XClient that supports service discovery and service governance.
func NewXClient(servicePath string, failMode FailMode, selectMode SelectMode, discovery ServiceDiscovery, option Option) XClient { func NewXClient(servicePath string, failMode FailMode, selectMode SelectMode, discovery ServiceDiscovery, option Option) XClient {
client := &xClient{ client := &xClient{
failMode: failMode, failMode: failMode,
selectMode: selectMode, selectMode: selectMode,
discovery: discovery, discovery: discovery,
servicePath: servicePath, servicePath: servicePath,
cachedClient: make(map[string]RPCClient), cachedClient: make(map[string]RPCClient),
option: option, cacheClientBuilders: make(map[string]CacheClientBuilder),
option: option,
} }
pairs := discovery.GetServices() pairs := discovery.GetServices()
@@ -171,6 +182,12 @@ func NewBidirectionalXClient(servicePath string, failMode FailMode, selectMode S
return client return client
} }
func (c *xClient) RegisterCacheClientBuilder(network string, builder CacheClientBuilder) {
c.mu.Lock()
c.mu.Unlock()
c.cacheClientBuilders[network] = builder
}
// SetSelector sets customized selector by users. // SetSelector sets customized selector by users.
func (c *xClient) SetSelector(s Selector) { func (c *xClient) SetSelector(s Selector) {
c.mu.RLock() c.mu.RLock()
@@ -255,7 +272,7 @@ func (c *xClient) getCachedClient(k string, servicePath, serviceMethod string, a
var needCallPlugin bool var needCallPlugin bool
defer func() { defer func() {
if needCallPlugin { if needCallPlugin {
c.Plugins.DoClientConnected((client.(*Client)).Conn) c.Plugins.DoClientConnected(client.GetConn())
} }
}() }()
c.mu.Lock() c.mu.Lock()
@@ -302,20 +319,52 @@ func (c *xClient) getCachedClient(k string, servicePath, serviceMethod string, a
} }
func (c *xClient) setCachedClient(client RPCClient, k, servicePath, serviceMethod string) { func (c *xClient) setCachedClient(client RPCClient, k, servicePath, serviceMethod string) {
network, _ := splitNetworkAndAddress(k)
if builder, ok := c.cacheClientBuilders[network]; ok {
builder.setCachedClient(client, k, servicePath, serviceMethod)
return
}
c.cachedClient[k] = client c.cachedClient[k] = client
} }
func (c *xClient) findCachedClient(k, servicePath, serviceMethod string) RPCClient { func (c *xClient) findCachedClient(k, servicePath, serviceMethod string) RPCClient {
network, _ := splitNetworkAndAddress(k)
if builder, ok := c.cacheClientBuilders[network]; ok {
return builder.findCachedClient(k, servicePath, serviceMethod)
}
return c.cachedClient[k] return c.cachedClient[k]
} }
func (c *xClient) deleteCachedClient(client RPCClient, k, servicePath, serviceMethod string) { func (c *xClient) deleteCachedClient(client RPCClient, k, servicePath, serviceMethod string) {
network, _ := splitNetworkAndAddress(k)
if builder, ok := c.cacheClientBuilders[network]; ok && client != nil {
builder.deleteCachedClient(client, k, servicePath, serviceMethod)
client.Close()
return
}
delete(c.cachedClient, k) delete(c.cachedClient, k)
if client != nil { if client != nil {
client.Close() client.Close()
} }
} }
func (c *xClient) removeClient(k, servicePath, serviceMethod string, client RPCClient) {
c.mu.Lock()
cl := c.findCachedClient(k, servicePath, serviceMethod)
if cl == client {
c.deleteCachedClient(client, k, servicePath, serviceMethod)
}
c.mu.Unlock()
if client != nil {
client.UnregisterServerMessageChan()
client.Close()
}
}
func (c *xClient) generateClient(k, servicePath, serviceMethod string) (client RPCClient, err error) { func (c *xClient) generateClient(k, servicePath, serviceMethod string) (client RPCClient, err error) {
client = &Client{ client = &Client{
option: c.option, option: c.option,
@@ -339,51 +388,45 @@ func (c *xClient) generateClient(k, servicePath, serviceMethod string) (client R
} }
func (c *xClient) getCachedClientWithoutLock(k, servicePath, serviceMethod string) (RPCClient, error) { func (c *xClient) getCachedClientWithoutLock(k, servicePath, serviceMethod string) (RPCClient, error) {
client := c.cachedClient[k] client := c.findCachedClient(k, servicePath, serviceMethod)
if client != nil { if client != nil {
if !client.IsClosing() && !client.IsShutdown() { if !client.IsClosing() && !client.IsShutdown() {
return client, nil return client, nil
} }
delete(c.cachedClient, k) c.deleteCachedClient(client, k, servicePath, serviceMethod)
client.Close()
} }
// double check var needCallPlugin bool
client = c.cachedClient[k] defer func() {
if client == nil || client.IsShutdown() { if needCallPlugin {
network, addr := splitNetworkAndAddress(k) c.Plugins.DoClientConnected(client.GetConn())
client = &Client{
option: c.option,
Plugins: c.Plugins,
} }
err := client.Connect(network, addr) }()
// double check
client = c.findCachedClient(k, servicePath, serviceMethod)
if client == nil || client.IsShutdown() {
generatedClient, err, _ := c.slGroup.Do(k, func() (interface{}, error) {
return c.generateClient(k, servicePath, serviceMethod)
})
c.slGroup.Forget(k)
if err != nil { if err != nil {
return nil, err return nil, err
} }
client = generatedClient.(RPCClient)
if c.Plugins != nil {
needCallPlugin = true
}
client.RegisterServerMessageChan(c.serverMessageChan) client.RegisterServerMessageChan(c.serverMessageChan)
c.cachedClient[k] = client c.setCachedClient(client, k, servicePath, serviceMethod)
} }
return client, nil return client, nil
} }
func (c *xClient) removeClient(k, servicePath, serviceMethod string, client RPCClient) {
c.mu.Lock()
cl := c.cachedClient[k]
if cl == client {
delete(c.cachedClient, k)
}
c.mu.Unlock()
if client != nil {
client.UnregisterServerMessageChan()
client.Close()
}
}
func splitNetworkAndAddress(server string) (string, string) { func splitNetworkAndAddress(server string) (string, string) {
ss := strings.SplitN(server, "@", 2) ss := strings.SplitN(server, "@", 2)
if len(ss) == 1 { if len(ss) == 1 {