Hi everyone,

Since protobufs are used quite a bit in network protocols, I'm looking for 
some advice requiring extensible protocol definitions using protos. Me nor 
any of my colleagues have used them for this purpose, so trying to avoid 
blunders. The other end of the connection is a mobile device using 
protobuf-lite, so I'm not using "Any" fields that don't have library 
support on the lite version. The use case is pushing various types of 
messages to a mobile device and back over WebSocket or UDP without really 
having to concern over transport level issues.

I'm leaving out the authentication part of the protocol, since it's not 
relevant here. There are some key requirements:

1. It should be possible to ack messages (to support e.g. delivery 
callbacks and return errors).

2. It should be easy to add new payload types as well as remove old ones 
that are obsolete.

3. The protocol needs to be versioned and the server might need to handle 
old clients.

It would also help if types are chosen in a way that makes parsing quick 
without sacrificing ease of use and extensibility, since the server fleet 
will handle millions of concurrent users.

With these requirements in place, a somewhat simplified protocol definition 
with a payload type invented for this question would be:

    syntax = "proto3";
    package protocol;
    
    import "google/protobuf/timestamp.proto";
    
    // Basic protocol
    
    enum Platform {
      PLATFORM_UNSPECIFIED = 0;
      PLATFORM_ANDROID = 1;
      PLATFORM_IOS = 2;
    }
    
    enum MessageKind {
      MESSAGE_KIND_UNSPECIFIED = 0;
      MESSAGE_KIND_STATUS = 1;
      MESSAGE_KIND_NOTIFICATION = 2;
      // ... and others
    }
    
    enum StatusCode {
      STATUS_CODE_UNSPECIFIED = 0;
      STATUS_CODE_OK = 1;
      STATUS_CODE_PERMISSION_DENIED = 2;
      STATUS_CODE_INTERNAL_ERROR = 3;
    }
    
    // Every message written onto the wire is of this type.
    message ProtocolMessage {
      int32 version = 1;
      int32 sequence_number = 2;
    
      MessageKind kind = 3; // Indicates protobuf type encoded in 'data' 
field.
      bytes data = 4; // Serialized protobuf.
    }
    
    message Status {
      int32 sequence_number = 1;
      StatusCode code = 2;
      string error_string = 3;
    }
    
    // Notification payload
    
    message NotificationMessage {
      google.protobuf.Timestamp issued_at = 1;
      google.protobuf.Timestamp expiration = 2;
      google.protobuf.Timestamp not_before = 3;
    
      oneof kind {
        Promotion promotion = 4;
        PurchaseCompleted purchase = 5;
        // ... and others
      }
    }

Any comments or improvement ideas? Does oneof make good sense here for fast 
parsing and extensibility/deprecation? Does it make sense to e.g. group 
various parts of the messages and choose field numbers from a specific 
range for each group? For example, in "NotificationMessage" would it make 
sense to start the field numbers in the oneof at e.g. 100 to make room for 
adding more fields before that? Of course, nothing forces to write the 
fields in the protobuf definition in increasing numerical order. I remember 
having seen this done in some protos back in the day when I worked at 
Google.

I'm planning on phasing out fields by prepending "deprecated_" to fields 
that will be removed and then prepend the field name with "OBSOLETE_" once 
it's not in use anywhere.

Interested if someone has any lessons learned from using protobufs in 
network protocols and improvement ideas to make the design more future 
proof.

Best,
Edvard

-- 
You received this message because you are subscribed to the Google Groups 
"Protocol Buffers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/protobuf/66772256-2f20-4bb2-941f-0b88363a102fn%40googlegroups.com.

Reply via email to