2

I am trying to consume a protobuf message from RMQ on node js. The protobuf message was created with protobuf-net on C#.Net

So for example the c# object looks like this:

    [ProtoContract]
    public class PositionOpenNotification : MessageBase
    {
    [ProtoMember(1)]
    public int PositionID { get; set; }

    [ProtoMember(2)]
    public int InstrumentID { get; set; }
    ..
    ..Down to tag 30

Then it is added to RMQ and we have .net listeners with the same object on the other side to decode it.

But now we want to read the message from nodejs. For this I am using amqplib and protobuf-js on the nodejs side.

I was trying to decode the message using an object with decorators like this:

import { Message, Type, Field } from "protobufjs/light"; 
 
 @Type.d("PositionOpenNotification")
 export class PositionOpenNotification extends Message<PositionOpenNotification> {
 
  @Field.d(1,"int32", "required")
  public PositionID: number;
}

And Decoding like this:

ch.consume(q.queue, function(msg, res) {
            try {
                if(msg.content) {
                    let decoded = PositionOpenNotification.decode( msg.content);
                    console.log(" Received %s", decoded,q.queue);
                }
              } catch (e) {
                 console.log("Error  %s ", e.message)
              }
        }

where ch is the amqplib RMQ channel.

But I always get one of these errors:

invalid wire type 7 at offset 2

invalid wire type 4 at offset 2

invalid wire type 6 at offset 2

index out of range: 237 + 10 > 237

etc

What am I doing wrong?

EDIT:

It looks like I did not take into account the fact that MessageBase(abstract which PositionOpenNotification inherits) is also a ProtoContract and that the data was serialized with length prefix.

So in the end this is what worked:

Add a MessageBase object with the PositionOpenNotification object in it:

@Type.d("MessageBase")
export class MessageBase extends Message<MessageBase> {

  @Field.d(108, PositionOpenNotification)
  public positionOpenNotification: PositionOpenNotification;
}

And then when deserialzing it:

 if(msg.content) {
    var reader = Reader.create(msg.content);
    let decoded = MessageBase.decodeDelimited(reader);
 }
Mithir
  • 2,355
  • 2
  • 25
  • 37

1 Answers1

2

Wire type 7 doesn't exist, so: the error is correct, at least.

This type of error is usually an indicator that the payload has been corrupted in transit. The most common way of doing this is by treating it as text, and / or (something that is seen very very frequently): running it through an encoding backwards to transmit the binary data over a text protocol. Check that you're not doing this. Basically, you need to get the exact same bytes at both ends; until you have that, nothing else will work. In particular, if you need to transmit binary over a text protocol: base-64 is your friend.

As a side note: protobuf-net has methods to export the .proto schema for your object model, to make x-plat more convenient. Look for Serializer.GetProto<T>.

If you have a payload that you are not sure about, you can use https://protogen.marcgravell.com/decode to validate and inspect the binary data.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • So if there are already .net readers for this message on the same RMQ using EasyNetQ, the only difference is that I'm using amqplib to read the message on nodejs... So I thought that the Buffer I am getting is equivalent to the byte array on .net. So either it is not equivalent (but why? it is not a text protocol) or my object is incorrect. – Mithir Jun 23 '20 at 05:07
  • Now I see that the .net readers are actually deserializing with Serializer.DeserializeWithLengthPrefix(stream, PrefixStyle.Base128) and the equivalent for that is decodeDelimited on protobufjs but there is no PrefixStyle indication and it still fails... – Mithir Jun 23 '20 at 07:50
  • I also did GetProto but still had the described issue (also needed to remove default for guids because of illegal value '00000000-0000-0000-0000-000000000000' error) – Mithir Jun 23 '20 at 11:27
  • 1
    @Mithir any chance I can see some payload hex here? it would make it much easier to offer guidance – Marc Gravell Jun 23 '20 at 11:35
  • I just found a way to make it work... I've put the PositionOpenNotification as a subtype on MessageBase object and it worked, I'll edit the question with the answer. Thanks for your help!! – Mithir Jun 23 '20 at 11:41
  • Marc - When loading the generated proto file the decoding did not work but with the solution I wrote in the Question it did work. Does this make sense to you? – Mithir Jun 23 '20 at 12:52
  • 1
    @Mithir I'm not sure what your current setup is - it keeps changing. Very hard to comment without a very clear scenario. Sorry, but the details matter. – Marc Gravell Jun 23 '20 at 13:16