Skip to content

Commit c60c742

Browse files
committed
Base grpc generation
1 parent 7c3a58d commit c60c742

File tree

3 files changed

+356
-4
lines changed

3 files changed

+356
-4
lines changed

protoc-gen-go-bbs/bbs.go

Lines changed: 212 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"slices"
77
"strings"
88
"text/template"
9+
"unicode"
910

1011
"google.golang.org/protobuf/compiler/protogen"
1112
"google.golang.org/protobuf/proto"
@@ -27,17 +28,31 @@ type bbsGenerateHelperInterface interface {
2728
}
2829
type bbsGenerateHelper struct{}
2930

31+
var ignoredMessages []string = []string{"ProtoRoutes"}
32+
var ignoredEnums []string = []string{}
33+
var ignoredServices []string = []string{}
34+
3035
var helper bbsGenerateHelperInterface = bbsGenerateHelper{}
3136

3237
func getUnsafeName(g *protogen.GeneratedFile, ident protogen.GoIdent) string {
3338
return g.QualifiedGoIdent(ident)
3439
}
3540

41+
func getUnsafeNameFromString(name protoreflect.Name) string {
42+
unsafeName := name
43+
return string(unsafeName)
44+
}
45+
3646
func getCopysafeName(g *protogen.GeneratedFile, ident protogen.GoIdent) (string, bool) {
3747
unsafeName := getUnsafeName(g, ident)
3848
return strings.CutPrefix(unsafeName, *prefix)
3949
}
4050

51+
func getCopysafeNameFromString(name protoreflect.Name) (string, bool) {
52+
unsafeName := getUnsafeNameFromString(name)
53+
return strings.CutPrefix(unsafeName, *prefix)
54+
}
55+
4156
func getFieldName(goName string) string {
4257
result := goName
4358
return result
@@ -694,6 +709,27 @@ func generateFile(plugin *protogen.Plugin, file *protogen.File) *protogen.Genera
694709
return g
695710
}
696711

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

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

723756
helper.genGlobalEnum(g, eNuM)
724757
}
758+
}
725759

