github.com/cloudwego/kitex@v0.9.0/tool/internal_pkg/tpl/service.go (about) 1 // Copyright 2022 CloudWeGo Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package tpl 16 17 // ServiceTpl is the template for generating the servicename.go source. 18 var ServiceTpl string = `// Code generated by Kitex {{.Version}}. DO NOT EDIT. 19 {{$HandlerReturnKeepResp := .HandlerReturnKeepResp}} 20 {{$UseThriftReflection := .UseThriftReflection}} 21 package {{ToLower .ServiceName}} 22 23 import ( 24 {{- range $path, $aliases := .Imports}} 25 {{- if not $aliases}} 26 "{{$path}}" 27 {{- else}} 28 {{- range $alias, $is := $aliases}} 29 {{$alias}} "{{$path}}" 30 {{- end}} 31 {{- end}} 32 {{- end}} 33 ) 34 35 var errInvalidMessageType = errors.New("invalid message type for service method handler") 36 37 {{- if gt (len .CombineServices) 0}} 38 type {{call .ServiceTypeName}} interface { 39 {{- range .CombineServices}} 40 {{.PkgRefName}}.{{.ServiceName}} 41 {{- end}} 42 } 43 {{- end}} 44 45 var serviceMethods = map[string]kitex.MethodInfo{ 46 {{- range .AllMethods}} 47 "{{.RawName}}": kitex.NewMethodInfo( 48 {{LowerFirst .Name}}Handler, 49 new{{.ArgStructName}}, 50 {{if .Oneway}}nil{{else}}new{{.ResStructName}}{{end}}, 51 {{if .Oneway}}true{{else}}false{{end}}, 52 kitex.WithStreamingMode( 53 {{- if and .ServerStreaming .ClientStreaming -}} kitex.StreamingBidirectional 54 {{- else if .ServerStreaming -}} kitex.StreamingServer 55 {{- else if .ClientStreaming -}} kitex.StreamingClient 56 {{- else -}} 57 {{- if or (eq $.Codec "protobuf") (eq .Streaming.Mode "unary") -}} kitex.StreamingUnary 58 {{- else -}} kitex.StreamingNone 59 {{- end -}} 60 {{- end}}), 61 ), 62 {{- end}} 63 } 64 65 var ( 66 {{LowerFirst .ServiceName}}ServiceInfo = NewServiceInfo() 67 {{LowerFirst .ServiceName}}ServiceInfoForClient = NewServiceInfoForClient() 68 {{LowerFirst .ServiceName}}ServiceInfoForStreamClient = NewServiceInfoForStreamClient() 69 ) 70 71 // for server 72 func serviceInfo() *kitex.ServiceInfo { 73 return {{LowerFirst .ServiceName}}ServiceInfo 74 } 75 76 // for client 77 func serviceInfoForStreamClient() *kitex.ServiceInfo { 78 return {{LowerFirst .ServiceName}}ServiceInfoForStreamClient 79 } 80 81 // for stream client 82 func serviceInfoForClient() *kitex.ServiceInfo { 83 return {{LowerFirst .ServiceName}}ServiceInfoForClient 84 } 85 86 // NewServiceInfo creates a new ServiceInfo containing all methods 87 {{- /* It's for the Server (providing both streaming/non-streaming APIs), or for the grpc client */}} 88 func NewServiceInfo() *kitex.ServiceInfo { 89 return newServiceInfo({{- if .HasStreaming}}true{{else}}false{{end}}, true, true) 90 } 91 92 // NewServiceInfo creates a new ServiceInfo containing non-streaming methods 93 {{- /* It's for the KitexThrift Client with only non-streaming APIs */}} 94 func NewServiceInfoForClient() *kitex.ServiceInfo { 95 return newServiceInfo(false, false, true) 96 } 97 98 {{- /* It's for the StreamClient with only streaming APIs */}} 99 func NewServiceInfoForStreamClient() *kitex.ServiceInfo { 100 return newServiceInfo(true, true, false) 101 } 102 103 func newServiceInfo(hasStreaming bool, keepStreamingMethods bool, keepNonStreamingMethods bool) *kitex.ServiceInfo { 104 serviceName := "{{.RawServiceName}}" 105 handlerType := (*{{call .ServiceTypeName}})(nil) 106 methods := map[string]kitex.MethodInfo{} 107 for name, m := range serviceMethods { 108 if m.IsStreaming() && !keepStreamingMethods { 109 continue 110 } 111 if !m.IsStreaming() && !keepNonStreamingMethods { 112 continue 113 } 114 methods[name] = m 115 } 116 extra := map[string]interface{}{ 117 "PackageName": "{{.PkgInfo.PkgName}}", 118 {{- if $UseThriftReflection }} 119 "ServiceFilePath": {{ backquoted .ServiceFilePath }}, 120 {{end}} 121 } 122 {{- if gt (len .CombineServices) 0}} 123 extra["combine_service"] = true 124 extra["combined_service_list"] = []string{ 125 {{- range .CombineServices}}"{{.ServiceName}}",{{- end}} 126 } 127 {{- end}} 128 if hasStreaming { 129 extra["streaming"] = hasStreaming 130 } 131 svcInfo := &kitex.ServiceInfo{ 132 ServiceName: serviceName, 133 HandlerType: handlerType, 134 Methods: methods, 135 {{- if ne "Hessian2" .ServiceInfo.Protocol}} 136 PayloadCodec: kitex.{{.Codec | UpperFirst}}, 137 {{- end}} 138 KiteXGenVersion: "{{.Version}}", 139 Extra: extra, 140 } 141 return svcInfo 142 } 143 144 {{range .AllMethods}} 145 {{- $isStreaming := or .ClientStreaming .ServerStreaming}} 146 {{- $unary := and (not .ServerStreaming) (not .ClientStreaming)}} 147 {{- $clientSide := and .ClientStreaming (not .ServerStreaming)}} 148 {{- $serverSide := and (not .ClientStreaming) .ServerStreaming}} 149 {{- $bidiSide := and .ClientStreaming .ServerStreaming}} 150 {{- $arg := "" }} 151 {{- if or (eq $.Codec "protobuf") ($isStreaming) }} 152 {{- $arg = index .Args 0}}{{/* streaming api only supports exactly one argument */}} 153 {{- end}} 154 155 func {{LowerFirst .Name}}Handler(ctx context.Context, handler interface{}, arg, result interface{}) error { 156 {{- if eq $.Codec "protobuf"}} {{/* protobuf logic */}} 157 {{- if $unary}} {{/* unary logic */}} 158 switch s := arg.(type) { 159 case *streaming.Args: 160 st := s.Stream 161 req := new({{NotPtr $arg.Type}}) 162 if err := st.RecvMsg(req); err != nil { 163 return err 164 } 165 resp, err := handler.({{.PkgRefName}}.{{.ServiceName}}).{{.Name}}(ctx, req) 166 if err != nil { 167 return err 168 } 169 return st.SendMsg(resp) 170 case *{{if not .GenArgResultStruct}}{{.PkgRefName}}.{{end}}{{.ArgStructName}}: 171 success, err := handler.({{.PkgRefName}}.{{.ServiceName}}).{{.Name}}(ctx{{range .Args}}, s.{{.Name}}{{end}}) 172 if err != nil { 173 return err 174 } 175 realResult := result.(*{{if not .GenArgResultStruct}}{{.PkgRefName}}.{{end}}{{.ResStructName}}) 176 realResult.Success = {{if .IsResponseNeedRedirect}}&{{end}}success 177 return nil 178 default: 179 return errInvalidMessageType 180 } 181 {{- else}}{{/* streaming logic */}} 182 streamingArgs, ok := arg.(*streaming.Args) 183 if !ok { 184 return errInvalidMessageType 185 } 186 st := streamingArgs.Stream 187 stream := &{{LowerFirst .ServiceName}}{{.RawName}}Server{st} 188 {{- if $serverSide}} 189 req := new({{NotPtr $arg.Type}}) 190 if err := st.RecvMsg(req); err != nil { 191 return err 192 } 193 {{- end}} 194 return handler.({{.PkgRefName}}.{{.ServiceName}}).{{.Name}}({{if $serverSide}}req, {{end}}stream) 195 {{- end}} {{/* $unary end */}} 196 {{- else}} {{/* thrift logic */}} 197 {{- if $unary}} {{/* unary logic */}} 198 {{- if eq .Streaming.Mode "unary"}} 199 if streaming.GetStream(ctx) == nil { 200 return errors.New("{{.ServiceName}}.{{.Name}} is a thrift streaming unary method, please call with Kitex StreamClient or remove the annotation streaming.mode") 201 } 202 {{- end}} 203 {{if gt .ArgsLength 0}}realArg := {{else}}_ = {{end}}arg.(*{{if not .GenArgResultStruct}}{{.PkgRefName}}.{{end}}{{.ArgStructName}}) 204 {{if or (not .Void) .Exceptions}}realResult := result.(*{{if not .GenArgResultStruct}}{{.PkgRefName}}.{{end}}{{.ResStructName}}){{end}} 205 {{if .Void}}err := handler.({{.PkgRefName}}.{{.ServiceName}}).{{.Name}}(ctx{{range .Args}}, realArg.{{.Name}}{{end}}) 206 {{else}}success, err := handler.({{.PkgRefName}}.{{.ServiceName}}).{{.Name}}(ctx{{range .Args}}, realArg.{{.Name}}{{end}}) 207 {{end -}} 208 if err != nil { 209 {{- if $HandlerReturnKeepResp }} 210 // still keep resp when err is not nil 211 // NOTE: use "-handler-return-keep-resp" to generate this 212 {{if not .Void}}realResult.Success = {{if .IsResponseNeedRedirect}}&{{end}}success{{- end}} 213 {{- end }} 214 {{if .Exceptions -}} 215 switch v := err.(type) { 216 {{range .Exceptions -}} 217 case {{.Type}}: 218 realResult.{{.Name}} = v 219 {{end -}} 220 default: 221 return err 222 } 223 } else { 224 {{else -}} 225 return err 226 } 227 {{end -}} 228 {{if not .Void}}realResult.Success = {{if .IsResponseNeedRedirect}}&{{end}}success{{end}} 229 {{- if .Exceptions}}}{{end}} 230 return nil 231 {{- else}} {{/* $isStreaming */}} 232 st, ok := arg.(*streaming.Args) 233 if !ok { 234 return errors.New("{{.ServiceName}}.{{.Name}} is a thrift streaming method, please call with Kitex StreamClient") 235 } 236 stream := &{{LowerFirst .ServiceName}}{{.RawName}}Server{st.Stream} 237 {{- if not $serverSide}} 238 return handler.({{.PkgRefName}}.{{.ServiceName}}).{{.Name}}(stream) 239 {{- else}} {{/* !$serverSide */}} 240 {{- $RequestType := $arg.Type}} 241 req := new({{NotPtr $RequestType}}) 242 if err := st.Stream.RecvMsg(req); err != nil { 243 return err 244 } 245 return handler.({{.PkgRefName}}.{{.ServiceName}}).{{.Name}}(req, stream) 246 {{- end}} {{/* $serverSide end*/}} 247 {{- end}} {{/* thrift end */}} 248 {{- end}} {{/* protobuf end */}} 249 } 250 251 {{- /* define streaming struct */}} 252 {{- if $isStreaming}} 253 type {{LowerFirst .ServiceName}}{{.RawName}}Client struct { 254 streaming.Stream 255 } 256 257 {{- if or $clientSide $bidiSide}} 258 func (x *{{LowerFirst .ServiceName}}{{.RawName}}Client) Send(m {{$arg.Type}}) error { 259 return x.Stream.SendMsg(m) 260 } 261 {{- end}} 262 263 {{- if $clientSide}} 264 func (x *{{LowerFirst .ServiceName}}{{.RawName}}Client) CloseAndRecv() ({{.Resp.Type}}, error) { 265 if err := x.Stream.Close(); err != nil { 266 return nil, err 267 } 268 m := new({{NotPtr .Resp.Type}}) 269 return m, x.Stream.RecvMsg(m) 270 } 271 {{- end}} 272 273 {{- if or $serverSide $bidiSide}} 274 func (x *{{LowerFirst .ServiceName}}{{.RawName}}Client) Recv() ({{.Resp.Type}}, error) { 275 m := new({{NotPtr .Resp.Type}}) 276 return m, x.Stream.RecvMsg(m) 277 } 278 {{- end}} 279 280 type {{LowerFirst .ServiceName}}{{.RawName}}Server struct { 281 streaming.Stream 282 } 283 284 {{if or $serverSide $bidiSide}} 285 func (x *{{LowerFirst .ServiceName}}{{.RawName}}Server) Send(m {{.Resp.Type}}) error { 286 return x.Stream.SendMsg(m) 287 } 288 {{end}} 289 290 {{if $clientSide}} 291 func (x *{{LowerFirst .ServiceName}}{{.RawName}}Server) SendAndClose(m {{.Resp.Type}}) error { 292 return x.Stream.SendMsg(m) 293 } 294 {{end}} 295 296 {{if or $clientSide $bidiSide}} 297 func (x *{{LowerFirst .ServiceName}}{{.RawName}}Server) Recv() ({{$arg.Type}}, error) { 298 m := new({{NotPtr $arg.Type}}) 299 return m, x.Stream.RecvMsg(m) 300 } 301 {{end}} 302 303 {{- end}} 304 {{- /* define streaming struct end */}} 305 func new{{.ArgStructName}}() interface{} { 306 return {{if not .GenArgResultStruct}}{{.PkgRefName}}.New{{.ArgStructName}}(){{else}}&{{.ArgStructName}}{}{{end}} 307 } 308 {{if not .Oneway}} 309 func new{{.ResStructName}}() interface{} { 310 return {{if not .GenArgResultStruct}}{{.PkgRefName}}.New{{.ResStructName}}(){{else}}&{{.ResStructName}}{}{{end}} 311 }{{end}} 312 313 {{- if .GenArgResultStruct}} 314 {{$arg := index .Args 0}} 315 type {{.ArgStructName}} struct { 316 Req {{$arg.Type}} 317 } 318 319 {{- if and (eq $.Codec "protobuf") (not $.NoFastAPI)}} {{/* protobuf logic */}} 320 func (p *{{.ArgStructName}}) FastRead(buf []byte, _type int8, number int32) (n int, err error) { 321 if !p.IsSetReq() { 322 p.Req = new({{NotPtr $arg.Type}}) 323 } 324 return p.Req.FastRead(buf, _type, number) 325 } 326 327 func (p *{{.ArgStructName}}) FastWrite(buf []byte) (n int) { 328 if !p.IsSetReq() { 329 return 0 330 } 331 return p.Req.FastWrite(buf) 332 } 333 334 func (p *{{.ArgStructName}}) Size() (n int) { 335 if !p.IsSetReq() { 336 return 0 337 } 338 return p.Req.Size() 339 } 340 {{- end}} {{/* protobuf end */}} 341 342 func (p *{{.ArgStructName}}) Marshal(out []byte) ([]byte, error) { 343 if !p.IsSetReq() { 344 return out, nil 345 } 346 return proto.Marshal(p.Req) 347 } 348 349 func (p *{{.ArgStructName}}) Unmarshal(in []byte) error { 350 msg := new({{NotPtr $arg.Type}}) 351 if err := proto.Unmarshal(in, msg); err != nil { 352 return err 353 } 354 p.Req = msg 355 return nil 356 } 357 358 var {{.ArgStructName}}_Req_DEFAULT {{$arg.Type}} 359 360 func (p *{{.ArgStructName}}) GetReq() {{$arg.Type}} { 361 if !p.IsSetReq() { 362 return {{.ArgStructName}}_Req_DEFAULT 363 } 364 return p.Req 365 } 366 367 func (p *{{.ArgStructName}}) IsSetReq() bool { 368 return p.Req != nil 369 } 370 371 func (p *{{.ArgStructName}}) GetFirstArgument() interface{} { 372 return p.Req 373 } 374 375 type {{.ResStructName}} struct { 376 Success {{.Resp.Type}} 377 } 378 379 var {{.ResStructName}}_Success_DEFAULT {{.Resp.Type}} 380 381 {{- if and (eq $.Codec "protobuf") (not $.NoFastAPI)}} {{/* protobuf logic */}} 382 func (p *{{.ResStructName}}) FastRead(buf []byte, _type int8, number int32) (n int, err error) { 383 if !p.IsSetSuccess() { 384 p.Success = new({{NotPtr .Resp.Type}}) 385 } 386 return p.Success.FastRead(buf, _type, number) 387 } 388 389 func (p *{{.ResStructName}}) FastWrite(buf []byte) (n int) { 390 if !p.IsSetSuccess() { 391 return 0 392 } 393 return p.Success.FastWrite(buf) 394 } 395 396 func (p *{{.ResStructName}}) Size() (n int) { 397 if !p.IsSetSuccess() { 398 return 0 399 } 400 return p.Success.Size() 401 } 402 {{- end}} {{/* protobuf end */}} 403 404 func (p *{{.ResStructName}}) Marshal(out []byte) ([]byte, error) { 405 if !p.IsSetSuccess() { 406 return out, nil 407 } 408 return proto.Marshal(p.Success) 409 } 410 411 func (p *{{.ResStructName}}) Unmarshal(in []byte) error { 412 msg := new({{NotPtr .Resp.Type}}) 413 if err := proto.Unmarshal(in, msg); err != nil { 414 return err 415 } 416 p.Success = msg 417 return nil 418 } 419 420 func (p *{{.ResStructName}}) GetSuccess() {{.Resp.Type}} { 421 if !p.IsSetSuccess() { 422 return {{.ResStructName}}_Success_DEFAULT 423 } 424 return p.Success 425 } 426 427 func (p *{{.ResStructName}}) SetSuccess(x interface{}) { 428 p.Success = x.({{.Resp.Type}}) 429 } 430 431 func (p *{{.ResStructName}}) IsSetSuccess() bool { 432 return p.Success != nil 433 } 434 435 func (p *{{.ResStructName}}) GetResult() interface{} { 436 return p.Success 437 } 438 {{- end}} 439 {{end}} 440 441 type kClient struct { 442 c client.Client 443 } 444 445 func newServiceClient(c client.Client) *kClient { 446 return &kClient{ 447 c: c, 448 } 449 } 450 451 {{range .AllMethods}} 452 {{- if or .ClientStreaming .ServerStreaming}} 453 {{- /* streaming logic */}} 454 func (p *kClient) {{.Name}}(ctx context.Context{{if not .ClientStreaming}}{{range .Args}}, {{LowerFirst .Name}} {{.Type}}{{end}}{{end}}) ({{.ServiceName}}_{{.RawName}}Client, error) { 455 streamClient, ok := p.c.(client.Streaming) 456 if !ok { 457 return nil, fmt.Errorf("client not support streaming") 458 } 459 res := new(streaming.Result) 460 err := streamClient.Stream(ctx, "{{.RawName}}", nil, res) 461 if err != nil { 462 return nil, err 463 } 464 stream := &{{LowerFirst .ServiceName}}{{.RawName}}Client{res.Stream} 465 {{if not .ClientStreaming -}} 466 {{$arg := index .Args 0}} 467 if err := stream.Stream.SendMsg({{LowerFirst $arg.Name}}); err != nil { 468 return nil, err 469 } 470 if err := stream.Stream.Close(); err != nil { 471 return nil, err 472 } 473 {{end -}} 474 return stream, nil 475 } 476 {{- else}} 477 func (p *kClient) {{.Name}}(ctx context.Context {{range .Args}}, {{.RawName}} {{.Type}}{{end}}) ({{if not .Void}}r {{.Resp.Type}}, {{end}}err error) { 478 var _args {{if not .GenArgResultStruct}}{{.PkgRefName}}.{{end}}{{.ArgStructName}} 479 {{range .Args -}} 480 _args.{{.Name}} = {{.RawName}} 481 {{end -}} 482 {{if .Void -}} 483 {{if .Oneway -}} 484 if err = p.c.Call(ctx, "{{.RawName}}", &_args, nil); err != nil { 485 return 486 } 487 {{else -}} 488 var _result {{if not .GenArgResultStruct}}{{.PkgRefName}}.{{end}}{{.ResStructName}} 489 if err = p.c.Call(ctx, "{{.RawName}}", &_args, &_result); err != nil { 490 return 491 } 492 {{if .Exceptions -}} 493 switch { 494 {{range .Exceptions -}} 495 case _result.{{.Name}} != nil: 496 return _result.{{.Name}} 497 {{end -}} 498 } 499 {{end -}} 500 {{end -}} 501 return nil 502 {{else -}} 503 var _result {{if not .GenArgResultStruct}}{{.PkgRefName}}.{{end}}{{.ResStructName}} 504 if err = p.c.Call(ctx, "{{.RawName}}", &_args, &_result); err != nil { 505 return 506 } 507 {{if .Exceptions -}} 508 switch { 509 {{range .Exceptions -}} 510 case _result.{{.Name}} != nil: 511 return r, _result.{{.Name}} 512 {{end -}} 513 } 514 {{end -}} 515 return _result.GetSuccess(), nil 516 {{end -}} 517 } 518 {{- end}} 519 {{end}} 520 521 {{- if .FrugalPretouch}} 522 var pretouchOnce sync.Once 523 func pretouch() { 524 pretouchOnce.Do(func() { 525 {{- if gt (len .AllMethods) 0}} 526 var err error 527 {{- range .AllMethods}} 528 err = frugal.Pretouch(reflect.TypeOf({{if not .GenArgResultStruct}}{{.PkgRefName}}.New{{.ArgStructName}}(){{else}}&{{.ArgStructName}}{}{{end}})) 529 if err != nil { 530 goto PRETOUCH_ERR 531 } 532 {{- if not .Oneway}} 533 err = frugal.Pretouch(reflect.TypeOf({{if not .GenArgResultStruct}}{{.PkgRefName}}.New{{.ResStructName}}(){{else}}&{{.ResStructName}}{}{{end}})) 534 if err != nil { 535 goto PRETOUCH_ERR 536 } 537 {{- end}} 538 {{- end}}{{/* range .AllMethods */}} 539 return 540 PRETOUCH_ERR: 541 println("Frugal pretouch in {{.ServiceName}} failed: " + err.Error()) 542 {{- end}}{{/* if gt (len .AllMethods) 0 */}} 543 }) 544 } 545 {{- end}}{{/* if .FrugalPretouch */}} 546 `