trpc.group/trpc-go/trpc-go@v1.0.3/client/options.go (about)

     1  //
     2  //
     3  // Tencent is pleased to support the open source community by making tRPC available.
     4  //
     5  // Copyright (C) 2023 THL A29 Limited, a Tencent company.
     6  // All rights reserved.
     7  //
     8  // If you have downloaded a copy of the tRPC source code from Tencent,
     9  // please note that tRPC source code is licensed under the  Apache 2.0 License,
    10  // A copy of the Apache 2.0 License is included in this file.
    11  //
    12  //
    13  
    14  package client
    15  
    16  import (
    17  	"context"
    18  	"fmt"
    19  	"strings"
    20  	"sync"
    21  	"time"
    22  
    23  	"trpc.group/trpc-go/trpc-go/codec"
    24  	"trpc.group/trpc-go/trpc-go/filter"
    25  	"trpc.group/trpc-go/trpc-go/internal/attachment"
    26  	"trpc.group/trpc-go/trpc-go/naming/circuitbreaker"
    27  	"trpc.group/trpc-go/trpc-go/naming/discovery"
    28  	"trpc.group/trpc-go/trpc-go/naming/loadbalance"
    29  	"trpc.group/trpc-go/trpc-go/naming/registry"
    30  	"trpc.group/trpc-go/trpc-go/naming/selector"
    31  	"trpc.group/trpc-go/trpc-go/naming/servicerouter"
    32  	"trpc.group/trpc-go/trpc-go/pool/connpool"
    33  	"trpc.group/trpc-go/trpc-go/pool/multiplexed"
    34  	"trpc.group/trpc-go/trpc-go/transport"
    35  )
    36  
    37  // Options are clientside options.
    38  type Options struct {
    39  	ServiceName       string        // Backend service name.
    40  	CallerServiceName string        // Service name of caller itself.
    41  	CalleeMethod      string        // Callee method name, usually used for metrics.
    42  	Timeout           time.Duration // Timeout.
    43  
    44  	// Target is address of backend service: name://endpoint,
    45  	// also compatible with old addressing like ip://ip:port
    46  	Target   string
    47  	endpoint string // The same as service name if target is not set.
    48  
    49  	Network           string
    50  	Protocol          string
    51  	CallType          codec.RequestType           // Type of request, referring to transport.RequestType.
    52  	CallOptions       []transport.RoundTripOption // Options for client transport to call server.
    53  	Transport         transport.ClientTransport
    54  	EnableMultiplexed bool
    55  	StreamTransport   transport.ClientStreamTransport
    56  
    57  	SelectOptions             []selector.Option
    58  	Selector                  selector.Selector
    59  	DisableServiceRouter      bool
    60  	shouldErrReportToSelector func(error) bool
    61  
    62  	CurrentSerializationType int
    63  	CurrentCompressType      int
    64  	SerializationType        int
    65  	CompressType             int
    66  
    67  	Codec                 codec.Codec
    68  	MetaData              codec.MetaData
    69  	ClientStreamQueueSize int // Size of client stream's queue.
    70  
    71  	Filters                filter.ClientChain // Filter chain.
    72  	FilterNames            []string           // The name of filters.
    73  	DisableFilter          bool               // Whether to disable filter.
    74  	selectorFilterPosFixed bool               // Whether selector filter pos is fixed,if not, put it to the end.
    75  
    76  	ReqHead interface{} // Allow custom req head.
    77  	RspHead interface{} // Allow custom rsp head.
    78  	Node    *onceNode   // For getting node info.
    79  
    80  	MaxWindowSize uint32            // Max size of stream receiver's window.
    81  	SControl      SendControl       // Sender's flow control.
    82  	RControl      RecvControl       // Receiver's flow control.
    83  	StreamFilters StreamFilterChain // Stream filter chain.
    84  
    85  	fixTimeout func(error) error
    86  
    87  	attachment *attachment.Attachment
    88  }
    89  
    90  type onceNode struct {
    91  	*registry.Node
    92  	once sync.Once
    93  }
    94  
    95  func (n *onceNode) set(node *registry.Node, address string, cost time.Duration) {
    96  	if n == nil {
    97  		return
    98  	}
    99  	n.once.Do(func() {
   100  		*n.Node = *node
   101  		n.Node.Address = address
   102  		n.Node.CostTime = cost
   103  	})
   104  }
   105  
   106  // Option sets client options.
   107  type Option func(*Options)
   108  
   109  // WithNamespace returns an Option that sets namespace of backend service: Production/Development.
   110  func WithNamespace(namespace string) Option {
   111  	return func(o *Options) {
   112  		o.SelectOptions = append(o.SelectOptions, selector.WithNamespace(namespace))
   113  	}
   114  }
   115  
   116  // WithClientStreamQueueSize returns an Option that sets the size of client stream's buffer queue,
   117  // that is, max number of received messages to put into the channel.
   118  func WithClientStreamQueueSize(size int) Option {
   119  	return func(o *Options) {
   120  		o.ClientStreamQueueSize = size
   121  	}
   122  }
   123  
   124  // WithServiceName returns an Option that sets service name of backend service.
   125  func WithServiceName(s string) Option {
   126  	return func(o *Options) {
   127  		o.ServiceName = s
   128  		o.endpoint = s
   129  	}
   130  }
   131  
   132  // WithCallerServiceName returns an Option that sets service name of the caller service itself.
   133  func WithCallerServiceName(s string) Option {
   134  	return func(o *Options) {
   135  		o.CallerServiceName = s
   136  		o.SelectOptions = append(o.SelectOptions, selector.WithSourceServiceName(s))
   137  	}
   138  }
   139  
   140  // WithCallerNamespace returns an Option that sets namespace of the caller service itself.
   141  func WithCallerNamespace(s string) Option {
   142  	return func(o *Options) {
   143  		o.SelectOptions = append(o.SelectOptions, selector.WithSourceNamespace(s))
   144  	}
   145  }
   146  
   147  // WithDisableFilter returns an Option that sets whether to disable filter.
   148  // It's used when a plugin setup and need a client to send request
   149  // but filters' initialization has not been done.
   150  func WithDisableFilter() Option {
   151  	return func(o *Options) {
   152  		o.DisableFilter = true
   153  	}
   154  }
   155  
   156  // WithDisableServiceRouter returns an Option that disables service router.
   157  func WithDisableServiceRouter() Option {
   158  	return func(o *Options) {
   159  		o.DisableServiceRouter = true
   160  		o.SelectOptions = append(o.SelectOptions, selector.WithDisableServiceRouter())
   161  	}
   162  }
   163  
   164  // WithEnvKey returns an Option that sets env key.
   165  func WithEnvKey(key string) Option {
   166  	return func(o *Options) {
   167  		o.SelectOptions = append(o.SelectOptions, selector.WithEnvKey(key))
   168  	}
   169  }
   170  
   171  // WithCallerEnvName returns an Option that sets env name of the caller service itself.
   172  func WithCallerEnvName(envName string) Option {
   173  	return func(o *Options) {
   174  		o.SelectOptions = append(o.SelectOptions, selector.WithSourceEnvName(envName))
   175  	}
   176  }
   177  
   178  // WithCallerSetName returns an Option that sets "Set" of the caller service itself.
   179  func WithCallerSetName(setName string) Option {
   180  	return func(o *Options) {
   181  		o.SelectOptions = append(o.SelectOptions, selector.WithSourceSetName(setName))
   182  	}
   183  }
   184  
   185  // WithCalleeSetName returns an Option that sets "Set" of the callee service.
   186  func WithCalleeSetName(setName string) Option {
   187  	return func(o *Options) {
   188  		o.SelectOptions = append(o.SelectOptions, selector.WithDestinationSetName(setName))
   189  	}
   190  }
   191  
   192  // WithCalleeEnvName returns an Option that sets env name of the callee service.
   193  func WithCalleeEnvName(envName string) Option {
   194  	return func(o *Options) {
   195  		o.SelectOptions = append(o.SelectOptions, selector.WithDestinationEnvName(envName))
   196  	}
   197  }
   198  
   199  // WithCalleeMethod returns an Option that sets callee method name.
   200  func WithCalleeMethod(method string) Option {
   201  	return func(o *Options) {
   202  		o.CalleeMethod = method
   203  	}
   204  }
   205  
   206  // WithCallerMetadata returns an Option that sets metadata of caller.
   207  // It should not be used for env/set as specific methods are provided for env/set.
   208  func WithCallerMetadata(key string, val string) Option {
   209  	return func(o *Options) {
   210  		o.SelectOptions = append(o.SelectOptions, selector.WithSourceMetadata(key, val))
   211  	}
   212  }
   213  
   214  // WithCalleeMetadata returns an Option that sets metadata of callee.
   215  // It should not be used for env/set as specific methods are provided for env/set.
   216  func WithCalleeMetadata(key string, val string) Option {
   217  	return func(o *Options) {
   218  		o.SelectOptions = append(o.SelectOptions, selector.WithDestinationMetadata(key, val))
   219  	}
   220  }
   221  
   222  // WithBalancerName returns an Option that sets load balancer by name.
   223  func WithBalancerName(balancerName string) Option {
   224  	balancer := loadbalance.Get(balancerName)
   225  	return func(o *Options) {
   226  		o.SelectOptions = append(o.SelectOptions,
   227  			selector.WithLoadBalancer(balancer),
   228  			selector.WithLoadBalanceType(balancerName),
   229  		)
   230  	}
   231  }
   232  
   233  // WithDiscoveryName returns an Option that sets service discovery by name.
   234  func WithDiscoveryName(name string) Option {
   235  	d := discovery.Get(name)
   236  	return func(o *Options) {
   237  		o.SelectOptions = append(o.SelectOptions, selector.WithDiscovery(d))
   238  	}
   239  }
   240  
   241  // WithServiceRouterName returns an Option that sets service router by name.
   242  func WithServiceRouterName(name string) Option {
   243  	r := servicerouter.Get(name)
   244  	return func(o *Options) {
   245  		o.SelectOptions = append(o.SelectOptions, selector.WithServiceRouter(r))
   246  	}
   247  }
   248  
   249  // WithCircuitBreakerName returns an Option that sets circuit breaker by name.
   250  func WithCircuitBreakerName(name string) Option {
   251  	cb := circuitbreaker.Get(name)
   252  	return func(o *Options) {
   253  		o.SelectOptions = append(o.SelectOptions, selector.WithCircuitBreaker(cb))
   254  	}
   255  }
   256  
   257  // WithKey returns an Option that sets the hash key of stateful routing.
   258  func WithKey(key string) Option {
   259  	return func(o *Options) {
   260  		o.SelectOptions = append(o.SelectOptions, selector.WithKey(key))
   261  	}
   262  }
   263  
   264  // WithReplicas returns an Option that sets node replicas of stateful routing.
   265  func WithReplicas(r int) Option {
   266  	return func(o *Options) {
   267  		o.SelectOptions = append(o.SelectOptions, selector.WithReplicas(r))
   268  	}
   269  }
   270  
   271  // WithTarget returns an Option that sets target address using URI scheme://endpoint.
   272  // e.g. ip://ip_addr:port
   273  func WithTarget(t string) Option {
   274  	return func(o *Options) {
   275  		o.Target = t
   276  		o.endpoint = "" // should parse endpoint again after calling WithTarget
   277  	}
   278  }
   279  
   280  // WithNetwork returns an Option that sets dial network: tcp/udp, tcp by default.
   281  func WithNetwork(s string) Option {
   282  	return func(o *Options) {
   283  		if s == "" {
   284  			return
   285  		}
   286  		o.Network = s
   287  		o.CallOptions = append(o.CallOptions, transport.WithDialNetwork(s))
   288  	}
   289  }
   290  
   291  // WithPassword returns an Option that sets dial password.
   292  func WithPassword(s string) Option {
   293  	return func(o *Options) {
   294  		if s == "" {
   295  			return
   296  		}
   297  		o.CallOptions = append(o.CallOptions, transport.WithDialPassword(s))
   298  	}
   299  }
   300  
   301  // WithPool returns an Option that sets dial pool.
   302  func WithPool(pool connpool.Pool) Option {
   303  	return func(o *Options) {
   304  		o.CallOptions = append(o.CallOptions, transport.WithDialPool(pool))
   305  	}
   306  }
   307  
   308  // WithMultiplexedPool returns an Option that sets multiplexed pool.
   309  // Calling this method enables multiplexing.
   310  func WithMultiplexedPool(p multiplexed.Pool) Option {
   311  	return func(o *Options) {
   312  		o.EnableMultiplexed = true
   313  		o.CallOptions = append(o.CallOptions, transport.WithMultiplexedPool(p))
   314  	}
   315  }
   316  
   317  // WithTimeout returns an Option that sets timeout.
   318  func WithTimeout(t time.Duration) Option {
   319  	return func(o *Options) {
   320  		o.Timeout = t
   321  	}
   322  }
   323  
   324  // WithCurrentSerializationType returns an Option that sets serialization type of caller itself.
   325  // WithSerializationType should be used to set serialization type of backend service.
   326  func WithCurrentSerializationType(t int) Option {
   327  	return func(o *Options) {
   328  		o.CurrentSerializationType = t
   329  	}
   330  }
   331  
   332  // WithSerializationType returns an Option that sets serialization type of backend service.
   333  // Generally, only WithSerializationType will be used as WithCurrentSerializationType is used
   334  // for reverse proxy.
   335  func WithSerializationType(t int) Option {
   336  	return func(o *Options) {
   337  		o.SerializationType = t
   338  	}
   339  }
   340  
   341  // WithCurrentCompressType returns an Option that sets compression type of caller itself.
   342  // WithCompressType should be used to set compression type of backend service.
   343  func WithCurrentCompressType(t int) Option {
   344  	return func(o *Options) {
   345  		o.CurrentCompressType = t
   346  	}
   347  }
   348  
   349  // WithCompressType returns an Option that sets compression type of backend service.
   350  // Generally, only WithCompressType will be used as WithCurrentCompressType is used
   351  // for reverse proxy.
   352  func WithCompressType(t int) Option {
   353  	return func(o *Options) {
   354  		o.CompressType = t
   355  	}
   356  }
   357  
   358  // WithTransport returns an Option that sets client transport plugin.
   359  func WithTransport(t transport.ClientTransport) Option {
   360  	return func(o *Options) {
   361  		if t != nil {
   362  			o.Transport = t
   363  		}
   364  	}
   365  }
   366  
   367  // WithProtocol returns an Option that sets protocol of backend service like trpc.
   368  func WithProtocol(s string) Option {
   369  	return func(o *Options) {
   370  		if s == "" {
   371  			return
   372  		}
   373  		o.Protocol = s
   374  		o.Codec = codec.GetClient(s)
   375  		if b := transport.GetFramerBuilder(s); b != nil {
   376  			o.CallOptions = append(o.CallOptions,
   377  				transport.WithClientFramerBuilder(b),
   378  				transport.WithProtocol(s),
   379  			)
   380  		}
   381  		if t := transport.GetClientTransport(s); t != nil {
   382  			o.Transport = t
   383  		}
   384  	}
   385  }
   386  
   387  // WithConnectionMode returns an Option that sets whether connection mode is connected.
   388  // If connection mode is connected, udp will isolate packets from non-same path.
   389  func WithConnectionMode(connMode transport.ConnectionMode) Option {
   390  	return func(o *Options) {
   391  		o.CallOptions = append(o.CallOptions, transport.WithConnectionMode(connMode))
   392  	}
   393  }
   394  
   395  // WithSendOnly returns an Option that sets CallType SendOnly.
   396  // Generally it's used for udp async sending.
   397  func WithSendOnly() Option {
   398  	return func(o *Options) {
   399  		o.CallType = codec.SendOnly
   400  		o.CallOptions = append(o.CallOptions, transport.WithReqType(codec.SendOnly))
   401  	}
   402  }
   403  
   404  // WithFilter returns an Option that appends client filter to client filter chain.
   405  // ClientFilter processing could be before encoding or after decoding.
   406  // Selector filter is built-in filter and is at the end of the client filter chain by default.
   407  // It is also supported to set pos of selector filter through the yaml config file.
   408  func WithFilter(f filter.ClientFilter) Option {
   409  	return func(o *Options) {
   410  		o.Filters = append(o.Filters, f)
   411  		o.FilterNames = append(o.FilterNames, "client.WithFilter")
   412  	}
   413  }
   414  
   415  // WithNamedFilter returns an Option that adds named filter
   416  func WithNamedFilter(name string, f filter.ClientFilter) Option {
   417  	return func(o *Options) {
   418  		o.FilterNames = append(o.FilterNames, name)
   419  		o.Filters = append(o.Filters, f)
   420  	}
   421  }
   422  
   423  // WithFilters returns an Option that appends multiple client filters to the client filter chain.
   424  func WithFilters(fs []filter.ClientFilter) Option {
   425  	return func(o *Options) {
   426  		for _, f := range fs {
   427  			WithFilter(f)(o)
   428  		}
   429  	}
   430  }
   431  
   432  // WithStreamFilters returns an Option that appends multiple client stream filters to
   433  // the client stream filter chain.
   434  // StreamFilter processing could be before or after stream's establishing, before or after sending data,
   435  // before or after receiving data.
   436  func WithStreamFilters(sfs ...StreamFilter) Option {
   437  	return func(o *Options) {
   438  		o.StreamFilters = append(o.StreamFilters, sfs...)
   439  	}
   440  }
   441  
   442  // WithStreamFilter returns an Option that appends a client stream filter to
   443  // the client stream filter chain.
   444  func WithStreamFilter(sf StreamFilter) Option {
   445  	return func(o *Options) {
   446  		o.StreamFilters = append(o.StreamFilters, sf)
   447  	}
   448  }
   449  
   450  // WithReqHead returns an Option that sets req head.
   451  // It's default to clone server req head from source request.
   452  func WithReqHead(h interface{}) Option {
   453  	return func(o *Options) {
   454  		o.ReqHead = h
   455  	}
   456  }
   457  
   458  // WithRspHead returns an Option that sets rsp head.
   459  // Usually used for gateway service.
   460  func WithRspHead(h interface{}) Option {
   461  	return func(o *Options) {
   462  		o.RspHead = h
   463  	}
   464  }
   465  
   466  // WithAttachment returns an Option that sets attachment.
   467  func WithAttachment(attachment *Attachment) Option {
   468  	return func(o *Options) {
   469  		o.attachment = &attachment.attachment
   470  	}
   471  }
   472  
   473  // WithMetaData returns an Option that sets transparent transmitted metadata.
   474  func WithMetaData(key string, val []byte) Option {
   475  	return func(o *Options) {
   476  		if o.MetaData == nil {
   477  			o.MetaData = codec.MetaData{}
   478  		}
   479  		o.MetaData[key] = val
   480  	}
   481  }
   482  
   483  // WithSelectorNode returns an Option that records the selected node.
   484  // It's usually used for debugging.
   485  func WithSelectorNode(n *registry.Node) Option {
   486  	return func(o *Options) {
   487  		o.Node = &onceNode{Node: n}
   488  	}
   489  }
   490  
   491  // WithTLS returns an Option that sets client tls files.
   492  // If caFile="none", no server cert validation.
   493  // If caFile="root", local ca cert will be used to validate server.
   494  // certFile is only used for mTLS or should be empty.
   495  // serverName is used to validate the name of server. hostname by default for https.
   496  func WithTLS(certFile, keyFile, caFile, serverName string) Option {
   497  	return func(o *Options) {
   498  		if caFile == "" {
   499  			return
   500  		}
   501  		o.CallOptions = append(o.CallOptions, transport.WithDialTLS(certFile, keyFile, caFile, serverName))
   502  	}
   503  }
   504  
   505  // WithDisableConnectionPool returns an Option that disables connection pool.
   506  func WithDisableConnectionPool() Option {
   507  	return func(o *Options) {
   508  		o.CallOptions = append(o.CallOptions, transport.WithDisableConnectionPool())
   509  	}
   510  }
   511  
   512  // WithMultiplexed returns an Option that enables multiplexed.
   513  // WithMultiplexedPool should be used for custom Multiplexed.
   514  func WithMultiplexed(enable bool) Option {
   515  	return func(o *Options) {
   516  		o.EnableMultiplexed = enable
   517  	}
   518  }
   519  
   520  // WithLocalAddr returns an Option that sets local addr. Randomly picking for multiple NICs.
   521  //
   522  // for non-persistent conn, ip & port can be specified:
   523  // client.WithLocalAddr("127.0.0.1:8080")
   524  // for conn pool or multiplexed, only ip can be specified:
   525  // client.WithLocalAddr("127.0.0.1:")
   526  func WithLocalAddr(addr string) Option {
   527  	return func(o *Options) {
   528  		o.CallOptions = append(o.CallOptions, transport.WithLocalAddr(addr))
   529  	}
   530  }
   531  
   532  // WithDialTimeout returns an Option that sets timeout.
   533  func WithDialTimeout(dur time.Duration) Option {
   534  	return func(o *Options) {
   535  		o.CallOptions = append(o.CallOptions, transport.WithDialTimeout(dur))
   536  	}
   537  }
   538  
   539  // WithStreamTransport returns an Option that sets client stream transport.
   540  func WithStreamTransport(st transport.ClientStreamTransport) Option {
   541  	return func(o *Options) {
   542  		o.StreamTransport = st
   543  	}
   544  }
   545  
   546  // WithMaxWindowSize returns an Option that sets max size of receive window.
   547  // Client as the receiver will notify the sender of the window.
   548  func WithMaxWindowSize(s uint32) Option {
   549  	return func(o *Options) {
   550  		o.MaxWindowSize = s
   551  	}
   552  }
   553  
   554  // WithSendControl returns an Option that sets send control.
   555  func WithSendControl(sc SendControl) Option {
   556  	return func(o *Options) {
   557  		o.SControl = sc
   558  	}
   559  }
   560  
   561  // WithRecvControl returns an Option that sets recv control.
   562  func WithRecvControl(rc RecvControl) Option {
   563  	return func(o *Options) {
   564  		o.RControl = rc
   565  	}
   566  }
   567  
   568  // WithShouldErrReportToSelector returns an Option that sets should err report to selector
   569  func WithShouldErrReportToSelector(f func(error) bool) Option {
   570  	return func(o *Options) {
   571  		o.shouldErrReportToSelector = f
   572  	}
   573  }
   574  
   575  type optionsKey struct{}
   576  
   577  func contextWithOptions(ctx context.Context, opts *Options) context.Context {
   578  	return context.WithValue(ctx, optionsKey{}, opts)
   579  }
   580  
   581  // OptionsFromContext returns options from context.
   582  func OptionsFromContext(ctx context.Context) *Options {
   583  	opts, ok := ctx.Value(optionsKey{}).(*Options)
   584  	if ok {
   585  		return opts
   586  	}
   587  	return NewOptions()
   588  }
   589  
   590  type optionsImmutability struct{}
   591  
   592  // WithOptionsImmutable marks options of outermost layer immutable.
   593  // Cloning options is needed for modifying options in lower layers.
   594  //
   595  // It should only be used by filters that call the next filter concurrently.
   596  func WithOptionsImmutable(ctx context.Context) context.Context {
   597  	return context.WithValue(ctx, optionsImmutability{}, optionsImmutability{})
   598  }
   599  
   600  // IsOptionsImmutable checks the ctx if options are immutable.
   601  func IsOptionsImmutable(ctx context.Context) bool {
   602  	_, ok := ctx.Value(optionsImmutability{}).(optionsImmutability)
   603  	return ok
   604  }
   605  
   606  // ---------------------------- Options util api ---------------------//
   607  
   608  // NewOptions creates a new Options with fields set to default value.
   609  func NewOptions() *Options {
   610  	const (
   611  		invalidSerializationType = -1
   612  		invalidCompressType      = -1
   613  	)
   614  	return &Options{
   615  		Transport:         transport.DefaultClientTransport,
   616  		Selector:          selector.DefaultSelector,
   617  		SerializationType: invalidSerializationType, // the initial value is -1
   618  		// CurrentSerializationType is the serialization type of caller itself.
   619  		// SerializationType is the serialization type of backend service.
   620  		// For proxy, CurrentSerializationType should be noop but SerializationType should not.
   621  		CurrentSerializationType: invalidSerializationType,
   622  		CurrentCompressType:      invalidCompressType,
   623  
   624  		fixTimeout:                func(err error) error { return err },
   625  		shouldErrReportToSelector: func(err error) bool { return false },
   626  	}
   627  }
   628  
   629  // clone clones new options to ensure thread safety.
   630  // Note that this is a shallow copy.
   631  func (opts *Options) clone() *Options {
   632  	if opts == nil {
   633  		return NewOptions()
   634  	}
   635  	o := *opts
   636  	return &o
   637  }
   638  
   639  // rebuildSliceCapacity rebuilds slice capacity.
   640  // Since new options will be cloned for each RPC,
   641  // to prevent that appending slice may affect the original data of the slice,
   642  // cap of slice should be set to equal len of slice so that a new slice will be
   643  // created for each slice appending.
   644  func (opts *Options) rebuildSliceCapacity() {
   645  	if len(opts.CallOptions) != cap(opts.CallOptions) {
   646  		o := make([]transport.RoundTripOption, len(opts.CallOptions), len(opts.CallOptions))
   647  		copy(o, opts.CallOptions)
   648  		opts.CallOptions = o
   649  	}
   650  	if len(opts.SelectOptions) != cap(opts.SelectOptions) {
   651  		o := make([]selector.Option, len(opts.SelectOptions), len(opts.SelectOptions))
   652  		copy(o, opts.SelectOptions)
   653  		opts.SelectOptions = o
   654  	}
   655  	if len(opts.Filters) != cap(opts.Filters) {
   656  		o := make(filter.ClientChain, len(opts.Filters), len(opts.Filters))
   657  		copy(o, opts.Filters)
   658  		opts.Filters = o
   659  	}
   660  	if len(opts.FilterNames) != cap(opts.FilterNames) {
   661  		o := make([]string, len(opts.FilterNames), len(opts.FilterNames))
   662  		copy(o, opts.FilterNames)
   663  		opts.FilterNames = o
   664  	}
   665  }
   666  
   667  func (opts *Options) parseTarget() error {
   668  	if opts.Target == "" {
   669  		return nil
   670  	}
   671  
   672  	// Target should be like: selector://endpoint.
   673  	substr := "://"
   674  	index := strings.Index(opts.Target, substr)
   675  	if index == -1 {
   676  		return fmt.Errorf("client: target %s scheme invalid, format must be selector://endpoint", opts.Target)
   677  	}
   678  	opts.Selector = selector.Get(opts.Target[:index])
   679  	if opts.Selector == nil {
   680  		return fmt.Errorf("client: selector %s not exist", opts.Target[:index])
   681  	}
   682  	opts.endpoint = opts.Target[index+len(substr):]
   683  	if opts.endpoint == "" {
   684  		return fmt.Errorf("client: target %s endpoint empty, format must be selector://endpoint", opts.Target)
   685  	}
   686  
   687  	return nil
   688  }
   689  
   690  // LoadNodeConfig loads node config from config center.
   691  func (opts *Options) LoadNodeConfig(node *registry.Node) {
   692  	opts.CallOptions = append(opts.CallOptions, transport.WithDialAddress(node.Address))
   693  	// Naming service has higher priority.
   694  	// Use network from local config file only if it's not set by the naming service.
   695  	if node.Network != "" {
   696  		opts.Network = node.Network
   697  		opts.CallOptions = append(opts.CallOptions, transport.WithDialNetwork(node.Network))
   698  	}
   699  	if node.Protocol != "" {
   700  		WithProtocol(node.Protocol)(opts)
   701  	}
   702  }