Skip to content

Commit 12466ec

Browse files
committed
WIP: grpc gen changes
1 parent 7c3a58d commit 12466ec

File tree

2 files changed

+235
-4
lines changed

2 files changed

+235
-4
lines changed

protoc-gen-go-bbs/bbs.go

Lines changed: 231 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,31 @@ type bbsGenerateHelperInterface interface {
2727
}
2828
type bbsGenerateHelper struct{}
2929

30+
var ignoredMessages []string = []string{"ProtoRoutes"}
31+
var ignoredEnums []string = []string{}
32+
var ignoredServices []string = []string{}
33+
3034
var helper bbsGenerateHelperInterface = bbsGenerateHelper{}
3135

3236
func getUnsafeName(g *protogen.GeneratedFile, ident protogen.GoIdent) string {
3337
return g.QualifiedGoIdent(ident)
3438
}
3539

40+
func getUnsafeNameFromString(name string) string {
41+
unsafeName := name
42+
return unsafeName
43+
}
44+
3645
func getCopysafeName(g *protogen.GeneratedFile, ident protogen.GoIdent) (string, bool) {
3746
unsafeName := getUnsafeName(g, ident)
3847
return strings.CutPrefix(unsafeName, *prefix)
3948
}
4049

50+
func getCopysafeNameFromString(name string) (string, bool) {
51+
unsafeName := getUnsafeNameFromString(name)
52+
return strings.CutPrefix(unsafeName, *prefix)
53+
}
54+
4155
func getFieldName(goName string) string {
4256
result := goName
4357
return result
@@ -694,6 +708,27 @@ func generateFile(plugin *protogen.Plugin, file *protogen.File) *protogen.Genera
694708
return g
695709
}
696710

