readMessage method

DBusMessage? readMessage()

Reads a D-Bus message from the buffer or returns null if not enough data.

Implementation

DBusMessage? readMessage() {
  Map<String,dynamic> jsonResult = {};

  var type;
  var serial;

  if (_responseData.startsWith("invoke:")) {
    // print("> readMessage ${_responseData}");
    jsonResult = json.decode(_responseData.substring("invoke:".length));
    serial = jsonResult['id']['serial'];

    if (jsonResult['result']!=null) {
      type = DBusMessageType.methodReturn;
    } else if (jsonResult['error']!=null) {
      type = DBusMessageType.error;
    }
    // print("> readMessage type: $type, jr: $jsonResult");
  } else if (_responseData.startsWith("addMatch:")) {
    if (jsonResult['result']!=null) {
      type = DBusMessageType.methodReturn;
    } else if (jsonResult['error']!=null) {
      type = DBusMessageType.error;
    }
    serial = jsonResult['id'];
    // print("> readMessage (addMatch) type: $type jr: ${_responseData}");
  } else if (_responseData.startsWith("signal:")) {
    type = DBusMessageType.signal;
    jsonResult = json.decode(_responseData.substring("signal:".length));
    serial = jsonResult['serial'];
    // print("> readMessage type $type, jr: $jsonResult");
  }

  // var type = {
  //   1: DBusMessageType.methodCall,
  //   2: DBusMessageType.methodReturn,
  //   3: DBusMessageType.error,
  //   4: DBusMessageType.signal
  // }[readDBusByte()!.value];

  if (type == null) {
    throw 'Invalid type received';
  }
  var flags = <DBusMessageFlag>{};
  if (jsonResult['flags']!=null) {
    var flagsValue = jsonResult['flags'];
    if (flagsValue & 0x01 != 0) {
      flags.add(DBusMessageFlag.noReplyExpected);
    }
    if (flagsValue & 0x02 != 0) {
      flags.add(DBusMessageFlag.noAutoStart);
    }
    if (flagsValue & 0x04 != 0) {
      flags.add(DBusMessageFlag.allowInteractiveAuthorization);
    }
  }

  DBusSignature? signature;
  DBusObjectPath? path;
  DBusInterfaceName? interface;
  DBusMemberName? member;
  DBusErrorName? errorName;
  int? replySerial;
  DBusBusName? destination;
  DBusBusName? sender;
  var fdCount = 0;

  if (jsonResult['path']!=null) {
    path = DBusObjectPath(jsonResult['path']);
  }
  if (jsonResult['interface']!=null) {
    interface = DBusInterfaceName(jsonResult['interface']);
  }
  if (jsonResult['member']!=null) {
    member = DBusMemberName(jsonResult['member']);
  }
  if (jsonResult['errorName']!=null) {
    errorName = DBusErrorName(jsonResult['errorName']);
  }
  if (jsonResult['destination']!=null) {
    destination = DBusBusName(jsonResult['destination']);
  }
  if (jsonResult['sender']!=null) {
    sender = DBusBusName(jsonResult['sender']);
    if (!(sender.value == 'org.freedesktop.DBus' || sender.isUnique)) {
      throw 'Sender contains non-unique bus name';
    }
  }

  var values = <DBusValue>[  ];
  var values_in_json  = null;

  if (type == DBusMessageType.methodReturn) {
    replySerial = jsonResult['id']['serial'];
    signature = DBusSignature(jsonResult['id']['signature']);
    values_in_json = jsonResult['result'];
  } else if (type == DBusMessageType.signal) {
    replySerial = jsonResult['id'];
    // it is possible to receive signal without signature
    // example:
    //  {"serial":5,"path":"/device","interface":"com.lgi.rdk.utils.fsmaintainer1","member":"ConfigurationSet","sender":":1.5059","type":4,"flags":1}
    // enforce empty signature for such case
    signature = DBusSignature(jsonResult['signature'] ?? '');
    values_in_json = jsonResult['body'];
  } else if (type == DBusMessageType.error) {
    replySerial = jsonResult['id']['serial'];
    // for (var i in jsonResult['error']) {
    //   print(">>>>");
    //   print("$i");
    //   print("${i.runtimeType}");
    // }
    errorName = DBusErrorName.fromJson(jsonResult['error'][0]);
  }
  // print("> readMessage: signature: $signature");

  if (signature != null) {
    if (values_in_json!=null) {
      values = readDBusValuesFromJson(signature, values_in_json);
    } else {
      // signal with empty signature has no "body", example:
      // signal:{"serial":12,"signature":"","path":"/com/lgi/rdk/application/netdiagnostics1","member":"ServiceStarted","interface":"com.lgi.rdk.application.netdiagnostics1","sender":":1.3623","type":4,"flags":1}
      // method return with empty signature has empty "result", example:
      // invoke:{"id":{"serial":2,"signature":""},"result":[]}
      if (type != DBusMessageType.signal) {
        throw 'Message has signature $signature but json body is null';
      } else if (signature.value.isNotEmpty) {
        throw 'Signal message has signature $signature but json body is null';
      }
    }
  } else {
    if (values_in_json!=null && values_in_json.length != 0) {
      throw 'Message has no signature but contains data items of length ${values_in_json.length}';
    }
  }

  return DBusMessage(type,
      flags: flags,
      serial: serial,
      path: path,
      interface: interface,
      member: member,
      errorName: errorName,
      replySerial: replySerial,
      destination: destination,
      sender: sender,
      values: values);
}