go.uber.org/yarpc@v1.72.1/encoding/thrift/register.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 thrift
    22  
    23  import (
    24  	"context"
    25  	"fmt"
    26  
    27  	"go.uber.org/thriftrw/protocol"
    28  	"go.uber.org/thriftrw/protocol/binary"
    29  	"go.uber.org/thriftrw/protocol/stream"
    30  	"go.uber.org/thriftrw/thriftreflect"
    31  	"go.uber.org/thriftrw/wire"
    32  	"go.uber.org/yarpc/api/transport"
    33  	"go.uber.org/yarpc/pkg/procedure"
    34  )
    35  
    36  // Register calls the RouteTable's Register method.
    37  //
    38  // This function exists for backwards compatibility only. It will be removed
    39  // in a future version.
    40  //
    41  // Deprecated: Use the RouteTable's Register method directly.
    42  func Register(r transport.RouteTable, rs []transport.Procedure) {
    43  	r.Register(rs)
    44  }
    45  
    46  // UnaryHandler is a convenience type alias for functions that act as Handlers.
    47  type UnaryHandler func(context.Context, wire.Value) (Response, error)
    48  
    49  // OnewayHandler is a convenience type alias for functions that act as OnewayHandlers.
    50  type OnewayHandler func(context.Context, wire.Value) error
    51  
    52  // HandlerSpec represents the handler behind a Thrift service method.
    53  type HandlerSpec struct {
    54  	Type   transport.Type
    55  	Unary  UnaryHandler
    56  	Oneway OnewayHandler
    57  	NoWire NoWireHandler
    58  }
    59  
    60  // Method represents a Thrift service method.
    61  type Method struct {
    62  	// Name of the method itself.
    63  	Name string
    64  
    65  	// The handler to call.
    66  	HandlerSpec HandlerSpec
    67  
    68  	// Snippet of Go code representing the function definition of the handler.
    69  	// This is useful for introspection.
    70  	Signature string
    71  
    72  	// ThriftModule, if non-nil, refers to the Thrift module from where this
    73  	// method is coming from.
    74  	ThriftModule *thriftreflect.ThriftModule
    75  }
    76  
    77  // Service is a generic Thrift service implementation.
    78  type Service struct {
    79  	// Name of the Thrift service. This is the name specified for the service
    80  	// in the IDL.
    81  	Name    string
    82  	Methods []Method
    83  }
    84  
    85  // BuildProcedures builds a list of Procedures from a Thrift service
    86  // specification.
    87  func BuildProcedures(s Service, opts ...RegisterOption) []transport.Procedure {
    88  	// default NoWire to true because this is the our final state to achieve
    89  	// but we still allow users to opt out by overriding NoWire to false.
    90  	rc := registerConfig{NoWire: true}
    91  	for _, opt := range opts {
    92  		opt.applyRegisterOption(&rc)
    93  	}
    94  
    95  	var proto protocol.Protocol = binary.Default
    96  	if rc.Protocol != nil {
    97  		proto = rc.Protocol
    98  	}
    99  
   100  	// Only if we're trying to use the 'NoWire' implementation do we check if the
   101  	// config's `Protocol` provides the streaming ones needed.
   102  	var streamReqReader stream.RequestReader = binary.Default
   103  	if rc.NoWire && rc.Protocol != nil {
   104  		if sp, ok := rc.Protocol.(stream.RequestReader); ok {
   105  			streamReqReader = sp
   106  		}
   107  	}
   108  
   109  	svc := s.Name
   110  	if rc.ServiceName != "" {
   111  		svc = rc.ServiceName
   112  	}
   113  
   114  	rs := make([]transport.Procedure, 0, len(s.Methods))
   115  
   116  	for _, method := range s.Methods {
   117  		var spec transport.HandlerSpec
   118  		switch method.HandlerSpec.Type {
   119  		case transport.Unary:
   120  			if rc.NoWire {
   121  				spec = transport.NewUnaryHandlerSpec(thriftNoWireHandler{
   122  					Handler:       method.HandlerSpec.NoWire,
   123  					RequestReader: streamReqReader,
   124  				})
   125  			} else {
   126  				spec = transport.NewUnaryHandlerSpec(thriftUnaryHandler{
   127  					UnaryHandler: method.HandlerSpec.Unary,
   128  					Protocol:     proto,
   129  					Enveloping:   rc.Enveloping,
   130  				})
   131  			}
   132  		case transport.Oneway:
   133  			if rc.NoWire {
   134  				spec = transport.NewOnewayHandlerSpec(thriftNoWireHandler{
   135  					Handler:       method.HandlerSpec.NoWire,
   136  					RequestReader: streamReqReader,
   137  				})
   138  			} else {
   139  				spec = transport.NewOnewayHandlerSpec(thriftOnewayHandler{
   140  					OnewayHandler: method.HandlerSpec.Oneway,
   141  					Protocol:      proto,
   142  					Enveloping:    rc.Enveloping,
   143  				})
   144  			}
   145  		default:
   146  			panic(fmt.Sprintf("Invalid handler type for %T", method))
   147  		}
   148  
   149  		rs = append(rs, transport.Procedure{
   150  			Name:        procedure.ToName(svc, method.Name),
   151  			HandlerSpec: spec,
   152  			Encoding:    Encoding,
   153  			Signature:   method.Signature,
   154  		})
   155  	}
   156  	return rs
   157  }