代码之家  ›  专栏  ›  技术社区  ›  s4eed

将protobuf对象哈希为字符串,作为redis数据库的键

  •  0
  • s4eed  · 技术社区  · 3 年前

    我有一个复杂的protobuf对象。这是一个发送到我的GRPC端点的请求。如果我以前没有,我只想处理它。所以我想把对象散列成一些字符串,并将其存储在我的Redis数据库中。我曾经 ObjectHash-Proto 但在protobuf编译器的新版本中,我遇到了以下错误:

    got an unexpected struct of type 'impl.MessageState' for field {Name:state PkgPath:... Type:impl.MessageState Tag: Offset:0 Index:[0] Anonymous:false}
    

    它似乎不支持结构,新版本的protobuf编译器生成一个包含结构的代码。

    我无法为每个请求生成某种ID。ID实际上是整个对象的散列。

    0 回复  |  直到 3 年前
        1
  •  1
  •   Jean-François Fabre    3 年前

    Proto序列化是不稳定的,因此不能依靠对输出进行编组和散列来为同一消息生成相同的散列。

    从…起 https://developers.google.com/protocol-buffers/docs/reference/go/faq#hash

    如何使用协议缓冲区消息作为哈希键?

    您需要规范化序列化,协议缓冲区消息的封送输出保证随时间稳定。不幸的是,目前还没有规范化序列化的规范。你需要自己写,或者想办法避免需要。

    我能找到的最接近的解决办法是 deepmind objecthash-proto 但在过去的4年里没有捐款,所以我认为它可能已经过时了

        2
  •  2
  •   Zombo tliff    3 年前

    如果你有 proto.Message [1] ,则可以免费获得封送处理函数[2]。 因此,在封送消息之后,只需将字节传递给 base64 md5 或者任何你想要的:

    package main
    
    import (
       "encoding/base64"
       "google.golang.org/protobuf/proto"
       "google.golang.org/protobuf/types/known/structpb"
    )
    
    func hash(m proto.Message) (string, error) {
       b, err := proto.Marshal(m)
       if err != nil {
          return "", err
       }
       return base64.StdEncoding.EncodeToString(b), nil
    }
    
    func main() {
       m, err := structpb.NewStruct(map[string]interface{}{
          "month": 12, "day": 31,
       })
       if err != nil {
          panic(err)
       }
       s, err := hash(m)
       if err != nil {
          panic(err)
       }
       println(s) // ChIKBW1vbnRoEgkRAAAAAAAAKEAKEAoDZGF5EgkRAAAAAAAAP0A=
    }
    
    1. https://godocs.io/google.golang.org/protobuf/proto#Message
    2. https://godocs.io/google.golang.org/protobuf/proto#Marshal