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}
2829type bbsGenerateHelper struct {}
2930
31+ var ignoredMessages []string = []string {"ProtoRoutes" }
32+ var ignoredEnums []string = []string {}
33+ var ignoredServices []string = []string {}
34+
3035var helper bbsGenerateHelperInterface = bbsGenerateHelper {}
3136
3237func 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+
3646func 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+
4156func 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+
697733func 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 ("\t Ignoring 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+ }
0 commit comments