1

I'm using ScalaPB for my protobuf compiler which generates Scala case classes, parsers and serializers for my protocol buffers.

I have a simple protobuf message in a .proto file that has been compiled to a Scala case class thanks to ScalaPB.

option java_outer_classname = "MovementProtos";

message Move {
    required string direction = 1;
    required string mode = 2;
}

This file is compiled and allows me to do something like:

val move = Move(direction = "up", mode = "walk")

I have an Akka actor handling a TCP connection.

class PacketHandler extends Actor {

  def receive: Receive = {
    case m: Move =>
      // successfully matched against Move case class message
    case Tcp.Received(data) =>
      // didn't match any messages
    case _: Tcp.ConnectionClosed =>
      context.stop(self)
  }
}

If I send a Move protobuf message to my PacketHandler, will it successfully match against my Move case class with how I've wrote my receive?

How do I send a Move protobuf message? Let's say when it successfully matches against a Move protobuf message it echoes it back.

def receive: Receive = {
  case m: Move =>
    // successfully matched against Move case class message
    // now echo back 'm' over the wire
    sender ! Tcp.Write(???)
  ...
}

I have no client to test my PacketHandler actor so I've been using telnet.

It would also be useful to know what the encoded Move message looks like exactly so I can create my connection over telnet and send the encoded message over the wire and test whether it gets decoded when it reaches PacketHandler.

kliew
  • 3,073
  • 1
  • 14
  • 25
Edward Maxedon
  • 1,151
  • 2
  • 11
  • 17

1 Answers1

1

One way is to send instances as Akka messages. ie. sender ! Tcp.Write(m). The instances are sent with all the binary overhead of a Scala class. But that sort of defeats the point of using protocol buffers.

Bandwidth is usually one of the scarcest/slowest resources in a system so typically you would use the protobuf serialization and deserialization functions for rpc. You serialize using any of the to~ functions (ie. toByteString) and deserialize using parseFrom.

kliew
  • 3,073
  • 1
  • 14
  • 25
  • Unfortunately, sending Scala case classes are not an option for me... The serialize using toByteString is what I was looking for in terms of sending encoded data. Will I be able to match against incoming messages? For instance, parseFrom expects to deserialize given a certain type. What if I don't necessarily know what type of message is coming through? – Edward Maxedon Mar 29 '16 at 04:48
  • You should have one endpoint with URI for each message type. Otherwise you could wrap every message in a parent message (with a common type) that indicates the message type in a string and the actual message in a byte field, and have your single endpoint deserialize the parent message and then deserialize the wrapped message based on the message-type-string. protobuf does not automatically detect the message type. – kliew Mar 29 '16 at 13:41
  • Another solution is to define a general message with only one field. All other message types must have this same field type (enum or string probably) with the same tag number, and the value should indicate the specific message type. First you would deserialize the received message using the general-message-type. Then based on the value of the single field, deserialize again using the indicated message type. – kliew Mar 30 '16 at 04:53
  • 1
    Actually I've decided to use the 'oneof' feature introduced in protobuf v2.6+. This way I use a parent message that has 'oneof' a child message. The problem now is that I haven't been able to find any examples of how to use this functionality. I'm getting there though... – Edward Maxedon Mar 30 '16 at 19:57
  • I'm wondering actually if you'll be able to clarify use of the `oneof` feature... I've posted a new question [here](http://stackoverflow.com/questions/36319162/how-to-serialize-deserialize-a-protobuf-message-that-uses-oneof-with-scalapb). For your consideration... – Edward Maxedon Mar 30 '16 at 20:40