Class: AceMQ::AMQP::ProtobufCodec
- Inherits:
-
Object
- Object
- AceMQ::AMQP::ProtobufCodec
- Defined in:
- lib/acemq/amqp/codec/protobuf.rb
Overview
Reads and writes Protocol Buffers.
For high volume, and for a contract shared with services in other languages. Messages are much smaller than JSON and parse faster, at the cost of being unreadable without the schema — which is the trade, not an oversight.
There is no codec without a message type, and there cannot be one
Protobuf bytes describe nothing about themselves. A reader must already hold the type the writer used, so this codec is built with one:
codec = ProtobufCodec.new(Acme::Order)
That asymmetry with JSONCodec, which needs no argument at all, is the
difference between the formats made visible rather than an awkwardness in
the API. It is also why protobuf is not a name Codecs knows: a name in
configuration cannot carry a class, and the Java library leaves it out of
its own registry for the same reason.
A codec reads one type. Protobuf will happily parse bytes meant for one
message as another where the field numbers overlap, giving a wrong answer
rather than an error, so a queue carrying two types wants two consumers or
a wrapper message with a oneof.
The gem
google-protobuf, required lazily and named when it is missing. The gem
declares no runtime dependencies, so a service publishing JSON is not made
to compile a protobuf runtime to do it.
Constant Summary collapse
- CONTENT_TYPE =
What this codec writes, and what Java, Go and .NET write.
"application/x-protobuf"- ALSO_READS =
Both spellings are in use, and Go also answers for Google's own.
["application/protobuf", "application/vnd.google.protobuf"].freeze
Instance Attribute Summary collapse
-
#message_class ⇒ Class
readonly
The message type this codec reads and writes.
Instance Method Summary collapse
-
#can_decode?(content_type) ⇒ Boolean
Accepts the two spellings of the protobuf media type, Google's own, and any +...+protobuf+ media type.
- #content_type ⇒ Object
- #decode(body) ⇒ Google::Protobuf::MessageExts
-
#encode(payload) ⇒ String
The bytes to publish.
-
#initialize(message_class) ⇒ ProtobufCodec
constructor
A new instance of ProtobufCodec.
Constructor Details
#initialize(message_class) ⇒ ProtobufCodec
Returns a new instance of ProtobufCodec.
62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/acemq/amqp/codec/protobuf.rb', line 62 def initialize() load_runtime! unless .is_a?(Class) && < Google::Protobuf::MessageExts raise ArgumentError, "#{.inspect} is not a class protoc generated. The protobuf " \ "codec reads one message type, and takes the class generated from your .proto." end @message_class = freeze end |
Instance Attribute Details
#message_class ⇒ Class (readonly)
The message type this codec reads and writes.
79 80 81 |
# File 'lib/acemq/amqp/codec/protobuf.rb', line 79 def @message_class end |
Instance Method Details
#can_decode?(content_type) ⇒ Boolean
Accepts the two spellings of the protobuf media type, Google's own, and any +...+protobuf+ media type.
Never a message whose sender set no content type. Protobuf bytes are not recognisable and parse quietly into nonsense more often than they fail, so a codec that volunteered would report that nonsense as a success.
110 111 112 113 114 115 |
# File 'lib/acemq/amqp/codec/protobuf.rb', line 110 def can_decode?(content_type) lower = content_type.to_s.downcase return false if lower.empty? lower.start_with?(CONTENT_TYPE, *ALSO_READS) || lower.include?("+protobuf") end |
#content_type ⇒ Object
74 |
# File 'lib/acemq/amqp/codec/protobuf.rb', line 74 def content_type = CONTENT_TYPE |
#decode(body) ⇒ Google::Protobuf::MessageExts
98 99 100 101 102 |
# File 'lib/acemq/amqp/codec/protobuf.rb', line 98 def decode(body) @message_class.decode(body.to_s.b) rescue Google::Protobuf::ParseError => e raise DecodeError, "this message is not a #{@message_class}: #{e.}" end |
#encode(payload) ⇒ String
Returns the bytes to publish.
84 85 86 87 88 89 90 91 92 93 |
# File 'lib/acemq/amqp/codec/protobuf.rb', line 84 def encode(payload) unless payload.is_a?(@message_class) raise EncodeError, "the protobuf codec writes #{@message_class} and was given a " \ "#{payload.class}. Publish the generated type, or use JSONCodec to have " \ "an ordinary object encoded." end @message_class.encode(payload) end |