/
server_types.go
123 lines (116 loc) Β· 3.39 KB
/
server_types.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package codegen
import (
"path"
"path/filepath"
"goa.design/goa/codegen"
"goa.design/goa/expr"
)
// ServerTypeFiles returns the types file for every gRPC service that contain
// constructors to transform:
//
// * protocol buffer request message types into service payload types
// * service result types into protocol buffer response message types
func ServerTypeFiles(genpkg string, root *expr.RootExpr) []*codegen.File {
fw := make([]*codegen.File, len(root.API.GRPC.Services))
seen := make(map[string]struct{})
for i, r := range root.API.GRPC.Services {
fw[i] = serverType(genpkg, r, seen)
}
return fw
}
// serverType returns the file containing the constructor functions to
// transform the gRPC request types to the corresponding service payload types
// and service result types to the corresponding gRPC response types.
//
// seen keeps track of the constructor names that have already been generated
// to prevent duplicate code generation.
func serverType(genpkg string, svc *expr.GRPCServiceExpr, seen map[string]struct{}) *codegen.File {
var (
initData []*InitData
sd = GRPCServices.Get(svc.Name())
foundInits = make(map[string]struct{})
)
{
collect := func(c *ConvertData) {
if c.Init != nil {
initData = append(initData, c.Init)
}
}
for _, a := range svc.GRPCEndpoints {
ed := sd.Endpoint(a.Name())
if c := ed.Request.ServerConvert; c != nil {
collect(c)
}
if c := ed.Response.ServerConvert; c != nil {
collect(c)
}
if ed.ServerStream != nil {
if c := ed.ServerStream.SendConvert; c != nil {
collect(c)
}
if c := ed.ServerStream.RecvConvert; c != nil {
collect(c)
}
}
for _, e := range ed.Errors {
if c := e.Response.ServerConvert; c != nil {
collect(c)
}
}
}
}
var (
fpath string
sections []*codegen.SectionTemplate
)
{
svcName := codegen.SnakeCase(sd.Service.VarName)
fpath = filepath.Join(codegen.Gendir, "grpc", svcName, "server", "types.go")
sections = []*codegen.SectionTemplate{
codegen.Header(svc.Name()+" gRPC server types", "server",
[]*codegen.ImportSpec{
{Path: "unicode/utf8"},
{Path: "goa.design/goa", Name: "goa"},
{Path: path.Join(genpkg, svcName), Name: sd.Service.PkgName},
{Path: path.Join(genpkg, svcName, "views"), Name: sd.Service.ViewsPkg},
{Path: path.Join(genpkg, "grpc", svcName, pbPkgName), Name: sd.PkgName},
}),
}
for _, init := range initData {
if _, ok := foundInits[init.Name]; ok {
continue
}
sections = append(sections, &codegen.SectionTemplate{
Name: "server-type-init",
Source: typeInitT,
Data: init,
})
foundInits[init.Name] = struct{}{}
}
for _, data := range sd.validations {
if data.Kind == validateClient {
continue
}
sections = append(sections, &codegen.SectionTemplate{
Name: "server-validate",
Source: validateT,
Data: data,
})
}
for _, h := range sd.transformHelpers {
sections = append(sections, &codegen.SectionTemplate{
Name: "server-transform-helper",
Source: transformHelperT,
Data: h,
})
}
}
return &codegen.File{Path: fpath, SectionTemplates: sections}
}
// input: TransformFunctionData
const transformHelperT = `{{ printf "%s builds a value of type %s from a value of type %s." .Name .ResultTypeRef .ParamTypeRef | comment }}
func {{ .Name }}(v {{ .ParamTypeRef }}) {{ .ResultTypeRef }} {
{{ .Code }}
return res
}
`