Skip to content

Commit c5c11ef

Browse files
committed
codegen: create RPC service interface with gRPC & DRPC adapters
Define a shared `RPC<Service>Client` interface to wrap both gRPC's `<Service>Client` and DRPC's `DRPC<Service>Client`. Streaming methods will also return the common `RPC<Service>_<Method>Client`. Adds two simple adapters: - `NewGRPC<Service>ClientAdapter` - `NewDRPC<Service>ClientAdapter` They implement `RPC<Service>Client`, so we can swap clients at runtime via the cluster setting.
1 parent 3e0c530 commit c5c11ef

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

cmd/protoc-gen-go-drpc/main.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,28 @@ func (d *drpc) ClientIface(service *protogen.Service) string {
9292
return "DRPC" + service.GoName + "Client"
9393
}
9494

95+
func (d *drpc) RPCClientIface(service *protogen.Service) string {
96+
return "RPC" + service.GoName + "Client"
97+
}
98+
99+
func (d *drpc) GRPCClientAdapter(service *protogen.Service) string {
100+
return "grpc" + service.GoName + "ClientAdapter"
101+
}
102+
103+
func (d *drpc) DRPCClientAdapter(service *protogen.Service) string {
104+
return "drpc" + service.GoName + "ClientAdapter"
105+
}
106+
95107
func (d *drpc) ClientImpl(service *protogen.Service) string {
96108
return "drpc" + service.GoName + "Client"
97109
}
98110

111+
func unexport(s string) string { return strings.ToLower(s[:1]) + s[1:] }
112+
113+
func (d *drpc) GRPCClientImpl(service *protogen.Service) string {
114+
return unexport(service.GoName) + "Client"
115+
}
116+
99117
func (d *drpc) ServerIface(service *protogen.Service) string {
100118
return "DRPC" + service.GoName + "Server"
101119
}
@@ -323,6 +341,9 @@ func (d *drpc) generateService(service *protogen.Service) {
323341
for _, method := range service.Methods {
324342
d.generateServerMethod(method)
325343
}
344+
345+
d.generateServiceRPCInterfaces(service)
346+
d.generateServiceAdapters(service)
326347
}
327348

328349
//
@@ -595,3 +616,86 @@ func (d *drpc) generateRPCClientInterface(method *protogen.Method) {
595616
d.P("}")
596617
d.P()
597618
}
619+
620+
func (d *drpc) generateServiceRPCInterfaces(service *protogen.Service) {
621+
// Client interface
622+
d.P("type ", d.RPCClientIface(service), " interface {")
623+
d.P()
624+
for _, method := range service.Methods {
625+
d.P(d.generateRPCClientSignature(method))
626+
}
627+
d.P("}")
628+
d.P()
629+
}
630+
631+
func (d *drpc) generateRPCClientSignature(method *protogen.Method) string {
632+
reqArg := ", in *" + d.InputType(method)
633+
if method.Desc.IsStreamingClient() {
634+
reqArg = ""
635+
}
636+
respName := "*" + d.OutputType(method)
637+
if method.Desc.IsStreamingServer() || method.Desc.IsStreamingClient() {
638+
respName = d.ClientStreamRPCIface(method)
639+
}
640+
return fmt.Sprintf("%s(ctx %s%s) (%s, error)", method.GoName, d.Ident("context", "Context"), reqArg, respName)
641+
}
642+
func (d *drpc) generateServiceAdapters(service *protogen.Service) {
643+
d.generateGRPCAdapter(service)
644+
d.generateDRPCAdapter(service)
645+
}
646+
647+
func (d *drpc) generateGRPCAdapter(service *protogen.Service) {
648+
adapter := d.GRPCClientAdapter(service)
649+
grpcClientImpl := d.GRPCClientImpl(service)
650+
rpcIface := d.RPCClientIface(service)
651+
652+
d.P("// ", service.GoName, " gRPC -> RPC adapter")
653+
d.P("type ", adapter, " ", grpcClientImpl)
654+
d.P()
655+
d.P("func NewGRPC", service.GoName, "ClientAdapter(conn *", d.Ident("google.golang.org/grpc", "ClientConn"), ") ", rpcIface, " {")
656+
d.P("return (*", adapter, ")(&", grpcClientImpl, "{conn})")
657+
d.P("}")
658+
d.P()
659+
660+
for _, m := range service.Methods {
661+
d.P("func (a *", adapter, ") ", d.generateRPCClientSignature(m), " {")
662+
if m.Desc.IsStreamingClient() {
663+
d.P("return (*", grpcClientImpl, ")(a).", m.GoName, "(ctx)")
664+
} else {
665+
d.P("return (*", grpcClientImpl, ")(a).", m.GoName, "(ctx, in)")
666+
}
667+
d.P("}")
668+
d.P()
669+
}
670+
d.P("// compile-time assertion")
671+
d.P("var _ ", rpcIface, " = (*", adapter, ")(nil)")
672+
d.P()
673+
}
674+
675+
func (d *drpc) generateDRPCAdapter(service *protogen.Service) {
676+
adapter := d.DRPCClientAdapter(service)
677+
drpcClientImpl := d.ClientImpl(service)
678+
rpcIface := d.RPCClientIface(service)
679+
680+
d.P("// ", service.GoName, " DRPC -> RPC adapter")
681+
d.P("type ", adapter, " ", drpcClientImpl)
682+
d.P()
683+
d.P("func NewDRPC", service.GoName, "ClientAdapter(conn ", d.Ident("storj.io/drpc", "Conn"), ") ", rpcIface, " {")
684+
d.P("return (*", adapter, ")(&", drpcClientImpl, "{conn})")
685+
d.P("}")
686+
d.P()
687+
688+
for _, m := range service.Methods {
689+
d.P("func (a *", adapter, ") ", d.generateRPCClientSignature(m), " {")
690+
if m.Desc.IsStreamingClient() {
691+
d.P("return (*", drpcClientImpl, ")(a).", m.GoName, "(ctx)")
692+
} else {
693+
d.P("return (*", drpcClientImpl, ")(a).", m.GoName, "(ctx, in)")
694+
}
695+
d.P("}")
696+
d.P()
697+
}
698+
d.P("// compile-time assertion")
699+
d.P("var _ ", rpcIface, " = (*", adapter, ")(nil)")
700+
d.P()
701+
}
9.05 MB
Binary file not shown.

0 commit comments

Comments
 (0)