Path: blob/main/components/public-api/go/protoc-proxy-gen/protoc-proxy-gen.go
2500 views
// Copyright (c) 2023 Gitpod GmbH. All rights reserved.1// Licensed under the GNU Affero General Public License (AGPL).2// See License.AGPL.txt in the project root for license information.34package main56import (7"fmt"8"path"910"google.golang.org/protobuf/compiler/protogen"11"google.golang.org/protobuf/types/pluginpb"12)1314const (15contextPackage = protogen.GoImportPath("context")16connectPackage = protogen.GoImportPath("github.com/bufbuild/connect-go")17)1819func main() {20protogen.Options{}.Run(func(gen *protogen.Plugin) error {21gen.SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)2223for _, f := range gen.Files {24if !f.Generate {25continue26}27generateFile(gen, f)28}29return nil30})31}3233func generateFile(gen *protogen.Plugin, file *protogen.File) {34// We only generate our proxy implementation for services, not for raw structs35if len(file.Services) == 0 {36return37}3839var (40targetPackageName = fmt.Sprintf("%sconnect", file.GoPackageName)4142filename = path.Join(43path.Dir(file.GeneratedFilenamePrefix),44targetPackageName,45fmt.Sprintf("%s.proxy.connect.go", path.Base(file.GeneratedFilenamePrefix)))46importPath = protogen.GoImportPath(path.Join(string(file.GoImportPath), string(file.GoPackageName)))47)4849// Setup a new generated file50g := gen.NewGeneratedFile(filename, importPath)5152// generate preamble53g.P("// Code generated by protoc-proxy-gen. DO NOT EDIT.")54g.P()55g.P("package ", targetPackageName)56g.P()57g.Import(file.GoImportPath)58g.P()5960// generate individual services61for _, service := range file.Services {62// generate struct definition63handlerStructName := fmt.Sprintf("Proxy%sHandler", service.GoName)6465// Generate a type assertion to ensure the handler implements the connect handler interface66g.P(fmt.Sprintf("var _ %sHandler = (*%s)(nil)", service.GoName, handlerStructName))6768g.Annotate(handlerStructName, service.Location)69g.P(fmt.Sprintf("type %s struct {", handlerStructName))70g.P(fmt.Sprintf(" Client %s", g.QualifiedGoIdent(file.GoImportPath.Ident(service.GoName+"Client"))))71g.P(fmt.Sprintf(" Unimplemented%sHandler", service.GoName))72g.P("}")73g.P()7475for _, method := range service.Methods {76// We do not generate any non-unary methods, for now.77// Should we need these, we can choose to do so and handle them explicitly.78// The handler still continues to work fine, as it inherits from the default Unimplemented handling, and will79// always return Unimplemented.80if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() {81continue82}8384// method signature85g.P(fmt.Sprintf("func (s *%s) %s(ctx %s, req *%s) (*%s, error) {",86handlerStructName,87method.GoName,88g.QualifiedGoIdent(contextPackage.Ident("Context")),89g.QualifiedGoIdent(connectPackage.Ident("Request"))+"["+g.QualifiedGoIdent(method.Input.GoIdent)+"]",90g.QualifiedGoIdent(connectPackage.Ident("Response"))+"["+g.QualifiedGoIdent(method.Output.GoIdent)+"]",91))9293// method implementation94g.P(fmt.Sprintf(" resp, err := s.Client.%s(ctx, req.Msg)", method.GoName))95g.P(" if err != nil {")96g.P(" // TODO(milan): Convert to correct status code")97g.P(" return nil, err")98g.P(" }")99g.P()100g.P(fmt.Sprintf(" return %s(resp), nil", g.QualifiedGoIdent(connectPackage.Ident("NewResponse"))))101102// method end103g.P("}")104g.P()105}106}107}108109110