github.com/cloudwego/kitex@v0.9.0/pkg/rpcinfo/remoteinfo/remoteInfo.go (about)

     1  /*
     2   * Copyright 2021 CloudWeGo Authors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package remoteinfo
    18  
    19  import (
    20  	"errors"
    21  	"net"
    22  	"sync"
    23  
    24  	"github.com/cloudwego/kitex/internal"
    25  	"github.com/cloudwego/kitex/pkg/discovery"
    26  	"github.com/cloudwego/kitex/pkg/kerrors"
    27  	"github.com/cloudwego/kitex/pkg/rpcinfo"
    28  )
    29  
    30  // RemoteInfo implements a rpcinfo.EndpointInfo with mutable address and connection.
    31  // It is typically used to represent server info on client side or client info on server side.
    32  type RemoteInfo interface {
    33  	rpcinfo.EndpointInfo
    34  	SetServiceName(name string)
    35  	SetTag(key, value string) error
    36  	ForceSetTag(key, value string)
    37  
    38  	// SetTagLock freezes a key of the tags and refuses further modification on its value.
    39  	SetTagLock(key string)
    40  	GetInstance() discovery.Instance
    41  	SetInstance(ins discovery.Instance)
    42  
    43  	// SetRemoteAddr tries to set the network address of the discovery.Instance hold by RemoteInfo.
    44  	// The result indicates whether the modification is successful.
    45  	SetRemoteAddr(addr net.Addr) (ok bool)
    46  	ImmutableView() rpcinfo.EndpointInfo
    47  }
    48  
    49  // RefreshableInstance declares an interface which can return an instance containing the new address.
    50  type RefreshableInstance interface {
    51  	RefreshInstanceWithAddr(addr net.Addr) (newInstance discovery.Instance)
    52  }
    53  
    54  var (
    55  	_              RemoteInfo = &remoteInfo{}
    56  	remoteInfoPool sync.Pool
    57  )
    58  
    59  type remoteInfo struct {
    60  	sync.RWMutex
    61  	serviceName string
    62  	method      string
    63  	tags        map[string]string
    64  
    65  	instance discovery.Instance
    66  	tagLocks map[string]struct{}
    67  }
    68  
    69  func init() {
    70  	remoteInfoPool.New = newRemoteInfo
    71  }
    72  
    73  func newRemoteInfo() interface{} {
    74  	return &remoteInfo{
    75  		tags:     make(map[string]string),
    76  		tagLocks: make(map[string]struct{}),
    77  	}
    78  }
    79  
    80  // GetInstance implements the RemoteInfo interface.
    81  func (ri *remoteInfo) GetInstance() (ins discovery.Instance) {
    82  	ri.RLock()
    83  	ins = ri.instance
    84  	ri.RUnlock()
    85  	return
    86  }
    87  
    88  // SetInstance implements the RemoteInfo interface.
    89  func (ri *remoteInfo) SetInstance(ins discovery.Instance) {
    90  	ri.Lock()
    91  	ri.instance = ins
    92  	ri.Unlock()
    93  }
    94  
    95  // ServiceName implements the rpcinfo.EndpointInfo interface.
    96  func (ri *remoteInfo) ServiceName() string {
    97  	return ri.serviceName
    98  }
    99  
   100  // SetServiceName implements the RemoteInfo interface.
   101  func (ri *remoteInfo) SetServiceName(name string) {
   102  	ri.serviceName = name
   103  }
   104  
   105  // Method implements the rpcinfo.EndpointInfo interface.
   106  func (ri *remoteInfo) Method() string {
   107  	return ri.method
   108  }
   109  
   110  // Tag implements the rpcinfo.EndpointInfo interface.
   111  func (ri *remoteInfo) Tag(key string) (value string, exist bool) {
   112  	ri.RLock()
   113  	defer ri.RUnlock()
   114  
   115  	if ri.instance != nil {
   116  		if value, exist = ri.instance.Tag(key); exist {
   117  			return
   118  		}
   119  	}
   120  	value, exist = ri.tags[key]
   121  	return
   122  }
   123  
   124  // DefaultTag implements the rpcinfo.EndpointInfo interface.
   125  func (ri *remoteInfo) DefaultTag(key, def string) string {
   126  	if value, exist := ri.Tag(key); exist && value != "" {
   127  		return value
   128  	}
   129  	return def
   130  }
   131  
   132  // SetRemoteAddr implements the RemoteInfo interface.
   133  func (ri *remoteInfo) SetRemoteAddr(addr net.Addr) bool {
   134  	ri.Lock()
   135  	defer ri.Unlock()
   136  	if ins, ok := ri.instance.(RefreshableInstance); ok {
   137  		ri.instance = ins.RefreshInstanceWithAddr(addr)
   138  		return true
   139  	}
   140  	return false
   141  }
   142  
   143  // Address implements the rpcinfo.EndpointInfo interface.
   144  func (ri *remoteInfo) Address() net.Addr {
   145  	ri.RLock()
   146  	defer ri.RUnlock()
   147  	if ri.instance != nil {
   148  		return ri.instance.Address()
   149  	}
   150  	return nil
   151  }
   152  
   153  // SetTagLocks locks tag.
   154  func (ri *remoteInfo) SetTagLock(key string) {
   155  	ri.Lock()
   156  	ri.tagLocks[key] = struct{}{}
   157  	ri.Unlock()
   158  }
   159  
   160  // SetTag implements rpcinfo.MutableEndpointInfo.
   161  func (ri *remoteInfo) SetTag(key, value string) error {
   162  	ri.Lock()
   163  	defer ri.Unlock()
   164  	if _, exist := ri.tagLocks[key]; exist {
   165  		return kerrors.ErrNotSupported
   166  	}
   167  	ri.tags[key] = value
   168  	return nil
   169  }
   170  
   171  // ForceSetTag is used to set Tag without tag lock.
   172  func (ri *remoteInfo) ForceSetTag(key, value string) {
   173  	ri.Lock()
   174  	defer ri.Unlock()
   175  	ri.tags[key] = value
   176  }
   177  
   178  // ImmutableView implements rpcinfo.MutableEndpointInfo.
   179  func (ri *remoteInfo) ImmutableView() rpcinfo.EndpointInfo {
   180  	return ri
   181  }
   182  
   183  func (ri *remoteInfo) zero() {
   184  	ri.Lock()
   185  	defer ri.Unlock()
   186  	ri.serviceName = ""
   187  	ri.method = ""
   188  	ri.instance = nil
   189  	for k := range ri.tags {
   190  		delete(ri.tags, k)
   191  	}
   192  	for k := range ri.tagLocks {
   193  		delete(ri.tagLocks, k)
   194  	}
   195  }
   196  
   197  // Recycle is used to recycle the remoteInfo.
   198  func (ri *remoteInfo) Recycle() {
   199  	if r, ok := ri.instance.(internal.Reusable); ok {
   200  		r.Recycle()
   201  	}
   202  	ri.zero()
   203  	remoteInfoPool.Put(ri)
   204  }
   205  
   206  // NewRemoteInfo creates a remoteInfo wrapping the given endpointInfo.
   207  // The return value of the created RemoteInfo's Method method will be the `method` argument
   208  // instead of the Method field in `basicInfo`.
   209  // If the given basicInfo is nil, this function will panic.
   210  func NewRemoteInfo(basicInfo *rpcinfo.EndpointBasicInfo, method string) RemoteInfo {
   211  	if basicInfo == nil {
   212  		panic(errors.New("nil basicInfo"))
   213  	}
   214  	ri := remoteInfoPool.Get().(*remoteInfo)
   215  	ri.serviceName = basicInfo.ServiceName
   216  	ri.method = method
   217  	for k, v := range basicInfo.Tags {
   218  		ri.tags[k] = v
   219  	}
   220  	return ri
   221  }
   222  
   223  // AsRemoteInfo converts an rpcinfo.EndpointInfo into a RemoteInfo. Returns nil if impossible.
   224  func AsRemoteInfo(r rpcinfo.EndpointInfo) RemoteInfo {
   225  	if v, ok := r.(RemoteInfo); ok {
   226  		return v
   227  	}
   228  	return nil
   229  }