@@ -27,17 +27,31 @@ type bbsGenerateHelperInterface interface {
2727}
2828type bbsGenerateHelper struct {}
2929
30+ var ignoredMessages []string = []string {"ProtoRoutes" }
31+ var ignoredEnums []string = []string {}
32+ var ignoredServices []string = []string {}
33+
3034var helper bbsGenerateHelperInterface = bbsGenerateHelper {}
3135
3236func 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+
3645func 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+
4155func 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+
697732func 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 ("\t Ignoring 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+ }
0 commit comments