sendToDeviceEncrypted method

Future<void> sendToDeviceEncrypted(
  1. List<DeviceKeys> deviceKeys,
  2. String eventType,
  3. Map<String, dynamic> message, {
  4. String? messageId,
  5. bool onlyVerified = false,
})

Sends an encrypted message of this eventType to these deviceKeys.

Implementation

Future<void> sendToDeviceEncrypted(
  List<DeviceKeys> deviceKeys,
  String eventType,
  Map<String, dynamic> message, {
  String? messageId,
  bool onlyVerified = false,
}) async {
  final encryption = this.encryption;
  if (!encryptionEnabled || encryption == null) return;
  // Don't send this message to blocked devices, and if specified onlyVerified
  // then only send it to verified devices
  if (deviceKeys.isNotEmpty) {
    deviceKeys.removeWhere((DeviceKeys deviceKeys) =>
        deviceKeys.blocked ||
        (deviceKeys.userId == userID && deviceKeys.deviceId == deviceID) ||
        (onlyVerified && !deviceKeys.verified));
    if (deviceKeys.isEmpty) return;
  }

  // So that we can guarantee order of encrypted to_device messages to be preserved we
  // must ensure that we don't attempt to encrypt multiple concurrent to_device messages
  // to the same device at the same time.
  // A failure to do so can result in edge-cases where encryption and sending order of
  // said to_device messages does not match up, resulting in an olm session corruption.
  // As we send to multiple devices at the same time, we may only proceed here if the lock for
  // *all* of them is freed and lock *all* of them while sending.

  try {
    await _sendToDeviceEncryptedLock.lock(deviceKeys);

    // Send with send-to-device messaging
    final data = await encryption.encryptToDeviceMessage(
      deviceKeys,
      eventType,
      message,
    );
    eventType = EventTypes.Encrypted;
    await sendToDevice(
        eventType, messageId ?? generateUniqueTransactionId(), data);
  } finally {
    _sendToDeviceEncryptedLock.unlock(deviceKeys);
  }
}