711+
func generateRpcFile(plugin *protogen.Plugin, file *protogen.File) *protogen.GeneratedFile {
712+
filename := file.GeneratedFilenamePrefix + "_bbs_grpc.pb.go"
713+
g := plugin.NewGeneratedFile(filename, file.GoImportPath)
714+
g.P("// Code generated by protoc-gen-go-bbs. DO NOT EDIT.")
715+
g.P("// versions:")
716+
g.P("// - protoc-gen-go-bbs v", version) // version from main.go
717+
g.P("// - protoc-gen-go-grpc ", "TODO: get version")
718+
g.P("// - protoc ", protocVersion(plugin))
719+
720+
if file.Proto.GetOptions().GetDeprecated() {
721+
g.P("// ", file.Desc.Path(), " is a deprecated file.")
722+
} else {
723+
g.P("// source: ", file.Desc.Path())
724+
}
725+
g.P()
726+
g.P("package ", file.GoPackageName)
727+
g.P()
728+
generateRpcFileContent(file, g)
729+
return g
730+
}
731+
697732
func protocVersion(plugin *protogen.Plugin) string {
698733
v := plugin.Request.GetCompilerVersion()
699734
if v == nil {
@@ -706,10 +741,7 @@ func protocVersion(plugin *protogen.Plugin) string {
706741
return fmt.Sprintf("v%d.%d.%d%s", v.GetMajor(), v.GetMinor(), v.GetPatch(), suffix)
707742
}
708743

709-
var ignoredMessages []string = []string{"ProtoRoutes"}
710-
var ignoredEnums []string = []string{}
711-
712-
func generateFileContent(file *protogen.File, g *protogen.GeneratedFile) {
744+
func generateFileEnums(file *protogen.File, g *protogen.GeneratedFile) {
713745
for _, eNuM := range file.Enums {
714746
if *debug {
715747
log.Printf("New Enum Detected: %+v\n\n", eNuM)
@@ -722,7 +754,9 @@ func generateFileContent(file *protogen.File, g *protogen.GeneratedFile) {
722754

723755
helper.genGlobalEnum(g, eNuM)
724756
}
757+
}
725758

759+
func generateFileMessages(file *protogen.File, g *protogen.GeneratedFile) {
726760
for _, msg := range file.Messages {
727761
if *debug {
728762
log.Printf("New Message Detected: %+v\n\n", msg)
@@ -740,3 +774,196 @@ func generateFileContent(file *protogen.File, g *protogen.GeneratedFile) {
740774
helper.genFromProtoSliceMethod(g, msg)
741775
}
742776
}
777+
778+
func generateFileServices(file *protogen.File, g *protogen.GeneratedFile) {
779+
for _, svc := range file.Services {
780+
if *debug {
781+
log.Printf("New Service Detected: %+v\n\n", svc)
782+
}
783+
784+
//if slices.Contains(ignoredMessages, getUnsafeName(g, svc.GoIdent)) {
785+
if slices.Contains(ignoredMessages, svc.GoName) {
786+
log.Printf("\tIgnoring message %s", svc.Desc.Name())
787+
continue
788+
}
789+
790+
genImports(g)
791+
genClient(g, svc)
792+
genServer(g, svc)
793+
genServiceDesc(file, g, svc)
794+
}
795+
}
796+
797+
func genImports(g *protogen.GeneratedFile) {
798+
importBuilder := new(strings.Builder)
799+
importT, err := template.New("import").Parse(
800+
`
801+
import (
802+
context "context"
803+
grpc "google.golang.org/grpc"
804+
codes "google.golang.org/grpc/codes"
805+
status "google.golang.org/grpc/status"
806+
)
807+
808+
// This is a compile-time assertion to ensure that this generated file
809+
// is compatible with the grpc package it is being compiled against.
810+
// Requires gRPC-Go v1.64.0 or later.
811+
const _ = grpc.SupportPackageIsVersion9
812+
`)
813+
if err != nil {
814+
panic(err)
815+
}
816+
importT.Execute(importBuilder, nil)
817+
g.P(importBuilder.String())
818+
819+
}
820+
821+
func genClient(g *protogen.GeneratedFile, svc *protogen.Service) {
822+
823+
clientT, err := template.New("client").Parse(
824+
`
825+
type {{.ServiceName}}Client interface {
826+
{{.ClientInterfaceMethods}} // build these
827+
}
828+
829+
type {{.ServiceName | LowerFirst}} struct { // pass funcmap to get LowerFirst
830+
cc grpc.ClientConnInterface
831+
}
832+
833+
func New{{.ServiceName}}Client(cc grpc.ClientConnInterface) {{.ServiceName}}Client {
834+
return &{{.ServiceName | LowerFirst}}Client{cc}
835+
}
836+
837+
{{.ClientMethods}}
838+
`)
839+
if err != nil {
840+
panic(err)
841+
}
842+
}
843+
844+
func genServer(g *protogen.GeneratedFile, svc *protogen.Service) {
845+
serverBuilder := new(strings.Builder)
846+
serverT, err := template.New("server").Parse(
847+
`
848+
type {{.ServiceName}}Server interface {
849+
{{.ServerInterfaceMethods}} // build these
850+
mustEmbedUnimplemented{{.ServiceName}}Server()
851+
}
852+
853+
// Unimplemented{{.ServiceName}Server must be embedded to have
854+
// forward compatible implementations.
855+
//
856+
// NOTE: this should be embedded by value instead of pointer to avoid a nil
857+
// pointer dereference when methods are called.
858+
type Unimplemented{{.ServiceName}}Server struct {}
859+
860+
{{.UnimplementedServerMethods}} // build these
861+
func (Unimplemented{{.ServiceName}}Server) mustEmbedUnimplemented{{.ServiceName}}Server() {}
862+
func (Unimplemented{{.ServiceName}}Server) testEmbeddedByValue() {}
863+
864+
// Unsafe{{.ServiceName}}Server may be embedded to opt out of forward compatibility for this service.
865+
// Use of this interface is not recommended, as added methods to {{.ServiceName}}Server will
866+
// result in compilation errors.
867+
868+
func Register{{.ServiceName}}Server(s grpc.ServiceRegistrar, srv LocketServer) {
869+
// If the following call panics, it indicates Unimplemented{{.ServiceName}}Server was
870+
// embedded by pointer and is nil. This will cause panics if an
871+
// unimplemented method is ever invoked, so we test this at initialization
872+
// time to prevent it from happening at runtime later due to I/O.
873+
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
874+
t.testEmbeddedByValue()
875+
}
876+
s.RegisterService(&{{.ServiceName}}_ServiceDesc, srv)
877+
}
878+
879+
{{.ServerMethods}}
880+
`)
881+
if err != nil {
882+
panic(err)
883+
}
884+
885+
serverT.Execute(serverBuilder, nil)
886+
}
887+
888+
type Service struct {
889+
Name string
890+
Source string
891+
}
892+
893+
type ServiceDescData struct {
894+
ServiceName string
895+
Methods string
896+
SourceFilename string
897+
}
898+
899+
type MethodData struct {
900+
ServiceName string
901+
MethodName string
902+
}
903+
904+
func genServiceDesc(file *protogen.File, g *protogen.GeneratedFile, svc *protogen.Service) {
905+
sourceFilename := file.Desc.Path()
906+
907+
if serviceName, ok := getCopysafeNameFromString(svc.GoName); ok {
908+
methodsBuilder := new(strings.Builder)
909+
methodT, err := template.New("method").Parse(
910+
`
911+
{
912+
MethodName: "{{.MethodName}}",
913+
Handler: _{{.ServiceName}}_{{.MethodName}}_Handler,
914+
}`)
915+
if err != nil {
916+
panic(err)
917+
}
918+
919+
methodsBuilder.WriteString("Methods: []grpc.MethodDesc{")
920+
for i, method := range svc.Methods {
921+
methodName, _ := getCopysafeNameFromString(method.GoName)
922+
methodT.Execute(methodsBuilder,
923+
MethodData{
924+
ServiceName: serviceName,
925+
MethodName: methodName,
926+
})
927+
if i < len(svc.Methods)-1 {
928+
methodsBuilder.WriteRune(',')
929+
}
930+
}
931+
methodsBuilder.WriteString("}")
932+
methods := methodsBuilder.String()
933+
934+
serviceDescBuilder := new(strings.Builder)
935+
serviceDescT, err := template.New("serviceDesc").Parse(
936+
`
937+
// {{.ServiceName}}_ServiceDesc is the grpc.ServiceDesc for {{.ServiceName}} service.
938+
// It's only intended for direct use with grpc.RegisterService,
939+
// and not to be introspected or modified (even as a copy)
940+
var {{.ServiceName}}_ServiceDesc = grpc.ServiceDesc{
941+
ServiceName: "models.{{.ServiceName}}",
942+
HandlerType: (*{{.ServiceName}}Server)(nil),
943+
{{.Methods}},
944+
Streams: []grpc.StreamDesc{},
945+
Metadata: "{{.SourceFilename}}",
946+
}
947+
`)
948+
if err != nil {
949+
panic(err)
950+
}
951+
serviceDescT.Execute(serviceDescBuilder,
952+
ServiceDescData{
953+
ServiceName: serviceName,
954+
Methods: methods,
955+
SourceFilename: sourceFilename,
956+
})
957+
g.P(serviceDescBuilder.String())
958+
959+
}
960+
}
961+
962+
func generateFileContent(file *protogen.File, g *protogen.GeneratedFile) {
963+
generateFileEnums(file, g)
964+
generateFileMessages(file, g)
965+
}
966+
967+
func generateRpcFileContent(file *protogen.File, g *protogen.GeneratedFile) {
968+
generateFileServices(file, g)
969+
}

protoc-gen-go-bbs/main.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ func main() {
4242
log.Printf("Generating %s\n", file.Desc.Path())
4343

4444
generateFile(plugin, file)
45+
if len(file.Services) > 0 {
46+
generateRpcFile(plugin, file)
47+
}
48+
4549
}
4650
return nil
4751
})

0 commit comments

Comments
 (0)