Go语言 如何在protoregistry中加载.proto文件

l0oc07j2  于 5个月前  发布在  Go
关注(0)|答案(2)|浏览(61)

我需要简单地直接将几个.proto文件的内容作为描述符加载,这样我就可以按照https://pkg.go.dev/google.golang.org/protobuf/reflect/protoregistry通过反射操作它们
据我所知,我需要
1.将文件的内容作为字符串加载。
1.使用prototext将字符串解组为descriptorpb.FileDescriptorProto
1.初始化ProtoFileDescriptor
1.最后,我可以在注册表中注册ProtoFileDescriptor。
我真的需要跳过所有这些环节吗,还是我完全错过了另一个API?

33qvvth1

33qvvth11#

如果有人问这个问题:

func registerProtoFile(src_dir string, filename string) error {
    // First, convert the .proto file to a file descriptor set
    tmp_file := filename + "tmp.pb"
    cmd := exec.Command("protoc", 
        "--descriptor_set_out=" + tmp_file, 
        "-I"+src_dir  
        path.Join(src_dir, filename))

    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    err := cmd.Run()
    if err != nil {
        return err
    }

    defer os.Remove(tmp_file)

    // Now load that temporary file as a file descriptor set protobuf
    protoFile, err := ioutil.ReadFile(tmp_file)
    if err != nil {
        return err
    }

    pb_set := new(descriptorpb.FileDescriptorSet)
    if err := proto.Unmarshal(protoFile, pb_set); err != nil {
        return err
    }

    // We know protoc was invoked with a single .proto file
    pb := pb_set.GetFile()[0]

    // Initialize the File descriptor object
    fd, err := protodesc.NewFile(pb, protoregistry.GlobalFiles)
    if err != nil {
        return err
    }

    // and finally register it.
    return protoregistry.GlobalFiles.RegisterFile(fd)
}

字符串

kuuvgm7e

kuuvgm7e2#

我一直在努力寻找一种方法来注册proto文件到protoregistry ,而不需要 * 使用主机上的protoc可执行文件。我在open policy agent中发现了这段代码,它使用bufbuild/protocompile(它将自己描述为“ github.com/jhump/protoreflect/desc/protoparse包的精神继承者 *”):
https://github.com/open-policy-agent/conftest/blob/68e075c067f82f415a070ce019554894a8228cf7/parser/textproto/textproto.go#L101
在我的例子中,我不仅想用protoregistry注册消息和类型,还想设置一个通用的服务处理程序,如gRPC GO Single Generic Service Handler中所描述的,所以我修改了一点开放策略代理代码:

func (s *server) registerServicesFromProtoFileDynamicpbNoProtoc(protoFileName string) error {

    // Skip this file if we already registered it.
    if _, err := protoregistry.GlobalFiles.FindFileByPath(protoFileName); err == nil {
        return nil
    }

    fh, err := os.Open(protoFileName)
    if err != nil {
        return fmt.Errorf("open file: %w", err)
    }
    defer fh.Close()

    handler := reporter.NewHandler(nil)
    node, err := parser.Parse(protoFileName, fh, handler)
    if err != nil {
        return fmt.Errorf("parse proto: %w", err)
    }

    res, err := parser.ResultFromAST(node, true, handler)
    if err != nil {
        return fmt.Errorf("convert from AST: %w", err)
    }

    fd, err := protodesc.NewFile(res.FileDescriptorProto(), protoregistry.GlobalFiles)
    if err != nil {
        return fmt.Errorf("convert to FileDescriptor: %w", err)
    }

    if err := protoregistry.GlobalFiles.RegisterFile(fd); err != nil {
        return fmt.Errorf("register file: %w", err)
    }

    for i := 0; i < fd.Messages().Len(); i++ {
        msg := fd.Messages().Get(i)
        if err := protoregistry.GlobalTypes.RegisterMessage(dynamicpb.NewMessageType(msg)); err != nil {
            return fmt.Errorf("register message %q: %w", msg.FullName(), err)
        }
    }
    for i := 0; i < fd.Extensions().Len(); i++ {
        ext := fd.Extensions().Get(i)
        if err := protoregistry.GlobalTypes.RegisterExtension(dynamicpb.NewExtensionType(ext)); err != nil {
            return fmt.Errorf("register extension %q: %w", ext.FullName(), err)
        }
    }

    for svcNum := 0; svcNum < fd.Services().Len(); svcNum++ {
        svc := fd.Services().Get(svcNum)
        serviceName := string(svc.FullName())
        s.sdMap2[serviceName] = svc
        gsd := grpc.ServiceDesc{ServiceName: serviceName, HandlerType: (*interface{})(nil)}
        for methodNum := 0; methodNum < svc.Methods().Len(); methodNum++ {
            m := svc.Methods().Get(methodNum)
            gsd.Methods = append(gsd.Methods, grpc.MethodDesc{MethodName: string(m.Name()), Handler: s.GenericHandler})
        }
        s.grpcServer.RegisterService(&gsd, s)
    }

    return nil
}

字符串
我的server struct也是从上面的通用服务处理程序帖子修改的:

type server struct {
    tunnel.UnimplementedRequestTunnelServer
    sdMap                  map[string]*desc.ServiceDescriptor         // this uses the github.com/jhump/protoreflect/desc package that I didn't want to use
    sdMap2                 map[string]protoreflect.ServiceDescriptor  // Instead, I use the official protoreflect package
    grpcServer             *grpc.Server
}

相关问题