go.uber.org/yarpc@v1.72.1/encoding/thrift/thriftrw-plugin-yarpc/main.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 // thriftrw-plugin-yarpc implements a plugin for ThriftRW that generates code 22 // compatible with YARPC. 23 // 24 // thriftrw-plugin-yarpc supports "rpc.code" annotations on Thrift exceptions. 25 // For example: 26 // 27 // exception ExceptionWithCode { 28 // 1: required string val 29 // } ( 30 // rpc.code = "INVALID_ARGUMENT" 31 // ) 32 // 33 // The "rpc.code" annotation can be any code matching the string name of gRPC 34 // status enum codes. YARPC error codes match 1-1 with these codes, however gRPC 35 // uses a different string name representation. We choose to use the raw gRPC 36 // enum code names instead to ensure cross-language compatibility with other 37 // languages, such as Java. 38 // - https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto 39 // 40 // Available string names method: 41 // - "CANCELLED" 42 // - "UNKNOWN" 43 // - "INVALID_ARGUMENT" 44 // - "DEADLINE_EXCEEDED" 45 // - "NOT_FOUND" 46 // - "ALREADY_EXISTS" 47 // - "PERMISSION_DENIED" 48 // - "RESOURCE_EXHAUSTED" 49 // - "FAILED_PRECONDITION" 50 // - "ABORTED" 51 // - "OUT_OF_RANGE" 52 // - "UNIMPLEMENTED" 53 // - "INTERNAL" 54 // - "UNAVAILABLE" 55 // - "DATA_LOSS" 56 // - "UNAUTHENTICATED" 57 // 58 // Adding codes will affect YARPC's observability middleware classification of 59 // client and server errors for Thrift exceptions. 60 // 61 // For more information on the Thrift encoding, check the documentation of the 62 // parent package. 63 package main 64 65 import ( 66 "flag" 67 "strings" 68 69 "go.uber.org/thriftrw/plugin" 70 "go.uber.org/thriftrw/plugin/api" 71 ) 72 73 // Command line flags 74 var ( 75 _context = flag.String("context-import-path", 76 "context", 77 "Import path at which Context is available") 78 _unaryHandlerWrapper = flag.String("unary-handler-wrapper", 79 "go.uber.org/yarpc/encoding/thrift.UnaryHandler", 80 "Function used to wrap generic Thrift unary function handlers into YARPC handlers") 81 _onewayHandlerWrapper = flag.String("oneway-handler-wrapper", 82 "go.uber.org/yarpc/encoding/thrift.OnewayHandler", 83 "Function used to wrap generic Thrift oneway function handlers into YARPC handlers") 84 _noGomock = flag.Bool("no-gomock", false, 85 "Don't generate gomock mocks for service clients") 86 _noFx = flag.Bool("no-fx", false, "Don't generate Fx module") 87 _sanitizeTChannel = flag.Bool("sanitize-tchannel", false, "Enable tchannel context sanitization") 88 ) 89 90 type g struct { 91 SanitizeTChannel bool 92 } 93 94 func (g g) Generate(req *api.GenerateServiceRequest) (*api.GenerateServiceResponse, error) { 95 // moduleGenerators apply to all Thrift IDL files, even when no service 96 // definition exists 97 moduleGenerators := []moduleGenFunc{yarpcErrorGenerator} 98 99 // serviceGenerators apply only when one or more services are defined in the 100 // Thrift IDL file. 101 serviceGenerators := []serviceGenFunc{clientGenerator, serverGenerator} 102 if !*_noFx { 103 serviceGenerators = append(serviceGenerators, fxGenerator) 104 } 105 if !*_noGomock { 106 serviceGenerators = append(serviceGenerators, gomockGenerator) 107 } 108 109 unaryWrapperImport, unaryWrapperFunc := splitFunctionPath(*_unaryHandlerWrapper) 110 onewayWrapperImport, onewayWrapperFunc := splitFunctionPath(*_onewayHandlerWrapper) 111 112 files := make(map[string][]byte) 113 114 for _, serviceID := range req.RootServices { 115 data := serviceTemplateData{ 116 Svc: buildSvc(serviceID, req), 117 ContextImportPath: *_context, 118 UnaryWrapperImport: unaryWrapperImport, 119 UnaryWrapperFunc: unaryWrapperFunc, 120 OnewayWrapperImport: onewayWrapperImport, 121 OnewayWrapperFunc: onewayWrapperFunc, 122 SanitizeTChannel: g.SanitizeTChannel, 123 } 124 for _, gen := range serviceGenerators { 125 if err := gen(&data, files); err != nil { 126 return nil, err 127 } 128 } 129 } 130 131 for _, moduleID := range req.RootModules { 132 data := moduleTemplateData{ 133 Module: req.Modules[moduleID], 134 ContextImportPath: *_context, 135 } 136 for _, gen := range moduleGenerators { 137 if err := gen(&data, files); err != nil { 138 return nil, err 139 } 140 } 141 } 142 return &api.GenerateServiceResponse{Files: files}, nil 143 } 144 145 func splitFunctionPath(input string) (string, string) { 146 i := strings.LastIndex(input, ".") 147 return input[:i], input[i+1:] 148 } 149 150 func buildSvc(serviceID api.ServiceID, req *api.GenerateServiceRequest) *Svc { 151 service := req.Services[serviceID] 152 module := req.Modules[service.ModuleID] 153 154 var parents []*Svc 155 if service.ParentID != nil { 156 parentSvc := buildSvc(*service.ParentID, req) 157 parents = append(parents, parentSvc) 158 parents = append(parents, parentSvc.Parents...) 159 } 160 161 return &Svc{ 162 Service: service, 163 Module: module, 164 Parents: parents, 165 } 166 } 167 168 func main() { 169 flag.Parse() 170 plugin.Main(&plugin.Plugin{Name: "yarpc", ServiceGenerator: g{ 171 SanitizeTChannel: *_sanitizeTChannel, 172 }}) 173 }