如何解析协议缓冲区消息并创建 JSON 数据?

huangapple go评论78阅读模式
英文:

How to parse protocol buffer message and create json out of it?

问题

这是我的最小.proto文件:

syntax = "proto3";

message getDhtParams {}

message DhtContents {
    string dht_contents=1;
}

service MyApp {
    rpc getDhtContent(getDhtParams) returns (DhtContents) {}
}

与上述.proto文件相关的两个要点:

  1. 这是一个最小化的文件,实际上还有更多内容。
  2. 服务器已经生成并正在运行,服务器是用Python实现的。

我正在用Go编写客户端。以下是我编写的获取代码:

func fetchDht() (*pb.DhtContents, error) {
	// Set up a connection to the server.
	address := "localhost:9998"
	conn, err := grpc.Dial(address, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()

	client := pb.NewMyAppClient(conn)

	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	r, err := client.GetDhtContent(ctx, &pb.GetDhtParams{})

	if err != nil {
		return nil, errors.New("could not get dht contents")
	}
	return r, nil
}

为了简单起见,我简化了输出,但输出看起来类似于这样:

dht_contents:"{'node_ids': ['dgxydhlqoopevxv'], 'peer_addrs': [['192.168.1.154', '41457']], 'peer_meta': [{'peer_id': {'nodeID': 'dgxydhlqoopevxv', 'key': 'kdlvjdictuvgxspwkdizqryr', 'mid': 'isocvavbtzkxeigkkrubzkcx', 'public_key': 'uhapwxnfeqqmnojsaijghhic', '_address': 'xklqlebqngpkxb'}, 'ip_addrs': ['192.168.1.154', '41457'], 'services': [{'service_input': '', 'service_output': '', 'price': 0}], 'timestamp': 1661319968}]}"

关于此响应的几个要点:

  1. 它以 dht_contents: 开头,我知道这是 DhtContents 消息的一个字段。
  2. 这可能是服务器端的问题;在这种情况下,我将通知服务开发人员。但是,封闭的JSON不是有效的JSON,因为它使用了单引号。

我的问题:

  1. 处理 dht_contents 的优雅方法是什么?一定有protobuf/grpc的方法。我希望获取双引号之间的内容。
  2. 如何将内容转换为JSON?我已经创建了用于解组的结构。

如果我能将类型为 *pb.DhtContents 的响应转换为 []byte,那就足够了,从那里我可以将其转换为JSON。

英文:

Here is my minimal .proto file:

syntax = "proto3";

message getDhtParams {}

message DhtContents {
    string dht_contents=1;
}

service MyApp {
    rpc getDhtContent(getDhtParams) returns (DhtContents) {}
}

Two things to note related to the above proto file:

  1. It is a minimal file. There is a lot more to it.
  2. The server is already generated and running. The server is implemented in Python.

I am writing client in Go. And this is the fetching code I have come up with:

func fetchDht() (*pb.DhtContents, error) {
	// Set up a connection to the server.
	address := "localhost:9998"
	conn, err := grpc.Dial(address, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()

	client := pb.NewMyAppClient(conn)

	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	r, err := client.GetDhtContent(ctx, &pb.GetDhtParams{})

	if err != nil {
		return nil, errors.New("could not get dht contents")
	}
	return r, nil
}

For sake of simplicity, I have tripped down the output, but the output looks something like this:

dht_contents:"{'node_ids': ['dgxydhlqoopevxv'], 'peer_addrs': [['192.168.1.154', '41457']], 'peer_meta': [{'peer_id': {'nodeID': 'dgxydhlqoopevxv', 'key': 'kdlvjdictuvgxspwkdizqryr', 'mid': 'isocvavbtzkxeigkkrubzkcx', 'public_key': 'uhapwxnfeqqmnojsaijghhic', '_address': 'xklqlebqngpkxb'}, 'ip_addrs': ['192.168.1.154', '41457'], 'services': [{'service_input': '', 'service_output': '', 'price': 0}], 'timestamp': 1661319968}]}"

A few things to note about this response:

  1. It starts with dht_contents: which I know is a field of DhtContents message.
  2. This could be an issue from the server side; in that case I will inform the service developer. But the json enclosed is not a valid JSON as it uses single quotes.

My questions:

  1. What is an elegant way to deal with that dht_contents? There must be the protobuf/grpc way. I aim to get the contents between double quotes.
  2. How do I convert the content to JSON? I have already created the struct to unmarshal.

It would be enough if I am also able to convert the response which is of type *pb.DhtContents to []byte, from there I can convert it to JSON.

答案1

得分: 0

生成的代码应该有一个方法,该方法将从开头删除dht_contents:",并从末尾删除"

在你的情况下,该方法应该被称为GetDhtContents()

你可以修改你的fetchDht函数,像这样:

func fetchDht() (string, error) {
    address := "localhost:9998"
    // ...
    if err != nil {
        return nil, errors.New("could not get dht contents")
    }
    return r.GetDhtContents(), nil
}

从那里开始,你可以通过将单引号替换为双引号来使其成为有效的 JSON。或者这个处理可以在服务端处理。

英文:
  1. The generated code should have a method which will get rid of dht_contents:" from the start and " from the end.

In your case, that method should be called GetDhtContents().

You can modify your fetchDht function to something like this:

func fetchDht() (string, error) {
    address := "localhost:9998"
    // ...
    if err != nil {
        return nil, errors.New("could not get dht contents")
    }
    return r.GetDhtContents(), nil
}
  1. From there on, you can work on making it a valid JSON by replacing single quotes to double quotes. Or it may be handled on the service end.

答案2

得分: 0

  1. 通过proto文件生成的方法可以从结果("r")中获取内容,然后使用r.Get...,你可以获取到内容。
  2. 将字符串转换为你想要的类型。
    建议:
  3. 将proto类型更改为字节(bytes)。
  4. 然后使用json.Unmarshal([r.Get...],[dst])进行转换。
英文:
  1. there is the methods generated by proto file to get the content from the result(the "r"), then use r.Get..., you could get the content.
  2. convert string to the type you want.
    suggest:
  3. change proto type to bytes
  4. then json.Unmarshal([r.Get...],[dst])

huangapple
  • 本文由 发表于 2022年8月24日 16:31:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/73469887.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定