open method

Future<void> open(
  1. MessageEventModel event
)

Opens a message event, decrypting it if it is for this peer and updating the peer's local conversation and message tables.

Implementation

Future<void> open(MessageEventModel event) async {
  final MessageEventModel(:body, :hash, :timestamp) = event;

  if (!body.peers.contains(TailscaleClient.instance.peerPublicKey)) {
    return;
  }

  final device = await _db.devices.id(event.deviceKey).get();
  if (device == null) {
    _logger.log('Missing device for $hash');
    return;
  }

  final peerKey = device.peerKey;
  if (!body.peers.contains(peerKey)) {
    _logger.log('Peer not included in message $hash');
    return;
  }

  final secretKey = await openSecretKey(event);
  if (secretKey == null) {
    _logger.log('Unable to open message secret key for $hash');
    return;
  }

  final decryptedPayload = await _encryption.decryptSecret(
    secretKey,
    event.body.payload,
  );

  final conversationKey = ConversationModel.getKey(body.peers);
  final message = MessageModel.fromPayload(
    MessagePayloadModel.fromJson(jsonDecode(decryptedPayload)),
    peerKey: peerKey,
    hash: hash,
    deviceKey: event.deviceKey,
    sentAt: timestamp,
    conversationKey: conversationKey,
    attachments: body.attachments
        .map((media) => MessageNetworkMediaModel.fromMedia(hash, media))
        .toList(),
  );

  final conversation = await _db.conversations.id(conversationKey).get();
  if (conversation == null) {
    await _db.conversations.initialize(
      ConversationModel.getKey(body.peers),
      timestamp: event.timestamp,
      text: message.displayText,
      lastMessageAuthorKey: message.peerKey,
    );
  } else if (conversation.lastMessageAt case DateTime? lastMessageAt
      when lastMessageAt == null || timestamp.isAfter(lastMessageAt)) {
    await _db.conversations.update(
      conversationKey,
      lastMessageAt: timestamp,
      lastMessagePreview: message.displayText,
      lastMessageAuthorKey: message.peerKey,
    );
  }

  switch (message) {
    case CanvasMessageModel canvasMessage:
      await _db.canvases.upsert(
        CanvasModel(
          canvasId: canvasMessage.canvasId,
          conversationKey: conversationKey,
        ),
      );
      break;
    case TextMessageModel():
      if (!event.isCurrentDevice) {
        await _createReceipt(event, MessageReceiptStatus.delivered);
      }
      break;
    default:
      break;
  }

  await _db.messages.insert(message);
}