Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Background

Protocol

We've been writing a new client-server protocol as a public API for the creation of new Geode clients. We settled on using Protobuf as the encoding for the protocol as it allows a user not to think about a lot of the encoding details, which makes writing clients significantly easier.

...

The first approach was to use the JSON-PDX conversion that is already used for the REST API. Many languages have libraries to encode objects as JSON, but this has downsides, among them being slow.

Proposal

Regardless of proposal, we should allow users to have a pluggable object encoding that they can register a handler with on the server. This encoder will receive a byte array and return an Object. This allows users to do custom serialization if desired.

...

Code Block
titleProtobuf "struct"
linenumberstrue
collapsetrue
message Struct {
  string typeName = 1;
  repeated StructEntry entries = 2;

}
message StructEntry {
  string fieldName = 1;
  oneof value {
    int32 intField = 2;
    int64 longField = 3;
    int32 shortField = 4;
    byte byteField = 5;
    bool booleanField = 6;
    double doubleField = 7;
    float floatField = 8;
    bytes binaryField = 9;
    string stringField = 10;
    google.protobuf.NullValue nullField = 11;
    // Field serialized using a custom serialization format. This can only be used if
    // A HandshakeRequest is sent with valueFormat set to a valid format.
    //
    // See HandshakeRequest.valueFormat.
    bytes customObjectField = 12;
  }
}

 

The typeName field can be used for other clients to recognize the same type. Internally, it will be stored in the PDXInstance that this is converted to, but that detail shouldn't need to be exposed to the user.

...

Code Block
titleProtobuf Type registration
linenumberstrue
collapsetrue
message TypeRegistrationRequest {
  ValueTypeDefinition typeDefinition = 1;
}
message TypeRegistrationResponse {
  int typeID = 1;
}

message ValueTypeDefinition {
  string typeName = 1;
  repeated ValueTypeFieldDefinition definition = 2;
}
message ValueTypeFieldDefinition {
  string fieldName = 1;
  enum fieldTypeFieldType {
    intField;
    longField;
    shortField;
    byteField;
    booleanField;
    doubleField;
    floatField;
    binaryField;
    stringField;
    // no JSON?  string jsonObjectField;}
  FieldType fieldType // Field serialized using a custom serialization format. This can only be used if
    // A HandshakeRequest is sent with valueFormat set to a valid format.
    //
    // See HandshakeRequest.valueFormat.
    customObjectField;
  }
= 2;
 }

and for sending values:

Code Block
languagetext
titleProtobut Values
linenumberstrue
collapsetrue
message Value {
  int typeID = 1;
  repeated ValueField field = 2;
}
message ValueField = {
  oneof value {
    int32 intField = 1;
    int64 longField = 2;
    int32 shortField = 3;
    byte byteField = 4;
    bool booleanField = 5;
    double doubleField = 6;
    float floatField = 7;
    bytes binaryField = 8;
    string stringField = 9;
    google.protobuf.NullValue nullField = 11;
    // Field serialized using a custom serialization format. This can only be used if
    // A HandshakeRequest is sent with valueFormat set to a valid format.
    //
    // See HandshakeRequest.valueFormat.
    bytes customObjectField = 12;
  }
}

The client sends a registration request, and the server can determine the typeID.

...

This way a client can implement logic to find the correct type and deserialize the value.

Considerations

A driver developer may wish to provide a way for users to register types before sending values.

Client developers will have to make sure that types they want to use in different language clients can be correlated.