go.uber.org/yarpc@v1.72.1/internal/inboundmiddleware/chain.go (about)

     1  // Copyright (c) 2022 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package inboundmiddleware
    22  
    23  import (
    24  	"context"
    25  
    26  	"go.uber.org/yarpc/api/middleware"
    27  	"go.uber.org/yarpc/api/transport"
    28  )
    29  
    30  // UnaryChain combines a series of `UnaryInbound`s into a single `InboundMiddleware`.
    31  func UnaryChain(mw ...middleware.UnaryInbound) middleware.UnaryInbound {
    32  	unchained := make([]middleware.UnaryInbound, 0, len(mw))
    33  	for _, m := range mw {
    34  		if m == nil {
    35  			continue
    36  		}
    37  		if c, ok := m.(unaryChain); ok {
    38  			unchained = append(unchained, c...)
    39  			continue
    40  		}
    41  		unchained = append(unchained, m)
    42  	}
    43  
    44  	switch len(unchained) {
    45  	case 0:
    46  		return middleware.NopUnaryInbound
    47  	case 1:
    48  		return unchained[0]
    49  	default:
    50  		return unaryChain(unchained)
    51  	}
    52  }
    53  
    54  type unaryChain []middleware.UnaryInbound
    55  
    56  func (c unaryChain) Handle(ctx context.Context, req *transport.Request, resw transport.ResponseWriter, h transport.UnaryHandler) error {
    57  	return unaryChainExec{
    58  		Chain: []middleware.UnaryInbound(c),
    59  		Final: h,
    60  	}.Handle(ctx, req, resw)
    61  }
    62  
    63  // unaryChainExec adapts a series of `UnaryInbound`s into a UnaryHandler.
    64  // It is scoped to a single request to the `Handler` and is not thread-safe.
    65  type unaryChainExec struct {
    66  	Chain []middleware.UnaryInbound
    67  	Final transport.UnaryHandler
    68  }
    69  
    70  func (x unaryChainExec) Handle(ctx context.Context, req *transport.Request, resw transport.ResponseWriter) error {
    71  	if len(x.Chain) == 0 {
    72  		return x.Final.Handle(ctx, req, resw)
    73  	}
    74  	next := x.Chain[0]
    75  	x.Chain = x.Chain[1:]
    76  	return next.Handle(ctx, req, resw, x)
    77  }
    78  
    79  // OnewayChain combines a series of `OnewayInbound`s into a single `InboundMiddleware`.
    80  func OnewayChain(mw ...middleware.OnewayInbound) middleware.OnewayInbound {
    81  	unchained := make([]middleware.OnewayInbound, 0, len(mw))
    82  	for _, m := range mw {
    83  		if m == nil {
    84  			continue
    85  		}
    86  		if c, ok := m.(onewayChain); ok {
    87  			unchained = append(unchained, c...)
    88  			continue
    89  		}
    90  		unchained = append(unchained, m)
    91  	}
    92  
    93  	switch len(unchained) {
    94  	case 0:
    95  		return middleware.NopOnewayInbound
    96  	case 1:
    97  		return unchained[0]
    98  	default:
    99  		return onewayChain(unchained)
   100  	}
   101  }
   102  
   103  type onewayChain []middleware.OnewayInbound
   104  
   105  func (c onewayChain) HandleOneway(ctx context.Context, req *transport.Request, h transport.OnewayHandler) error {
   106  	return onewayChainExec{
   107  		Chain: []middleware.OnewayInbound(c),
   108  		Final: h,
   109  	}.HandleOneway(ctx, req)
   110  }
   111  
   112  // onewayChainExec adapts a series of `OnewayInbound`s into a OnewayHandler.
   113  // It is scoped to a single request to the `Handler` and is not thread-safe.
   114  type onewayChainExec struct {
   115  	Chain []middleware.OnewayInbound
   116  	Final transport.OnewayHandler
   117  }
   118  
   119  func (x onewayChainExec) HandleOneway(ctx context.Context, req *transport.Request) error {
   120  	if len(x.Chain) == 0 {
   121  		return x.Final.HandleOneway(ctx, req)
   122  	}
   123  	next := x.Chain[0]
   124  	x.Chain = x.Chain[1:]
   125  	return next.HandleOneway(ctx, req, x)
   126  }
   127  
   128  // StreamChain combines a series of `StreamInbound`s into a single `InboundMiddleware`.
   129  func StreamChain(mw ...middleware.StreamInbound) middleware.StreamInbound {
   130  	unchained := make([]middleware.StreamInbound, 0, len(mw))
   131  	for _, m := range mw {
   132  		if m == nil {
   133  			continue
   134  		}
   135  		if c, ok := m.(streamChain); ok {
   136  			unchained = append(unchained, c...)
   137  			continue
   138  		}
   139  		unchained = append(unchained, m)
   140  	}
   141  
   142  	switch len(unchained) {
   143  	case 0:
   144  		return middleware.NopStreamInbound
   145  	case 1:
   146  		return unchained[0]
   147  	default:
   148  		return streamChain(unchained)
   149  	}
   150  }
   151  
   152  type streamChain []middleware.StreamInbound
   153  
   154  func (c streamChain) HandleStream(s *transport.ServerStream, h transport.StreamHandler) error {
   155  	return streamChainExec{
   156  		Chain: []middleware.StreamInbound(c),
   157  		Final: h,
   158  	}.HandleStream(s)
   159  }
   160  
   161  // streamChainExec adapts a series of `StreamInbound`s into a StreamHandler.
   162  // It is scoped to a single request to the `Handler` and is not thread-safe.
   163  type streamChainExec struct {
   164  	Chain []middleware.StreamInbound
   165  	Final transport.StreamHandler
   166  }
   167  
   168  func (x streamChainExec) HandleStream(s *transport.ServerStream) error {
   169  	if len(x.Chain) == 0 {
   170  		return x.Final.HandleStream(s)
   171  	}
   172  	next := x.Chain[0]
   173  	x.Chain = x.Chain[1:]
   174  	return next.HandleStream(s, x)
   175  }