github.com/cloudwego/kitex@v0.9.0/server/option_advanced.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 server defines the Options of server
    18  package server
    19  
    20  // Notice!! This file defines the advanced Options of client, normal user should not use it.
    21  // It is used for customized extension.
    22  
    23  import (
    24  	"context"
    25  	"fmt"
    26  	"net"
    27  	"reflect"
    28  
    29  	internal_server "github.com/cloudwego/kitex/internal/server"
    30  	"github.com/cloudwego/kitex/pkg/acl"
    31  	"github.com/cloudwego/kitex/pkg/diagnosis"
    32  	"github.com/cloudwego/kitex/pkg/generic"
    33  	"github.com/cloudwego/kitex/pkg/klog"
    34  	"github.com/cloudwego/kitex/pkg/limiter"
    35  	"github.com/cloudwego/kitex/pkg/profiler"
    36  	"github.com/cloudwego/kitex/pkg/proxy"
    37  	"github.com/cloudwego/kitex/pkg/remote"
    38  	"github.com/cloudwego/kitex/pkg/rpcinfo"
    39  	"github.com/cloudwego/kitex/pkg/utils"
    40  )
    41  
    42  // WithServerBasicInfo provides initial information for client endpoint in RPCInfo.
    43  func WithServerBasicInfo(ebi *rpcinfo.EndpointBasicInfo) Option {
    44  	return Option{F: func(o *internal_server.Options, di *utils.Slice) {
    45  		di.Push(fmt.Sprintf("WithServerBasicInfo(%+v)", ebi))
    46  
    47  		if ebi != nil {
    48  			o.Svr = ebi
    49  		}
    50  	}}
    51  }
    52  
    53  // WithDiagnosisService sets the diagnosis service for gathering debug information.
    54  func WithDiagnosisService(ds diagnosis.Service) Option {
    55  	return Option{F: func(o *internal_server.Options, di *utils.Slice) {
    56  		o.Once.OnceOrPanic()
    57  		di.Push(fmt.Sprintf("WithDiagnosisService(%+v)", ds))
    58  
    59  		o.DebugService = ds
    60  	}}
    61  }
    62  
    63  // WithACLRules sets the ACL rules.
    64  func WithACLRules(rules ...acl.RejectFunc) Option {
    65  	return Option{F: func(o *internal_server.Options, di *utils.Slice) {
    66  		var names []string
    67  		for _, r := range rules {
    68  			names = append(names, utils.GetFuncName(r))
    69  		}
    70  		di.Push(fmt.Sprintf("WithACLRules(%+v)", names))
    71  
    72  		o.ACLRules = append(o.ACLRules, rules...)
    73  	}}
    74  }
    75  
    76  // WithMetaHandler adds a MetaHandler.
    77  func WithMetaHandler(h remote.MetaHandler) Option {
    78  	return Option{F: func(o *internal_server.Options, di *utils.Slice) {
    79  		di.Push(fmt.Sprintf("WithMetaHandler(%T)", h))
    80  
    81  		o.MetaHandlers = append(o.MetaHandlers, h)
    82  	}}
    83  }
    84  
    85  // WithProxy sets the backward Proxy for server.
    86  func WithProxy(p proxy.ReverseProxy) Option {
    87  	return Option{F: func(o *internal_server.Options, di *utils.Slice) {
    88  		o.Once.OnceOrPanic()
    89  		di.Push(fmt.Sprintf("WithProxy(%T)", p))
    90  
    91  		if o.Proxy != nil {
    92  			panic(fmt.Errorf("reassignment of Proxy is not allowed: %T -> %T", o.Proxy, p))
    93  		}
    94  		o.Proxy = p
    95  	}}
    96  }
    97  
    98  // WithTransHandlerFactory sets the TransHandlerFactory for server.
    99  func WithTransHandlerFactory(f remote.ServerTransHandlerFactory) Option {
   100  	return Option{F: func(o *internal_server.Options, di *utils.Slice) {
   101  		o.Once.OnceOrPanic()
   102  		di.Push(fmt.Sprintf("WithTransHandlerFactory(%T)", f))
   103  
   104  		o.RemoteOpt.SvrHandlerFactory = f
   105  	}}
   106  }
   107  
   108  // WithTransServerFactory sets the TransServerFactory for server.
   109  func WithTransServerFactory(f remote.TransServerFactory) Option {
   110  	return Option{F: func(o *internal_server.Options, di *utils.Slice) {
   111  		o.Once.OnceOrPanic()
   112  		di.Push(fmt.Sprintf("WithTransServerFactory(%T)", f))
   113  
   114  		o.RemoteOpt.TransServerFactory = f
   115  	}}
   116  }
   117  
   118  // WithLimitReporter do report when server limit happen
   119  func WithLimitReporter(r limiter.LimitReporter) Option {
   120  	return Option{F: func(o *internal_server.Options, di *utils.Slice) {
   121  		o.Once.OnceOrPanic()
   122  		di.Push(fmt.Sprintf("WithLimitReporter(%T)", r))
   123  
   124  		o.Limit.LimitReporter = r
   125  	}}
   126  }
   127  
   128  // WithGeneric set Generic type for generic call
   129  func WithGeneric(g generic.Generic) Option {
   130  	return Option{F: func(o *internal_server.Options, di *utils.Slice) {
   131  		o.Once.OnceOrPanic()
   132  		di.Push(fmt.Sprintf("WithGeneric(%T)", g))
   133  
   134  		if g == nil {
   135  			panic("invalid Generic: nil")
   136  		}
   137  		o.RemoteOpt.PayloadCodec = g.PayloadCodec()
   138  	}}
   139  }
   140  
   141  // WithErrorHandler sets the error handler.
   142  func WithErrorHandler(f func(context.Context, error) error) Option {
   143  	return Option{F: func(o *internal_server.Options, di *utils.Slice) {
   144  		o.Once.OnceOrPanic()
   145  		di.Push(fmt.Sprintf("WithErrorHandler(%+v)", utils.GetFuncName(f)))
   146  
   147  		o.ErrHandle = f
   148  	}}
   149  }
   150  
   151  // WithBoundHandler adds remote.BoundHandler for server.
   152  func WithBoundHandler(h remote.BoundHandler) Option {
   153  	return Option{F: func(o *internal_server.Options, di *utils.Slice) {
   154  		di.Push(fmt.Sprintf("AddBoundHandler(%T)", h))
   155  
   156  		exist := false
   157  		switch handler := h.(type) {
   158  		case remote.InboundHandler:
   159  			for _, inboundHandler := range o.RemoteOpt.Inbounds {
   160  				if reflect.DeepEqual(inboundHandler, handler) {
   161  					exist = true
   162  					break
   163  				}
   164  			}
   165  		case remote.OutboundHandler:
   166  			for _, outboundHandler := range o.RemoteOpt.Outbounds {
   167  				if reflect.DeepEqual(outboundHandler, handler) {
   168  					exist = true
   169  					break
   170  				}
   171  			}
   172  		}
   173  		// prevent duplication
   174  		if !exist {
   175  			doAddBoundHandler(h, o.RemoteOpt)
   176  		} else {
   177  			klog.Warnf("KITEX: BoundHandler already exists, BoundHandler=%v", h)
   178  		}
   179  	}}
   180  }
   181  
   182  // WithExitSignal adds ExitSignal for server.
   183  func WithExitSignal(f func() <-chan error) Option {
   184  	return Option{F: func(o *internal_server.Options, di *utils.Slice) {
   185  		di.Push(fmt.Sprintf("AddExitSignal(%+v)", utils.GetFuncName(f)))
   186  		o.ExitSignal = f
   187  	}}
   188  }
   189  
   190  // WithListener sets the listener for server, the priority is higher than WithServiceAddr
   191  func WithListener(ln net.Listener) Option {
   192  	return Option{F: func(o *internal_server.Options, di *utils.Slice) {
   193  		di.Push(fmt.Sprintf("WithListener(%+v)", ln))
   194  
   195  		o.RemoteOpt.Listener = ln
   196  	}}
   197  }
   198  
   199  // WithReusePort sets SO_REUSEPORT on listener, it is only used with Option `WithServiceAddr`.
   200  // It won't take effect when listener is specified by WithListener.
   201  func WithReusePort(reuse bool) Option {
   202  	return Option{F: func(o *internal_server.Options, di *utils.Slice) {
   203  		di.Push(fmt.Sprintf("WithReusePort(%+v)", reuse))
   204  
   205  		o.RemoteOpt.ReusePort = reuse
   206  	}}
   207  }
   208  
   209  // WithSupportedTransportsFunc sets a function which converts supported transports from server option.
   210  func WithSupportedTransportsFunc(f func(option remote.ServerOption) []string) Option {
   211  	return Option{
   212  		F: func(o *internal_server.Options, di *utils.Slice) {
   213  			di.Push("WithSupportedTransportsFunc()")
   214  			o.SupportedTransportsFunc = f
   215  		},
   216  	}
   217  }
   218  
   219  // WithProfiler set a profiler to server.
   220  func WithProfiler(pc profiler.Profiler) Option {
   221  	return Option{F: func(o *internal_server.Options, di *utils.Slice) {
   222  		di.Push(fmt.Sprintf("WithProfiler(%T{%+v})", pc, pc))
   223  		o.RemoteOpt.Profiler = pc
   224  	}}
   225  }
   226  
   227  // WithProfilerTransInfoTagging set transinfo tagging function to profiler
   228  // TransInfoTagging extracting tags after TransInfo decoded but before message decoded.
   229  // At this stage, we can only get msg.TransInfo() and the real message payload is not decoded yet.
   230  // If upstream is not use TTHeader protocol, we can get nothing here.
   231  // So if you don't very care about the accuracy of statistics, we recommend to use WithProfilerMessageTagging to extract your custom tags.
   232  func WithProfilerTransInfoTagging(tagging remote.TransInfoTagging) Option {
   233  	return Option{F: func(o *internal_server.Options, di *utils.Slice) {
   234  		di.Push(fmt.Sprintf("WithProfilerTransInfoTagging(%+v)", utils.GetFuncName(tagging)))
   235  		interTagging := o.RemoteOpt.ProfilerTransInfoTagging
   236  		if interTagging == nil {
   237  			o.RemoteOpt.ProfilerTransInfoTagging = tagging
   238  			return
   239  		}
   240  		o.RemoteOpt.ProfilerTransInfoTagging = func(ctx context.Context, msg remote.Message) (context.Context, []string) {
   241  			c, t := tagging(ctx, msg)
   242  			c2, t2 := interTagging(c, msg)
   243  			return c2, append(t, t2...)
   244  		}
   245  	}}
   246  }
   247  
   248  // WithProfilerMessageTagging set message tagging function to profiler
   249  // MessageTagging extracting tags after whole decode process finished.
   250  // At this stage, we can get the rpcInfo from ctx, and full complete message.
   251  func WithProfilerMessageTagging(tagging remote.MessageTagging) Option {
   252  	return Option{F: func(o *internal_server.Options, di *utils.Slice) {
   253  		di.Push(fmt.Sprintf("WithProfilerMessageTagging(%+v)", utils.GetFuncName(tagging)))
   254  		interTagging := o.RemoteOpt.ProfilerMessageTagging
   255  		if interTagging == nil {
   256  			o.RemoteOpt.ProfilerMessageTagging = tagging
   257  			return
   258  		}
   259  		o.RemoteOpt.ProfilerMessageTagging = func(ctx context.Context, msg remote.Message) (context.Context, []string) {
   260  			c, t := tagging(ctx, msg)
   261  			c2, t2 := interTagging(c, msg)
   262  			return c2, append(t, t2...)
   263  		}
   264  	}}
   265  }