1 // Copyright (c) 2020 Cisco and/or its affiliates.
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:
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
23 // generated service names
25 serviceApiName = "RPCService" // name for the RPC service interface
26 serviceImplName = "serviceClient" // name for the RPC service implementation
27 serviceClientName = "ServiceClient" // name for the RPC service client
29 // TODO: register service descriptor
30 //serviceDescType = "ServiceDesc" // name for service descriptor type
31 //serviceDescName = "_ServiceRPC_serviceDesc" // name for service descriptor var
34 func generateFileRPC(ctx *GenFile, w io.Writer) {
35 logf("----------------------------")
36 logf("generating RPC file package: %q", ctx.file.PackageName)
37 logf("----------------------------")
39 // generate file header
40 fmt.Fprintln(w, "// Code generated by GoVPP's binapi-generator. DO NOT EDIT.")
43 // generate package header
44 fmt.Fprintf(w, "package %s\n", ctx.file.PackageName)
48 fmt.Fprintln(w, "import (")
49 fmt.Fprintln(w, ` "context"`)
50 fmt.Fprintln(w, ` "io"`)
52 fmt.Fprintf(w, "\tapi \"%s\"\n", "git.fd.io/govpp.git/api")
56 // generate RPC service
57 if ctx.file.Service != nil && len(ctx.file.Service.RPCs) > 0 {
58 generateService(ctx, w, ctx.file.Service)
61 // generate message registrations
62 /*fmt.Fprintln(w, "var _RPCService_desc = api.RPCDesc{")
67 // generate import refs
68 fmt.Fprintf(w, "// Reference imports to suppress errors if they are not otherwise used.\n")
69 fmt.Fprintf(w, "var _ = api.RegisterMessage\n")
70 fmt.Fprintf(w, "var _ = context.Background\n")
71 fmt.Fprintf(w, "var _ = io.Copy\n")
75 func generateService(ctx *GenFile, w io.Writer, svc *Service) {
76 // generate services comment
77 generateComment(ctx, w, serviceApiName, "services", "service")
79 // generate service api
80 fmt.Fprintf(w, "type %s interface {\n", serviceApiName)
81 for _, rpc := range svc.RPCs {
82 generateRPCMethod(ctx, w, &rpc)
88 // generate client implementation
89 fmt.Fprintf(w, "type %s struct {\n", serviceImplName)
90 fmt.Fprintf(w, "\tch api.Channel\n")
94 // generate client constructor
95 fmt.Fprintf(w, "func New%s(ch api.Channel) %s {\n", serviceClientName, serviceApiName)
96 fmt.Fprintf(w, "\treturn &%s{ch}\n", serviceImplName)
100 for _, rpc := range svc.RPCs {
101 method := camelCaseName(rpc.RequestMsg)
102 if m := strings.TrimSuffix(method, "Dump"); method != m {
106 fmt.Fprintf(w, "func (c *%s) ", serviceImplName)
107 generateRPCMethod(ctx, w, &rpc)
108 fmt.Fprintln(w, " {")
110 streamImpl := fmt.Sprintf("%s_%sClient", serviceImplName, method)
111 fmt.Fprintf(w, "\tstream := c.ch.SendMultiRequest(in)\n")
112 fmt.Fprintf(w, "\tx := &%s{stream}\n", streamImpl)
113 fmt.Fprintf(w, "\treturn x, nil\n")
114 } else if replyTyp := camelCaseName(rpc.ReplyMsg); replyTyp != "" {
115 fmt.Fprintf(w, "\tout := new(%s)\n", replyTyp)
116 fmt.Fprintf(w, "\terr:= c.ch.SendRequest(in).ReceiveReply(out)\n")
117 fmt.Fprintf(w, "\tif err != nil { return nil, err }\n")
118 fmt.Fprintf(w, "\treturn out, nil\n")
120 fmt.Fprintf(w, "\tc.ch.SendRequest(in)\n")
121 fmt.Fprintf(w, "\treturn nil\n")
127 replyTyp := camelCaseName(rpc.ReplyMsg)
128 method := camelCaseName(rpc.RequestMsg)
129 if m := strings.TrimSuffix(method, "Dump"); method != m {
132 streamApi := fmt.Sprintf("%s_%sClient", serviceApiName, method)
134 fmt.Fprintf(w, "type %s interface {\n", streamApi)
135 fmt.Fprintf(w, "\tRecv() (*%s, error)\n", replyTyp)
139 streamImpl := fmt.Sprintf("%s_%sClient", serviceImplName, method)
140 fmt.Fprintf(w, "type %s struct {\n", streamImpl)
141 fmt.Fprintf(w, "\tapi.MultiRequestCtx\n")
145 fmt.Fprintf(w, "func (c *%s) Recv() (*%s, error) {\n", streamImpl, replyTyp)
146 fmt.Fprintf(w, "\tm := new(%s)\n", replyTyp)
147 fmt.Fprintf(w, "\tstop, err := c.MultiRequestCtx.ReceiveReply(m)\n")
148 fmt.Fprintf(w, "\tif err != nil { return nil, err }\n")
149 fmt.Fprintf(w, "\tif stop { return nil, io.EOF }\n")
150 fmt.Fprintf(w, "\treturn m, nil\n")
156 // TODO: generate service descriptor
157 /*fmt.Fprintf(w, "var %s = api.%s{\n", serviceDescName, serviceDescType)
158 fmt.Fprintf(w, "\tServiceName: \"%s\",\n", ctx.moduleName)
159 fmt.Fprintf(w, "\tHandlerType: (*%s)(nil),\n", serviceApiName)
160 fmt.Fprintf(w, "\tMethods: []api.MethodDesc{\n")
161 for _, method := range rpcs {
162 fmt.Fprintf(w, "\t {\n")
163 fmt.Fprintf(w, "\t MethodName: \"%s\",\n", method.Name)
164 fmt.Fprintf(w, "\t },\n")
166 fmt.Fprintf(w, "\t},\n")
167 //fmt.Fprintf(w, "\tCompatibility: %s,\n", messageCrcName)
168 //fmt.Fprintf(w, "\tMetadata: reflect.TypeOf((*%s)(nil)).Elem().PkgPath(),\n", serviceApiName)
169 fmt.Fprintf(w, "\tMetadata: \"%s\",\n", ctx.inputFile)
170 fmt.Fprintln(w, "}")*/
175 func generateRPCMethod(ctx *GenFile, w io.Writer, rpc *RPC) {
176 reqTyp := camelCaseName(rpc.RequestMsg)
178 logf(" writing RPC: %+v", reqTyp)
180 // method name is same as parameter type name by default
183 // use Dump as prefix instead of suffix for stream services
184 if m := strings.TrimSuffix(method, "Dump"); method != m {
189 params := fmt.Sprintf("in *%s", reqTyp)
192 if replyType := camelCaseName(rpc.ReplyMsg); replyType != "" {
195 replyTyp = fmt.Sprintf("%s_%sClient", serviceApiName, method)
197 replyTyp = fmt.Sprintf("*%s", replyType)
199 returns = fmt.Sprintf("(%s, error)", replyTyp)
202 fmt.Fprintf(w, "\t%s(ctx context.Context, %s) %s", method, params, returns)