increased logging again
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run

This commit is contained in:
otsmr 2026-05-28 12:41:10 +02:00
parent 0c32b41dd0
commit 62457f1f48
3 changed files with 78 additions and 98 deletions

View file

@ -153,18 +153,25 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
); );
final groupIds = entry.value; final groupIds = entry.value;
await (delete(messages)..where( final deletedCount =
(m) => await (delete(messages)..where(
m.groupId.isIn(groupIds) & (m) =>
((m.mediaStored.equals(true) & m.groupId.isIn(groupIds) &
m.isDeletedFromSender.equals(true)) | ((m.mediaStored.equals(true) &
m.mediaStored.equals(false)) & m.isDeletedFromSender.equals(true)) |
// Only remove the message when ALL members have seen it. Otherwise the receipt will also be deleted which could cause issues in case a member opens the image later.. m.mediaStored.equals(false)) &
(m.openedByAll.isSmallerThanValue(deletionTime) | // Only remove the message when ALL members have seen it. Otherwise the receipt will also be deleted which could cause issues in case a member opens the image later..
(m.isDeletedFromSender.equals(true) & (m.openedByAll.isSmallerThanValue(deletionTime) |
m.createdAt.isSmallerThanValue(deletionTime))), (m.isDeletedFromSender.equals(true) &
)) m.createdAt.isSmallerThanValue(deletionTime))),
.go(); ))
.go();
if (deletedCount > 0) {
Log.info(
'Deleted $deletedCount messages for groups $groupIds due to retention policy.',
);
}
} }
} }
@ -266,30 +273,48 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
actionTimestamp = msg.createdAt; actionTimestamp = msg.createdAt;
} }
await into(messageActions).insertOnConflictUpdate( final ts = actionTimestamp;
MessageActionsCompanion( await transaction(() async {
messageId: Value(messageId), await into(messageActions).insertOnConflictUpdate(
contactId: contactId, MessageActionsCompanion(
type: const Value(MessageActionType.openedAt), messageId: Value(messageId),
actionAt: Value(actionTimestamp), contactId: contactId,
), type: const Value(MessageActionType.openedAt),
); actionAt: Value(ts),
),
);
final isOpenedByAll = await haveAllMembers(
messageId,
MessageActionType.openedAt,
);
await (update(
messages,
)..where((tbl) => tbl.messageId.equals(messageId))).write(
MessagesCompanion(
openedAt: Value(ts),
openedByAll: Value(isOpenedByAll ? ts : null),
),
);
});
// Read-back verification: confirm the write was persisted.
final verified = await getMessageById(messageId).getSingleOrNull();
if (verified != null && verified.openedAt == null) {
Log.warn(
'handleMessagesOpened read-back failed for $messageId, retrying',
);
await (update(
messages,
)..where((tbl) => tbl.messageId.equals(messageId))).write(
MessagesCompanion(
openedAt: Value(actionTimestamp),
),
);
}
final isOpenedByAll = await haveAllMembers(
messageId,
MessageActionType.openedAt,
);
final rowsUpdated =
await (update(
messages,
)..where((tbl) => tbl.messageId.equals(messageId))).write(
MessagesCompanion(
openedAt: Value(actionTimestamp),
openedByAll: Value(isOpenedByAll ? actionTimestamp : null),
),
);
Log.info( Log.info(
'handleMessagesOpened updated $rowsUpdated rows for message $messageId', 'handleMessagesOpened completed for message $messageId',
); );
} catch (e) { } catch (e) {
Log.error('handleMessagesOpened failed for $messageId: $e'); Log.error('handleMessagesOpened failed for $messageId: $e');
@ -302,18 +327,20 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
String messageId, String messageId,
DateTime timestamp, DateTime timestamp,
) async { ) async {
await into(messageActions).insertOnConflictUpdate( await transaction(() async {
MessageActionsCompanion( await into(messageActions).insertOnConflictUpdate(
messageId: Value(messageId), MessageActionsCompanion(
contactId: Value(contactId), messageId: Value(messageId),
type: const Value(MessageActionType.ackByServerAt), contactId: Value(contactId),
actionAt: Value(timestamp), type: const Value(MessageActionType.ackByServerAt),
), actionAt: Value(timestamp),
); ),
await twonlyDB.messagesDao.updateMessageId( );
messageId, await twonlyDB.messagesDao.updateMessageId(
MessagesCompanion(ackByServer: Value(timestamp)), messageId,
); MessagesCompanion(ackByServer: Value(timestamp)),
);
});
} }
Future<bool> haveAllMembers( Future<bool> haveAllMembers(
@ -347,18 +374,20 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
String messageId, String messageId,
MessagesCompanion updatedValues, MessagesCompanion updatedValues,
) async { ) async {
await (update( final count = await (update(
messages, messages,
)..where((c) => c.messageId.equals(messageId))).write(updatedValues); )..where((c) => c.messageId.equals(messageId))).write(updatedValues);
Log.info('Updated $count message(s) with messageId $messageId');
} }
Future<void> updateMessagesByMediaId( Future<void> updateMessagesByMediaId(
String mediaId, String mediaId,
MessagesCompanion updatedValues, MessagesCompanion updatedValues,
) { ) async {
return (update( final count = await (update(
messages, messages,
)..where((c) => c.mediaId.equals(mediaId))).write(updatedValues); )..where((c) => c.mediaId.equals(mediaId))).write(updatedValues);
Log.info('Updated $count message(s) with mediaId $mediaId');
} }
Future<Message?> insertMessage(MessagesCompanion message) async { Future<Message?> insertMessage(MessagesCompanion message) async {

View file

@ -1,4 +1,3 @@
import 'package:clock/clock.dart';
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:drift_flutter/drift_flutter.dart' import 'package:drift_flutter/drift_flutter.dart'
show DriftNativeOptions, driftDatabase; show DriftNativeOptions, driftDatabase;
@ -246,38 +245,4 @@ class TwonlyDB extends _$TwonlyDB {
Log.info('Table: $tableName, Size: $tableSize bytes'); Log.info('Table: $tableName, Size: $tableSize bytes');
} }
} }
Future<void> deleteDataForTwonlySafe() async {
await (delete(messages)..where(
(t) =>
(t.mediaStored.equals(false) &
t.isDeletedFromSender.equals(false)),
))
.go();
await update(messages).write(
const MessagesCompanion(
downloadToken: Value(null),
),
);
await (delete(mediaFiles)..where(
(t) => (t.stored.equals(false)),
))
.go();
await delete(receipts).go();
await delete(receivedReceipts).go();
await update(contacts).write(
const ContactsCompanion(
avatarSvgCompressed: Value(null),
senderProfileCounter: Value(0),
),
);
await (delete(signalPreKeyStores)..where(
(t) => (t.createdAt.isSmallerThanValue(
clock.now().subtract(
const Duration(days: 25),
),
)),
))
.go();
}
} }

View file

@ -64,20 +64,6 @@ Future<void> reuploadMediaFiles() async {
} }
} }
if (receipt.retryCount >= 2) {
// After two retries, change the receiptId. This addresses a bug where the receiver received the message and marked it as received, but the app was closed before the message was fully processed. Because the receipt was already stored, subsequent retries were detected as duplicates and rejected.
final oldReceiptId = receipt.receiptId;
final updatedReceipt = await twonlyDB.receiptsDao.rotateReceiptId(
oldReceiptId,
);
if (updatedReceipt == null) continue;
Log.info(
'Changed receiptId $oldReceiptId to ${updatedReceipt.receiptId} as retryCount is ${receipt.retryCount}',
);
receipt = updatedReceipt;
}
var messageId = receipt.messageId; var messageId = receipt.messageId;
if (receipt.messageId == null) { if (receipt.messageId == null) {
Log.info('Message not in receipt. Loading it from the content.'); Log.info('Message not in receipt. Loading it from the content.');