760+
func generateFileMessages(file *protogen.File, g *protogen.GeneratedFile) {
726761
for _, msg := range file.Messages {
727762
if *debug {
728763
log.Printf("New Message Detected: %+v\n\n", msg)
@@ -740,3 +775,176 @@ func generateFileContent(file *protogen.File, g *protogen.GeneratedFile) {
740775
helper.genFromProtoSliceMethod(g, msg)
741776
}
742777
}
778+
779+
var currentService Service
780+
781+
func generateFileServices(file *protogen.File, g *protogen.GeneratedFile) {
782+
for _, svc := range file.Services {
783+
if *debug {
784+
log.Printf("New Service Detected: %+v\n\n", svc)
785+
}
786+
787+
if slices.Contains(ignoredServices, svc.GoName) {
788+
log.Printf("\tIgnoring service %s", svc.Desc.Name())
789+
continue
790+
}
791+
792+
if serviceName, ok := getCopysafeNameFromString(svc.Desc.Name()); ok {
793+
sourceFilename := file.Desc.Path()
794+
currentService = Service{Name: serviceName, Source: sourceFilename}
795+
796+
genImports(g)
797+
genClient(g, svc)
798+
genServer(g, svc)
799+
genServiceDesc(g, svc)
800+
}
801+
}
802+
}
803+
804+
var funcMap template.FuncMap = template.FuncMap{
805+
"LowerFirst": lowerFirst,
806+
}
807+
808+
func lowerFirst(s string) string {
809+
if len(s) == 0 {
810+
return s
811+
}
812+
813+
runes := []rune(s)
814+
runes[0] = unicode.ToLower(runes[0])
815+
return string(runes)
816+
}
817+
818+
func genImports(g *protogen.GeneratedFile) {
819+
importBuilder := new(strings.Builder)
820+
importT, err := template.New("import").Funcs(funcMap).Parse(grpcImports)
821+
if err != nil {
822+
panic(err)
823+
}
824+
importT.Execute(importBuilder, nil)
825+
g.P(importBuilder.String())
826+
827+
}
828+
829+
func genClient(g *protogen.GeneratedFile, svc *protogen.Service) {
830+
clientMethodNames := genMethodTemplate(svc, clientMethodName, false)
831+
clientInterfaceMethods := genMethodTemplate(svc, clientInterfaceMethod, false)
832+
clientMethods := genMethodTemplate(svc, clientMethod, false)
833+
clientBuilder := new(strings.Builder)
834+
835+
clientT, err := template.New("client").Funcs(funcMap).Parse(grpcClient)
836+
if err != nil {
837+
panic(err)
838+
}
839+
clientT.Execute(clientBuilder,
840+
Client{
841+
Service: currentService,
842+
ClientInterfaceMethods: clientInterfaceMethods,
843+
ClientMethodNames: clientMethodNames,
844+
ClientMethods: clientMethods,
845+
})
846+
g.P(clientBuilder.String())
847+
}
848+
849+
func genServer(g *protogen.GeneratedFile, svc *protogen.Service) {
850+
unimplementedServerMethods := genMethodTemplate(svc, unimplementedServerMethod, false)
851+
serverInterfaceMethods := genMethodTemplate(svc, serverInterfaceMethod, false)
852+
serverHandlers := genMethodTemplate(svc, serverHandler, false)
853+
854+
serverBuilder := new(strings.Builder)
855+
serverT, err := template.New("server").Funcs(funcMap).Parse(grpcServer)
856+
if err != nil {
857+
panic(err)
858+
}
859+
860+
serverT.Execute(serverBuilder,
861+
Server{
862+
Service: currentService,
863+
ServerHandlers: serverHandlers,
864+
ServerInterfaceMethods: serverInterfaceMethods,
865+
UnimplementedServerMethods: unimplementedServerMethods,
866+
})
867+
g.P(serverBuilder.String())
868+
}
869+
870+
func genMethodTemplate(svc *protogen.Service, methodTemplate string, addComma bool) string {
871+
builder := new(strings.Builder)
872+
methodT, err := template.New("method-template").Funcs(funcMap).Parse(methodTemplate)
873+
if err != nil {
874+
panic(err)
875+
}
876+
877+
for i, method := range svc.Methods {
878+
methodName, _ := getCopysafeNameFromString(method.Desc.Name())
879+
methodT.Execute(builder,
880+
Method{
881+
Service: currentService,
882+
MethodName: methodName,
883+
})
884+
if addComma {
885+
if i < len(svc.Methods)-1 {
886+
builder.WriteRune(',')
887+
}
888+
}
889+
}
890+
return builder.String()
891+
}
892+
893+
type Service struct {
894+
Name string
895+
Source string
896+
}
897+
898+
type Client struct {
899+
ClientInterfaceMethods string
900+
ClientMethodNames string
901+
ClientMethods string
902+
Service Service
903+
}
904+
905+
type Server struct {
906+
ServerInterfaceMethods string
907+
ServerHandlers string
908+
Service Service
909+
UnimplementedServerMethods string
910+
}
911+
912+
type ServiceDescData struct {
913+
Methods string
914+
Service Service
915+
}
916+
917+
type Method struct {
918+
MethodName string
919+
Service Service
920+
}
921+
922+
func genServiceDesc(g *protogen.GeneratedFile, svc *protogen.Service) {
923+
methodsBuilder := new(strings.Builder)
924+
methodsBuilder.WriteString("Methods: []grpc.MethodDesc{")
925+
serviceDescMethods := genMethodTemplate(svc, grpcMethodDesc, true)
926+
methodsBuilder.WriteString(serviceDescMethods)
927+
methodsBuilder.WriteString("}")
928+
methods := methodsBuilder.String()
929+
930+
serviceDescBuilder := new(strings.Builder)
931+
serviceDescT, err := template.New("serviceDesc").Parse(grpcServiceDescription)
932+
if err != nil {
933+
panic(err)
934+
}
935+
serviceDescT.Execute(serviceDescBuilder,
936+
ServiceDescData{
937+
Service: currentService,
938+
Methods: methods,
939+
})
940+
g.P(serviceDescBuilder.String())
941+
}
942+
943+
func generateFileContent(file *protogen.File, g *protogen.GeneratedFile) {
944+
generateFileEnums(file, g)
945+
generateFileMessages(file, g)
946+
}
947+
948+
func generateRpcFileContent(file *protogen.File, g *protogen.GeneratedFile) {
949+
generateFileServices(file, g)
950+
}

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)