sendNow method

  1. @override
Future<Message> sendNow(
  1. Message msg, {
  2. ChatSilentNotification notification = const ChatSilentNotification(),
  3. VerifyToSendMessage? verifyToSend,
  4. OnDeniedToSendMessage? onDeniedToSend,
})
override

Direct send without queue check. Used by createMessage for online path and by drainOfflineQueue for queued messages.

Implementation

@override
Future<Message> sendNow(
  Message msg, {
  ChatSilentNotification notification = const ChatSilentNotification(),
  VerifyToSendMessage? verifyToSend,
  OnDeniedToSendMessage? onDeniedToSend,
}) async {
  final failed = msg.copyWith(status: MessageStatus.failed);
  if (me.isEmpty || msg.isEmpty) return failed;

  final target = room(msg.roomId);
  if (verifyToSend != null && !verifyToSend(target)) {
    onDeniedToSend?.call(target);
    return msg;
  }

  final body = msg.lastMessage();
  final optimistic = target.copyWith(
    lastMessage: body,
    lastMessageId: msg.id,
    lastMessageSenderId: me,
    lastMessageDeleted: false,
    updatedAt: ChatValueTimestamp.now(),
  );

  try {
    put(optimistic);

    final uploaded = await _replace(msg);
    if (uploaded.isEmpty) {
      put(target);
      _trackFailed(msg, notification, verifyToSend, onDeniedToSend);
      return failed;
    }

    final sent = uploaded.copyWith(status: MessageStatus.sent);
    final normalizedMsg = n.normalize(sent.source, n.message);

    await RetryHelper.run(
      operation: () =>
          messageDelegate.create(msg.roomId, msg.id, normalizedMsg),
      onRetry: (attempt, error) {
        managerOrNull(
          msg.roomId,
        )?.put(uploaded.copyWith(status: MessageStatus.retrying));
        errorReporter.report(
          error,
          source: 'MessageMixin.sendNow.retry',
          context: {
            'roomId': msg.roomId,
            'msgId': msg.id,
            'attempt': attempt,
            'phase': 'create',
          },
        );
      },
    );

    await RetryHelper.run(
      operation: () => roomDelegate.update(
        msg.roomId,
        n.normalize(
          _roomMessageUpdatePayload(target, msg.id, body),
          n.room,
        ),
      ),
      onRetry: (attempt, error) {
        errorReporter.report(
          error,
          source: 'MessageMixin.sendNow.retry',
          context: {
            'roomId': msg.roomId,
            'msgId': msg.id,
            'attempt': attempt,
            'phase': 'roomUpdate',
          },
        );
      },
    );

    await sendNotification(msg, notification);

    _failedMessages.remove(msg.id);

    return sent;
  } catch (e, st) {
    errorReporter.report(
      e,
      stackTrace: st,
      source: 'MessageMixin.sendNow',
      context: {'roomId': msg.roomId, 'msgId': msg.id, 'type': msg.type.name},
    );
    put(target);
    _trackFailed(msg, notification, verifyToSend, onDeniedToSend);
    return failed;
  }
}