go.uber.org/yarpc@v1.72.1/encoding/thrift/thriftrw-plugin-yarpc/server.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 main 22 23 import ( 24 "path/filepath" 25 26 "go.uber.org/thriftrw/plugin" 27 ) 28 29 const serverTemplate = ` 30 // Code generated by thriftrw-plugin-yarpc 31 // @generated 32 33 <$pkgname := printf "%sserver" (lower .Name)> 34 package <$pkgname> 35 36 <$thrift := import "go.uber.org/yarpc/encoding/thrift"> 37 <$transport := import "go.uber.org/yarpc/api/transport"> 38 39 <$contextImportPath := .ContextImportPath> 40 <$onewayWrapperImport := .OnewayWrapperImport> 41 <$onewayWrapperFunc := .OnewayWrapperFunc> 42 <$unaryWrapperImport := .UnaryWrapperImport> 43 <$unaryWrapperFunc := .UnaryWrapperFunc> 44 45 </* Note that we import things like "context" inside loops rather than at the 46 top-level because they will end up unused if the service does not have any 47 functions. 48 */> 49 50 // Interface is the server-side interface for the <.Name> service. 51 type Interface interface { 52 <if .Parent><import .ParentServerPackagePath>.Interface 53 <end> 54 <range .Functions> 55 <$context := import $contextImportPath> 56 <.Name>( 57 ctx <$context>.Context, <range .Arguments> 58 <.Name> <formatType .Type>,<end> 59 )<if .OneWay> error 60 <else if .ReturnType> (<formatType .ReturnType>, error) 61 <else> error 62 <end> 63 <end> 64 } 65 66 <$module := .Module> 67 68 // New prepares an implementation of the <.Name> service for 69 // registration. 70 // 71 // handler := <.Name>Handler{} 72 // dispatcher.Register(<$pkgname>.New(handler)) 73 func New(impl Interface, opts ...<$thrift>.RegisterOption) []<$transport>.Procedure { 74 <if .Functions>h := handler{impl}<end> 75 service := <$thrift>.Service{ 76 Name: "<.Name>", 77 Methods: []<$thrift>.Method{ 78 <range .Functions> 79 <$thrift>.Method{ 80 Name: "<.ThriftName>", 81 HandlerSpec: <$thrift>.HandlerSpec{ 82 <if .OneWay> 83 Type: <$transport>.Oneway, 84 Oneway: <import $onewayWrapperImport>.<$onewayWrapperFunc>(h.<.Name>), 85 <else> 86 Type: <$transport>.Unary, 87 Unary: <import $unaryWrapperImport>.<$unaryWrapperFunc>(h.<.Name>), 88 <end -> 89 NoWire: <(lower .Name)>_NoWireHandler{impl}, 90 }, 91 Signature: "<.Name>(<range $i, $v := .Arguments><if ne $i 0>, <end><.Name> <formatType .Type><end>)<if not .OneWay | and .ReturnType> (<formatType .ReturnType>)<end>", 92 ThriftModule: <import $module.ImportPath>.ThriftModule, 93 }, 94 <end>}, 95 } 96 97 procedures := make([]<$transport>.Procedure, 0, <len .Functions>) 98 <if .Parent> 99 procedures = append( 100 procedures, 101 <import .ParentServerPackagePath>.New( 102 impl, 103 append( 104 opts, 105 <$thrift>.Named(<printf "%q" .Name>), 106 )..., 107 )..., 108 ) 109 <end -> 110 procedures = append(procedures, <$thrift>.BuildProcedures(service, opts...)...) 111 return procedures 112 } 113 114 <if .Functions> 115 type handler struct{ impl Interface } 116 117 <$yarpcerrors := import "go.uber.org/yarpc/yarpcerrors"> 118 119 type yarpcErrorNamer interface { YARPCErrorName() string } 120 121 type yarpcErrorCoder interface { YARPCErrorCode() *yarpcerrors.Code } 122 <end> 123 124 <$service := .> 125 <$module := .Module> 126 <range .Functions> 127 <$context := import $contextImportPath> 128 <$prefix := printf "%s.%s_%s_" (import $module.ImportPath) $service.Name .Name> 129 130 <$wire := import "go.uber.org/thriftrw/wire"> 131 132 <if .OneWay> 133 func (h handler) <.Name>(ctx <$context>.Context, body <$wire>.Value) error { 134 var args <$prefix>Args 135 if err := args.FromWire(body); err != nil { 136 return err 137 } 138 139 return h.impl.<.Name>(ctx, <range .Arguments>args.<.Name>,<end>) 140 } 141 <else> 142 <$yarpcerrors := import "go.uber.org/yarpc/yarpcerrors"> 143 func (h handler) <.Name>(ctx <$context>.Context, body <$wire>.Value) (<$thrift>.Response, error) { 144 var args <$prefix>Args 145 if err := args.FromWire(body); err != nil { 146 return <$thrift>.Response{}, <$yarpcerrors>.InvalidArgumentErrorf( 147 "could not decode Thrift request for service '<$service.Name>' procedure '<.Name>': %w", err) 148 } 149 150 <if .ReturnType> 151 success, appErr := h.impl.<.Name>(ctx, <range .Arguments>args.<.Name>,<end>) 152 <else> 153 appErr := h.impl.<.Name>(ctx, <range .Arguments>args.<.Name>,<end>) 154 <end> 155 156 hadError := appErr != nil 157 result, err := <$prefix>Helper.WrapResponse(<if .ReturnType>success,<end> appErr) 158 159 var response <$thrift>.Response 160 if err == nil { 161 response.IsApplicationError = hadError 162 response.Body = result 163 if namer, ok := appErr.(yarpcErrorNamer); ok { 164 response.ApplicationErrorName = namer.YARPCErrorName() 165 } 166 if extractor, ok := appErr.(yarpcErrorCoder); ok { 167 response.ApplicationErrorCode = extractor.YARPCErrorCode() 168 } 169 if appErr != nil { 170 response.ApplicationErrorDetails = appErr.Error() 171 } 172 } 173 174 return response, err 175 } 176 <end> 177 <end> 178 179 <range .Functions> 180 <$context := import $contextImportPath> 181 <$yarpcerrors := import "go.uber.org/yarpc/yarpcerrors"> 182 <$prefix := printf "%s.%s_%s_" (import $module.ImportPath) $service.Name .Name> 183 184 type <(lower .Name)>_NoWireHandler struct{ impl Interface } 185 186 func (h <(lower .Name)>_NoWireHandler) HandleNoWire(ctx <$context>.Context, nwc *<$thrift>.NoWireCall) (<$thrift>.NoWireResponse, error) { 187 var ( 188 args <$prefix>Args 189 <if not .OneWay>rw <import "go.uber.org/thriftrw/protocol/stream">.ResponseWriter<end> 190 err error 191 ) 192 193 <if .OneWay> 194 if _, err = nwc.RequestReader.ReadRequest(ctx, nwc.EnvelopeType, nwc.Reader, &args); err != nil { 195 return <$thrift>.NoWireResponse{}, <$yarpcerrors>.InvalidArgumentErrorf( 196 "could not decode (via no wire) Thrift request for service '<$service.Name>' procedure '<.Name>': %w", err) 197 } 198 199 return <$thrift>.NoWireResponse{}, h.impl.<.Name>(ctx, <range .Arguments>args.<.Name>,<end>) 200 <else> 201 rw, err = nwc.RequestReader.ReadRequest(ctx, nwc.EnvelopeType, nwc.Reader, &args) 202 if err != nil { 203 return <$thrift>.NoWireResponse{}, <$yarpcerrors>.InvalidArgumentErrorf( 204 "could not decode (via no wire) Thrift request for service '<$service.Name>' procedure '<.Name>': %w", err) 205 } 206 207 <if .ReturnType> 208 success, appErr := h.impl.<.Name>(ctx, <range .Arguments>args.<.Name>,<end>) 209 <else> 210 appErr := h.impl.<.Name>(ctx, <range .Arguments>args.<.Name>,<end>) 211 <end> 212 213 hadError := appErr != nil 214 result, err := <$prefix>Helper.WrapResponse(<if .ReturnType>success,<end> appErr) 215 response := <$thrift>.NoWireResponse{ResponseWriter: rw} 216 if err == nil { 217 response.IsApplicationError = hadError 218 response.Body = result 219 if namer, ok := appErr.(yarpcErrorNamer); ok { 220 response.ApplicationErrorName = namer.YARPCErrorName() 221 } 222 if extractor, ok := appErr.(yarpcErrorCoder); ok { 223 response.ApplicationErrorCode = extractor.YARPCErrorCode() 224 } 225 if appErr != nil { 226 response.ApplicationErrorDetails = appErr.Error() 227 } 228 } 229 return response, err 230 <end> 231 } 232 <end> 233 ` 234 235 func serverGenerator(data *serviceTemplateData, files map[string][]byte) (err error) { 236 packageName := filepath.Base(data.ServerPackagePath()) 237 // kv.thrift => .../kv/keyvalueserver/server.go 238 path := filepath.Join(data.Module.Directory, packageName, "server.go") 239 files[path], err = plugin.GoFileFromTemplate(path, serverTemplate, data, templateOptions...) 240 return 241 }