Skip to content

Writing messages

Vid Klopcic edited this page Oct 24, 2020 · 2 revisions

Messages must be defined in .proto files under the proto directory. Filenames must be the same as the package names!

Writing messages

Options

Custom message options are defined in the /* ... */ comment immediately before the message definition. If the option is only relevant for the client, the parameter is prefixed with client keyword. COMMON OPTIONS

  • type = '<value>' - specifies the type of the message
  • origin = client or origin = server - tells the generator whether to make a Tx or Rx class

CLIENT OPTIONS

  • client cache = <dart Duration params> - tells for how long the message should be kept in the cache. Specified values are mapped as such: Duration(days: {days}, hours: {hours}, minutes: {minutes}, seconds: {seconds}). You can also combine multiple values by separating them with whitespace (eg. client cache = years(10) days(120)
    • days(<val>)
    • hours(<val>)
    • minutes(<val>)
    • seconds(<val>)
  • client cache_keys = <cache keys> - specified cache keys are directly mapped to the first level message data. They form a cacheUuid which determines whether a message gets overwritten or added to the cache. They are also stored in a separate columns in the SQL database, so it is possible to make custom SQL queries on them. There can be no more than 5 keys of each type!
    • real('key1', 'key2', ...) - enum is also a real key
    • text('key1', 'key2', ...)
    • date('key1', 'key2', ...)

TxMessage OPTIONS

  • auth = false - auth header won't be set if set to false (true by default)

Example

A typical message definition consists of a comment with message options and the message definition.

/*
type = 'dynamic-field-value'
origin = server
client cache = days(30)
client cache_keys = text('uuid') real('bundle_index', 'form_instance_id', 'free_index')
 */
message DynamicFieldValue {
  string uuid = 1;
  DynamicFieldValueData value = 2;
  int32 bundle_index = 3;
  int32 form_instance_id = 4;
  int32 bundle_id = 5;
  int64 time_modified = 6;
  int32 free_index = 7;
  bool deleted = 8;
}

Because the origin is server, a Rx class will be generated. If there are any cache_keys, a corresponding CacheKeys class will be generated as well.

class RxDynamicFieldValueCacheKeys extends CacheKeys {
  CacheKey uuid = CacheKey(CacheKeyType.text, 0, 'uuid');
  CacheKey bundleIndex = CacheKey(CacheKeyType.real, 0, 'bundleIndex');
  CacheKey formInstanceId = CacheKey(CacheKeyType.real, 1, 'formInstanceId');
  CacheKey freeIndex = CacheKey(CacheKeyType.real, 2, 'freeIndex');

  RxDynamicFieldValueCacheKeys() : super(textKeys: ['uuid'], realKeys: ['bundleIndex', 'formInstanceId', 'freeIndex'], dateKeys: []);
}

class RxDynamicFieldValue extends SocketRxMessage {
  static const String type = 'dynamic-field-value';
  final DynamicFieldValue data = DynamicFieldValue();
  Duration cache = Duration(days: 30, hours: 0, minutes: 0, seconds: 0);
  final RxDynamicFieldValueCacheKeys cacheKeys = RxDynamicFieldValueCacheKeys();

  RxDynamicFieldValue([SocketRxMessageData message]) : super(type, message);

  @override
  RxDynamicFieldValue fromMessage(SocketRxMessageData message) => RxDynamicFieldValue(message);
}

Generating messages

To generate the messages, you need to call the fps_proto_gen_dart command (if not in path, it exists in the flutter_persistent_socket/utils folder). All .proto files under the proto directory will be included by default. If you wish to include proto files from other projects, you can specify them in the fps_config.json file under the project root as such:

{
  "protos": [
    "/path/to/other_project/proto"
  ]
}

Dart class templates

Here are the templates for the generated Dart classes used:

CACHE_KEYS_CLASS = '''
class {prefix}{proto}CacheKeys extends CacheKeys {{
  {fields}

  {prefix}{proto}CacheKeys() : super(textKeys: [{text_keys}], realKeys: [{real_keys}], dateKeys: [{date_keys}]);
}}'''

RX_MESSAGE_CLASS = '''class Rx{proto} extends SocketRxMessage {{
  static const String type = '{type}';
  final {proto} data = {proto}();
  {fields}

  Rx{proto}([SocketRxMessageData message]) : super(type, message);

  @override
  Rx{proto} fromMessage(SocketRxMessageData message) => Rx{proto}(message);
}}
'''

TX_MESSAGE_CLASS = '''

class Tx{proto} extends SocketTxMessage {{
  static const String type = '{type}';
  final {proto} proto;

  const Tx{proto}([this.proto]) : super(type, authRequired: {auth}, cache: {cache});
  
  static {proto} get newProto => {proto}();
}}
'''
Clone this wiki locally