Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/public-api/go/protoc-proxy-gen/protoc-proxy-gen.go
2500 views
1
// Copyright (c) 2023 Gitpod GmbH. All rights reserved.
2
// Licensed under the GNU Affero General Public License (AGPL).
3
// See License.AGPL.txt in the project root for license information.
4
5
package main
6
7
import (
8
"fmt"
9
"path"
10
11
"google.golang.org/protobuf/compiler/protogen"
12
"google.golang.org/protobuf/types/pluginpb"
13
)
14
15
const (
16
contextPackage = protogen.GoImportPath("context")
17
connectPackage = protogen.GoImportPath("github.com/bufbuild/connect-go")
18
)
19
20
func main() {
21
protogen.Options{}.Run(func(gen *protogen.Plugin) error {
22
gen.SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)
23
24
for _, f := range gen.Files {
25
if !f.Generate {
26
continue
27
}
28
generateFile(gen, f)
29
}
30
return nil
31
})
32
}
33
34
func generateFile(gen *protogen.Plugin, file *protogen.File) {
35
// We only generate our proxy implementation for services, not for raw structs
36
if len(file.Services) == 0 {
37
return
38
}
39
40
var (
41
targetPackageName = fmt.Sprintf("%sconnect", file.GoPackageName)
42
43
filename = path.Join(
44
path.Dir(file.GeneratedFilenamePrefix),
45
targetPackageName,
46
fmt.Sprintf("%s.proxy.connect.go", path.Base(file.GeneratedFilenamePrefix)))
47
importPath = protogen.GoImportPath(path.Join(string(file.GoImportPath), string(file.GoPackageName)))
48
)
49
50
// Setup a new generated file
51
g := gen.NewGeneratedFile(filename, importPath)
52
53
// generate preamble
54
g.P("// Code generated by protoc-proxy-gen. DO NOT EDIT.")
55
g.P()
56
g.P("package ", targetPackageName)
57
g.P()
58
g.Import(file.GoImportPath)
59
g.P()
60
61
// generate individual services
62
for _, service := range file.Services {
63
// generate struct definition
64
handlerStructName := fmt.Sprintf("Proxy%sHandler", service.GoName)
65
66
// Generate a type assertion to ensure the handler implements the connect handler interface
67
g.P(fmt.Sprintf("var _ %sHandler = (*%s)(nil)", service.GoName, handlerStructName))
68
69
g.Annotate(handlerStructName, service.Location)
70
g.P(fmt.Sprintf("type %s struct {", handlerStructName))
71
g.P(fmt.Sprintf(" Client %s", g.QualifiedGoIdent(file.GoImportPath.Ident(service.GoName+"Client"))))
72
g.P(fmt.Sprintf(" Unimplemented%sHandler", service.GoName))
73
g.P("}")
74
g.P()
75
76
for _, method := range service.Methods {
77
// We do not generate any non-unary methods, for now.
78
// Should we need these, we can choose to do so and handle them explicitly.
79
// The handler still continues to work fine, as it inherits from the default Unimplemented handling, and will
80
// always return Unimplemented.
81
if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() {
82
continue
83
}
84
85
// method signature
86
g.P(fmt.Sprintf("func (s *%s) %s(ctx %s, req *%s) (*%s, error) {",
87
handlerStructName,
88
method.GoName,
89
g.QualifiedGoIdent(contextPackage.Ident("Context")),
90
g.QualifiedGoIdent(connectPackage.Ident("Request"))+"["+g.QualifiedGoIdent(method.Input.GoIdent)+"]",
91
g.QualifiedGoIdent(connectPackage.Ident("Response"))+"["+g.QualifiedGoIdent(method.Output.GoIdent)+"]",
92
))
93
94
// method implementation
95
g.P(fmt.Sprintf(" resp, err := s.Client.%s(ctx, req.Msg)", method.GoName))
96
g.P(" if err != nil {")
97
g.P(" // TODO(milan): Convert to correct status code")
98
g.P(" return nil, err")
99
g.P(" }")
100
g.P()
101
g.P(fmt.Sprintf(" return %s(resp), nil", g.QualifiedGoIdent(connectPackage.Ident("NewResponse"))))
102
103
// method end
104
g.P("}")
105
g.P()
106
}
107
}
108
}
109
110