mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 09:28:41 +00:00
hopefully final fix for the retransmission problem
This commit is contained in:
parent
79caf95afe
commit
674e42722d
16 changed files with 8456 additions and 203 deletions
1
drift_schemas/twonly_database/drift_schema_v13.json
Normal file
1
drift_schemas/twonly_database/drift_schema_v13.json
Normal file
File diff suppressed because one or more lines are too long
1
drift_schemas/twonly_database/drift_schema_v14.json
Normal file
1
drift_schemas/twonly_database/drift_schema_v14.json
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -23,6 +23,15 @@ class MessageRetransmissionDao extends DatabaseAccessor<TwonlyDatabase>
|
|||
}
|
||||
|
||||
Future<List<int>> getRetransmitAbleMessages() async {
|
||||
final countDeleted = await (delete(messageRetransmissions)
|
||||
..where((t) =>
|
||||
t.encryptedHash.isNull() & t.acknowledgeByServerAt.isNotNull()))
|
||||
.go();
|
||||
|
||||
if (countDeleted > 0) {
|
||||
Log.info("Deleted $countDeleted faulty retransmissions");
|
||||
}
|
||||
|
||||
return (await (select(messageRetransmissions)
|
||||
..where((t) => t.acknowledgeByServerAt.isNull()))
|
||||
.get())
|
||||
|
|
@ -45,19 +54,11 @@ class MessageRetransmissionDao extends DatabaseAccessor<TwonlyDatabase>
|
|||
.write(updatedValues);
|
||||
}
|
||||
|
||||
Future resetAckStatusForAllMessages(int fromUserId) async {
|
||||
final deletedCount = await (delete(messageRetransmissions)
|
||||
..where((m) =>
|
||||
m.willNotGetACKByUser.equals(true) &
|
||||
m.acknowledgeByServerAt.isNotNull()))
|
||||
.go();
|
||||
if (deletedCount > 0) {
|
||||
Log.info('$deletedCount faulty retransmission messages where deleted.');
|
||||
}
|
||||
Future resetAckStatusFor(int fromUserId, Uint8List encryptedHash) async {
|
||||
return ((update(messageRetransmissions))
|
||||
..where((m) =>
|
||||
m.willNotGetACKByUser.equals(false) &
|
||||
m.contactId.equals(fromUserId)))
|
||||
m.contactId.equals(fromUserId) &
|
||||
m.encryptedHash.equals(encryptedHash)))
|
||||
.write(
|
||||
MessageRetransmissionsCompanion(
|
||||
acknowledgeByServerAt: Value(null),
|
||||
|
|
|
|||
|
|
@ -14,9 +14,7 @@ class MessageRetransmissions extends Table {
|
|||
|
||||
BlobColumn get plaintextContent => blob()();
|
||||
BlobColumn get pushData => blob().nullable()();
|
||||
|
||||
BoolColumn get willNotGetACKByUser =>
|
||||
boolean().withDefault(Constant(false))();
|
||||
BlobColumn get encryptedHash => blob().nullable()();
|
||||
|
||||
DateTimeColumn get acknowledgeByServerAt => dateTime().nullable()();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ class TwonlyDatabase extends _$TwonlyDatabase {
|
|||
TwonlyDatabase.forTesting(DatabaseConnection super.connection);
|
||||
|
||||
@override
|
||||
int get schemaVersion => 12;
|
||||
int get schemaVersion => 14;
|
||||
|
||||
static QueryExecutor _openConnection() {
|
||||
return driftDatabase(
|
||||
|
|
@ -125,6 +125,14 @@ class TwonlyDatabase extends _$TwonlyDatabase {
|
|||
m.addColumn(schema.messageRetransmissions,
|
||||
schema.messageRetransmissions.willNotGetACKByUser);
|
||||
},
|
||||
from12To13: (m, schema) async {
|
||||
m.dropColumn(
|
||||
schema.messageRetransmissions, "will_not_get_a_c_k_by_user");
|
||||
},
|
||||
from13To14: (m, schema) async {
|
||||
m.addColumn(schema.messageRetransmissions,
|
||||
schema.messageRetransmissions.encryptedHash);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4225,16 +4225,12 @@ class $MessageRetransmissionsTable extends MessageRetransmissions
|
|||
late final GeneratedColumn<Uint8List> pushData = GeneratedColumn<Uint8List>(
|
||||
'push_data', aliasedName, true,
|
||||
type: DriftSqlType.blob, requiredDuringInsert: false);
|
||||
static const VerificationMeta _willNotGetACKByUserMeta =
|
||||
const VerificationMeta('willNotGetACKByUser');
|
||||
static const VerificationMeta _encryptedHashMeta =
|
||||
const VerificationMeta('encryptedHash');
|
||||
@override
|
||||
late final GeneratedColumn<bool> willNotGetACKByUser = GeneratedColumn<bool>(
|
||||
'will_not_get_a_c_k_by_user', aliasedName, false,
|
||||
type: DriftSqlType.bool,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints: GeneratedColumn.constraintIsAlways(
|
||||
'CHECK ("will_not_get_a_c_k_by_user" IN (0, 1))'),
|
||||
defaultValue: Constant(false));
|
||||
late final GeneratedColumn<Uint8List> encryptedHash =
|
||||
GeneratedColumn<Uint8List>('encrypted_hash', aliasedName, true,
|
||||
type: DriftSqlType.blob, requiredDuringInsert: false);
|
||||
static const VerificationMeta _acknowledgeByServerAtMeta =
|
||||
const VerificationMeta('acknowledgeByServerAt');
|
||||
@override
|
||||
|
|
@ -4248,7 +4244,7 @@ class $MessageRetransmissionsTable extends MessageRetransmissions
|
|||
messageId,
|
||||
plaintextContent,
|
||||
pushData,
|
||||
willNotGetACKByUser,
|
||||
encryptedHash,
|
||||
acknowledgeByServerAt
|
||||
];
|
||||
@override
|
||||
|
|
@ -4290,11 +4286,11 @@ class $MessageRetransmissionsTable extends MessageRetransmissions
|
|||
context.handle(_pushDataMeta,
|
||||
pushData.isAcceptableOrUnknown(data['push_data']!, _pushDataMeta));
|
||||
}
|
||||
if (data.containsKey('will_not_get_a_c_k_by_user')) {
|
||||
if (data.containsKey('encrypted_hash')) {
|
||||
context.handle(
|
||||
_willNotGetACKByUserMeta,
|
||||
willNotGetACKByUser.isAcceptableOrUnknown(
|
||||
data['will_not_get_a_c_k_by_user']!, _willNotGetACKByUserMeta));
|
||||
_encryptedHashMeta,
|
||||
encryptedHash.isAcceptableOrUnknown(
|
||||
data['encrypted_hash']!, _encryptedHashMeta));
|
||||
}
|
||||
if (data.containsKey('acknowledge_by_server_at')) {
|
||||
context.handle(
|
||||
|
|
@ -4321,8 +4317,8 @@ class $MessageRetransmissionsTable extends MessageRetransmissions
|
|||
DriftSqlType.blob, data['${effectivePrefix}plaintext_content'])!,
|
||||
pushData: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.blob, data['${effectivePrefix}push_data']),
|
||||
willNotGetACKByUser: attachedDatabase.typeMapping.read(DriftSqlType.bool,
|
||||
data['${effectivePrefix}will_not_get_a_c_k_by_user'])!,
|
||||
encryptedHash: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.blob, data['${effectivePrefix}encrypted_hash']),
|
||||
acknowledgeByServerAt: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.dateTime,
|
||||
data['${effectivePrefix}acknowledge_by_server_at']),
|
||||
|
|
@ -4342,7 +4338,7 @@ class MessageRetransmission extends DataClass
|
|||
final int? messageId;
|
||||
final Uint8List plaintextContent;
|
||||
final Uint8List? pushData;
|
||||
final bool willNotGetACKByUser;
|
||||
final Uint8List? encryptedHash;
|
||||
final DateTime? acknowledgeByServerAt;
|
||||
const MessageRetransmission(
|
||||
{required this.retransmissionId,
|
||||
|
|
@ -4350,7 +4346,7 @@ class MessageRetransmission extends DataClass
|
|||
this.messageId,
|
||||
required this.plaintextContent,
|
||||
this.pushData,
|
||||
required this.willNotGetACKByUser,
|
||||
this.encryptedHash,
|
||||
this.acknowledgeByServerAt});
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
|
|
@ -4364,7 +4360,9 @@ class MessageRetransmission extends DataClass
|
|||
if (!nullToAbsent || pushData != null) {
|
||||
map['push_data'] = Variable<Uint8List>(pushData);
|
||||
}
|
||||
map['will_not_get_a_c_k_by_user'] = Variable<bool>(willNotGetACKByUser);
|
||||
if (!nullToAbsent || encryptedHash != null) {
|
||||
map['encrypted_hash'] = Variable<Uint8List>(encryptedHash);
|
||||
}
|
||||
if (!nullToAbsent || acknowledgeByServerAt != null) {
|
||||
map['acknowledge_by_server_at'] =
|
||||
Variable<DateTime>(acknowledgeByServerAt);
|
||||
|
|
@ -4383,7 +4381,9 @@ class MessageRetransmission extends DataClass
|
|||
pushData: pushData == null && nullToAbsent
|
||||
? const Value.absent()
|
||||
: Value(pushData),
|
||||
willNotGetACKByUser: Value(willNotGetACKByUser),
|
||||
encryptedHash: encryptedHash == null && nullToAbsent
|
||||
? const Value.absent()
|
||||
: Value(encryptedHash),
|
||||
acknowledgeByServerAt: acknowledgeByServerAt == null && nullToAbsent
|
||||
? const Value.absent()
|
||||
: Value(acknowledgeByServerAt),
|
||||
|
|
@ -4400,8 +4400,7 @@ class MessageRetransmission extends DataClass
|
|||
plaintextContent:
|
||||
serializer.fromJson<Uint8List>(json['plaintextContent']),
|
||||
pushData: serializer.fromJson<Uint8List?>(json['pushData']),
|
||||
willNotGetACKByUser:
|
||||
serializer.fromJson<bool>(json['willNotGetACKByUser']),
|
||||
encryptedHash: serializer.fromJson<Uint8List?>(json['encryptedHash']),
|
||||
acknowledgeByServerAt:
|
||||
serializer.fromJson<DateTime?>(json['acknowledgeByServerAt']),
|
||||
);
|
||||
|
|
@ -4415,7 +4414,7 @@ class MessageRetransmission extends DataClass
|
|||
'messageId': serializer.toJson<int?>(messageId),
|
||||
'plaintextContent': serializer.toJson<Uint8List>(plaintextContent),
|
||||
'pushData': serializer.toJson<Uint8List?>(pushData),
|
||||
'willNotGetACKByUser': serializer.toJson<bool>(willNotGetACKByUser),
|
||||
'encryptedHash': serializer.toJson<Uint8List?>(encryptedHash),
|
||||
'acknowledgeByServerAt':
|
||||
serializer.toJson<DateTime?>(acknowledgeByServerAt),
|
||||
};
|
||||
|
|
@ -4427,7 +4426,7 @@ class MessageRetransmission extends DataClass
|
|||
Value<int?> messageId = const Value.absent(),
|
||||
Uint8List? plaintextContent,
|
||||
Value<Uint8List?> pushData = const Value.absent(),
|
||||
bool? willNotGetACKByUser,
|
||||
Value<Uint8List?> encryptedHash = const Value.absent(),
|
||||
Value<DateTime?> acknowledgeByServerAt = const Value.absent()}) =>
|
||||
MessageRetransmission(
|
||||
retransmissionId: retransmissionId ?? this.retransmissionId,
|
||||
|
|
@ -4435,7 +4434,8 @@ class MessageRetransmission extends DataClass
|
|||
messageId: messageId.present ? messageId.value : this.messageId,
|
||||
plaintextContent: plaintextContent ?? this.plaintextContent,
|
||||
pushData: pushData.present ? pushData.value : this.pushData,
|
||||
willNotGetACKByUser: willNotGetACKByUser ?? this.willNotGetACKByUser,
|
||||
encryptedHash:
|
||||
encryptedHash.present ? encryptedHash.value : this.encryptedHash,
|
||||
acknowledgeByServerAt: acknowledgeByServerAt.present
|
||||
? acknowledgeByServerAt.value
|
||||
: this.acknowledgeByServerAt,
|
||||
|
|
@ -4452,9 +4452,9 @@ class MessageRetransmission extends DataClass
|
|||
? data.plaintextContent.value
|
||||
: this.plaintextContent,
|
||||
pushData: data.pushData.present ? data.pushData.value : this.pushData,
|
||||
willNotGetACKByUser: data.willNotGetACKByUser.present
|
||||
? data.willNotGetACKByUser.value
|
||||
: this.willNotGetACKByUser,
|
||||
encryptedHash: data.encryptedHash.present
|
||||
? data.encryptedHash.value
|
||||
: this.encryptedHash,
|
||||
acknowledgeByServerAt: data.acknowledgeByServerAt.present
|
||||
? data.acknowledgeByServerAt.value
|
||||
: this.acknowledgeByServerAt,
|
||||
|
|
@ -4469,7 +4469,7 @@ class MessageRetransmission extends DataClass
|
|||
..write('messageId: $messageId, ')
|
||||
..write('plaintextContent: $plaintextContent, ')
|
||||
..write('pushData: $pushData, ')
|
||||
..write('willNotGetACKByUser: $willNotGetACKByUser, ')
|
||||
..write('encryptedHash: $encryptedHash, ')
|
||||
..write('acknowledgeByServerAt: $acknowledgeByServerAt')
|
||||
..write(')'))
|
||||
.toString();
|
||||
|
|
@ -4482,7 +4482,7 @@ class MessageRetransmission extends DataClass
|
|||
messageId,
|
||||
$driftBlobEquality.hash(plaintextContent),
|
||||
$driftBlobEquality.hash(pushData),
|
||||
willNotGetACKByUser,
|
||||
$driftBlobEquality.hash(encryptedHash),
|
||||
acknowledgeByServerAt);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
|
|
@ -4494,7 +4494,7 @@ class MessageRetransmission extends DataClass
|
|||
$driftBlobEquality.equals(
|
||||
other.plaintextContent, this.plaintextContent) &&
|
||||
$driftBlobEquality.equals(other.pushData, this.pushData) &&
|
||||
other.willNotGetACKByUser == this.willNotGetACKByUser &&
|
||||
$driftBlobEquality.equals(other.encryptedHash, this.encryptedHash) &&
|
||||
other.acknowledgeByServerAt == this.acknowledgeByServerAt);
|
||||
}
|
||||
|
||||
|
|
@ -4505,7 +4505,7 @@ class MessageRetransmissionsCompanion
|
|||
final Value<int?> messageId;
|
||||
final Value<Uint8List> plaintextContent;
|
||||
final Value<Uint8List?> pushData;
|
||||
final Value<bool> willNotGetACKByUser;
|
||||
final Value<Uint8List?> encryptedHash;
|
||||
final Value<DateTime?> acknowledgeByServerAt;
|
||||
const MessageRetransmissionsCompanion({
|
||||
this.retransmissionId = const Value.absent(),
|
||||
|
|
@ -4513,7 +4513,7 @@ class MessageRetransmissionsCompanion
|
|||
this.messageId = const Value.absent(),
|
||||
this.plaintextContent = const Value.absent(),
|
||||
this.pushData = const Value.absent(),
|
||||
this.willNotGetACKByUser = const Value.absent(),
|
||||
this.encryptedHash = const Value.absent(),
|
||||
this.acknowledgeByServerAt = const Value.absent(),
|
||||
});
|
||||
MessageRetransmissionsCompanion.insert({
|
||||
|
|
@ -4522,7 +4522,7 @@ class MessageRetransmissionsCompanion
|
|||
this.messageId = const Value.absent(),
|
||||
required Uint8List plaintextContent,
|
||||
this.pushData = const Value.absent(),
|
||||
this.willNotGetACKByUser = const Value.absent(),
|
||||
this.encryptedHash = const Value.absent(),
|
||||
this.acknowledgeByServerAt = const Value.absent(),
|
||||
}) : contactId = Value(contactId),
|
||||
plaintextContent = Value(plaintextContent);
|
||||
|
|
@ -4532,7 +4532,7 @@ class MessageRetransmissionsCompanion
|
|||
Expression<int>? messageId,
|
||||
Expression<Uint8List>? plaintextContent,
|
||||
Expression<Uint8List>? pushData,
|
||||
Expression<bool>? willNotGetACKByUser,
|
||||
Expression<Uint8List>? encryptedHash,
|
||||
Expression<DateTime>? acknowledgeByServerAt,
|
||||
}) {
|
||||
return RawValuesInsertable({
|
||||
|
|
@ -4541,8 +4541,7 @@ class MessageRetransmissionsCompanion
|
|||
if (messageId != null) 'message_id': messageId,
|
||||
if (plaintextContent != null) 'plaintext_content': plaintextContent,
|
||||
if (pushData != null) 'push_data': pushData,
|
||||
if (willNotGetACKByUser != null)
|
||||
'will_not_get_a_c_k_by_user': willNotGetACKByUser,
|
||||
if (encryptedHash != null) 'encrypted_hash': encryptedHash,
|
||||
if (acknowledgeByServerAt != null)
|
||||
'acknowledge_by_server_at': acknowledgeByServerAt,
|
||||
});
|
||||
|
|
@ -4554,7 +4553,7 @@ class MessageRetransmissionsCompanion
|
|||
Value<int?>? messageId,
|
||||
Value<Uint8List>? plaintextContent,
|
||||
Value<Uint8List?>? pushData,
|
||||
Value<bool>? willNotGetACKByUser,
|
||||
Value<Uint8List?>? encryptedHash,
|
||||
Value<DateTime?>? acknowledgeByServerAt}) {
|
||||
return MessageRetransmissionsCompanion(
|
||||
retransmissionId: retransmissionId ?? this.retransmissionId,
|
||||
|
|
@ -4562,7 +4561,7 @@ class MessageRetransmissionsCompanion
|
|||
messageId: messageId ?? this.messageId,
|
||||
plaintextContent: plaintextContent ?? this.plaintextContent,
|
||||
pushData: pushData ?? this.pushData,
|
||||
willNotGetACKByUser: willNotGetACKByUser ?? this.willNotGetACKByUser,
|
||||
encryptedHash: encryptedHash ?? this.encryptedHash,
|
||||
acknowledgeByServerAt:
|
||||
acknowledgeByServerAt ?? this.acknowledgeByServerAt,
|
||||
);
|
||||
|
|
@ -4586,9 +4585,8 @@ class MessageRetransmissionsCompanion
|
|||
if (pushData.present) {
|
||||
map['push_data'] = Variable<Uint8List>(pushData.value);
|
||||
}
|
||||
if (willNotGetACKByUser.present) {
|
||||
map['will_not_get_a_c_k_by_user'] =
|
||||
Variable<bool>(willNotGetACKByUser.value);
|
||||
if (encryptedHash.present) {
|
||||
map['encrypted_hash'] = Variable<Uint8List>(encryptedHash.value);
|
||||
}
|
||||
if (acknowledgeByServerAt.present) {
|
||||
map['acknowledge_by_server_at'] =
|
||||
|
|
@ -4605,7 +4603,7 @@ class MessageRetransmissionsCompanion
|
|||
..write('messageId: $messageId, ')
|
||||
..write('plaintextContent: $plaintextContent, ')
|
||||
..write('pushData: $pushData, ')
|
||||
..write('willNotGetACKByUser: $willNotGetACKByUser, ')
|
||||
..write('encryptedHash: $encryptedHash, ')
|
||||
..write('acknowledgeByServerAt: $acknowledgeByServerAt')
|
||||
..write(')'))
|
||||
.toString();
|
||||
|
|
@ -7154,7 +7152,7 @@ typedef $$MessageRetransmissionsTableCreateCompanionBuilder
|
|||
Value<int?> messageId,
|
||||
required Uint8List plaintextContent,
|
||||
Value<Uint8List?> pushData,
|
||||
Value<bool> willNotGetACKByUser,
|
||||
Value<Uint8List?> encryptedHash,
|
||||
Value<DateTime?> acknowledgeByServerAt,
|
||||
});
|
||||
typedef $$MessageRetransmissionsTableUpdateCompanionBuilder
|
||||
|
|
@ -7164,7 +7162,7 @@ typedef $$MessageRetransmissionsTableUpdateCompanionBuilder
|
|||
Value<int?> messageId,
|
||||
Value<Uint8List> plaintextContent,
|
||||
Value<Uint8List?> pushData,
|
||||
Value<bool> willNotGetACKByUser,
|
||||
Value<Uint8List?> encryptedHash,
|
||||
Value<DateTime?> acknowledgeByServerAt,
|
||||
});
|
||||
|
||||
|
|
@ -7224,9 +7222,8 @@ class $$MessageRetransmissionsTableFilterComposer
|
|||
ColumnFilters<Uint8List> get pushData => $composableBuilder(
|
||||
column: $table.pushData, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<bool> get willNotGetACKByUser => $composableBuilder(
|
||||
column: $table.willNotGetACKByUser,
|
||||
builder: (column) => ColumnFilters(column));
|
||||
ColumnFilters<Uint8List> get encryptedHash => $composableBuilder(
|
||||
column: $table.encryptedHash, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<DateTime> get acknowledgeByServerAt => $composableBuilder(
|
||||
column: $table.acknowledgeByServerAt,
|
||||
|
|
@ -7293,8 +7290,8 @@ class $$MessageRetransmissionsTableOrderingComposer
|
|||
ColumnOrderings<Uint8List> get pushData => $composableBuilder(
|
||||
column: $table.pushData, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<bool> get willNotGetACKByUser => $composableBuilder(
|
||||
column: $table.willNotGetACKByUser,
|
||||
ColumnOrderings<Uint8List> get encryptedHash => $composableBuilder(
|
||||
column: $table.encryptedHash,
|
||||
builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<DateTime> get acknowledgeByServerAt => $composableBuilder(
|
||||
|
|
@ -7360,8 +7357,8 @@ class $$MessageRetransmissionsTableAnnotationComposer
|
|||
GeneratedColumn<Uint8List> get pushData =>
|
||||
$composableBuilder(column: $table.pushData, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<bool> get willNotGetACKByUser => $composableBuilder(
|
||||
column: $table.willNotGetACKByUser, builder: (column) => column);
|
||||
GeneratedColumn<Uint8List> get encryptedHash => $composableBuilder(
|
||||
column: $table.encryptedHash, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<DateTime> get acknowledgeByServerAt => $composableBuilder(
|
||||
column: $table.acknowledgeByServerAt, builder: (column) => column);
|
||||
|
|
@ -7439,7 +7436,7 @@ class $$MessageRetransmissionsTableTableManager extends RootTableManager<
|
|||
Value<int?> messageId = const Value.absent(),
|
||||
Value<Uint8List> plaintextContent = const Value.absent(),
|
||||
Value<Uint8List?> pushData = const Value.absent(),
|
||||
Value<bool> willNotGetACKByUser = const Value.absent(),
|
||||
Value<Uint8List?> encryptedHash = const Value.absent(),
|
||||
Value<DateTime?> acknowledgeByServerAt = const Value.absent(),
|
||||
}) =>
|
||||
MessageRetransmissionsCompanion(
|
||||
|
|
@ -7448,7 +7445,7 @@ class $$MessageRetransmissionsTableTableManager extends RootTableManager<
|
|||
messageId: messageId,
|
||||
plaintextContent: plaintextContent,
|
||||
pushData: pushData,
|
||||
willNotGetACKByUser: willNotGetACKByUser,
|
||||
encryptedHash: encryptedHash,
|
||||
acknowledgeByServerAt: acknowledgeByServerAt,
|
||||
),
|
||||
createCompanionCallback: ({
|
||||
|
|
@ -7457,7 +7454,7 @@ class $$MessageRetransmissionsTableTableManager extends RootTableManager<
|
|||
Value<int?> messageId = const Value.absent(),
|
||||
required Uint8List plaintextContent,
|
||||
Value<Uint8List?> pushData = const Value.absent(),
|
||||
Value<bool> willNotGetACKByUser = const Value.absent(),
|
||||
Value<Uint8List?> encryptedHash = const Value.absent(),
|
||||
Value<DateTime?> acknowledgeByServerAt = const Value.absent(),
|
||||
}) =>
|
||||
MessageRetransmissionsCompanion.insert(
|
||||
|
|
@ -7466,7 +7463,7 @@ class $$MessageRetransmissionsTableTableManager extends RootTableManager<
|
|||
messageId: messageId,
|
||||
plaintextContent: plaintextContent,
|
||||
pushData: pushData,
|
||||
willNotGetACKByUser: willNotGetACKByUser,
|
||||
encryptedHash: encryptedHash,
|
||||
acknowledgeByServerAt: acknowledgeByServerAt,
|
||||
),
|
||||
withReferenceMapper: (p0) => p0
|
||||
|
|
|
|||
|
|
@ -2722,6 +2722,490 @@ i1.GeneratedColumn<bool> _column_68(String aliasedName) =>
|
|||
defaultConstraints: i1.GeneratedColumn.constraintIsAlways(
|
||||
'CHECK ("will_not_get_a_c_k_by_user" IN (0, 1))'),
|
||||
defaultValue: const CustomExpression('0'));
|
||||
|
||||
final class Schema13 extends i0.VersionedSchema {
|
||||
Schema13({required super.database}) : super(version: 13);
|
||||
@override
|
||||
late final List<i1.DatabaseSchemaEntity> entities = [
|
||||
contacts,
|
||||
messages,
|
||||
mediaUploads,
|
||||
mediaDownloads,
|
||||
signalIdentityKeyStores,
|
||||
signalPreKeyStores,
|
||||
signalSenderKeyStores,
|
||||
signalSessionStores,
|
||||
signalContactPreKeys,
|
||||
signalContactSignedPreKeys,
|
||||
messageRetransmissions,
|
||||
];
|
||||
late final Shape13 contacts = Shape13(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'contacts',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(user_id)',
|
||||
],
|
||||
columns: [
|
||||
_column_0,
|
||||
_column_1,
|
||||
_column_2,
|
||||
_column_3,
|
||||
_column_4,
|
||||
_column_5,
|
||||
_column_6,
|
||||
_column_7,
|
||||
_column_8,
|
||||
_column_9,
|
||||
_column_39,
|
||||
_column_53,
|
||||
_column_57,
|
||||
_column_54,
|
||||
_column_40,
|
||||
_column_10,
|
||||
_column_11,
|
||||
_column_12,
|
||||
_column_13,
|
||||
_column_14,
|
||||
_column_55,
|
||||
_column_15,
|
||||
_column_16,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape10 messages = Shape10(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'messages',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_17,
|
||||
_column_18,
|
||||
_column_19,
|
||||
_column_48,
|
||||
_column_49,
|
||||
_column_20,
|
||||
_column_21,
|
||||
_column_22,
|
||||
_column_52,
|
||||
_column_23,
|
||||
_column_24,
|
||||
_column_25,
|
||||
_column_26,
|
||||
_column_27,
|
||||
_column_28,
|
||||
_column_29,
|
||||
_column_30,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape7 mediaUploads = Shape7(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'media_uploads',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_41,
|
||||
_column_42,
|
||||
_column_56,
|
||||
_column_44,
|
||||
_column_45,
|
||||
_column_46,
|
||||
_column_47,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape9 mediaDownloads = Shape9(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'media_downloads',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_50,
|
||||
_column_51,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape2 signalIdentityKeyStores = Shape2(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'signal_identity_key_stores',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(device_id, name)',
|
||||
],
|
||||
columns: [
|
||||
_column_31,
|
||||
_column_32,
|
||||
_column_33,
|
||||
_column_10,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape3 signalPreKeyStores = Shape3(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'signal_pre_key_stores',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(pre_key_id)',
|
||||
],
|
||||
columns: [
|
||||
_column_34,
|
||||
_column_35,
|
||||
_column_10,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape4 signalSenderKeyStores = Shape4(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'signal_sender_key_stores',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(sender_key_name)',
|
||||
],
|
||||
columns: [
|
||||
_column_36,
|
||||
_column_37,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape5 signalSessionStores = Shape5(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'signal_session_stores',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(device_id, name)',
|
||||
],
|
||||
columns: [
|
||||
_column_31,
|
||||
_column_32,
|
||||
_column_38,
|
||||
_column_10,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape14 signalContactPreKeys = Shape14(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'signal_contact_pre_keys',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(contact_id, pre_key_id)',
|
||||
],
|
||||
columns: [
|
||||
_column_58,
|
||||
_column_34,
|
||||
_column_35,
|
||||
_column_10,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape15 signalContactSignedPreKeys = Shape15(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'signal_contact_signed_pre_keys',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(contact_id)',
|
||||
],
|
||||
columns: [
|
||||
_column_58,
|
||||
_column_59,
|
||||
_column_60,
|
||||
_column_61,
|
||||
_column_10,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape16 messageRetransmissions = Shape16(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'message_retransmissions',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_62,
|
||||
_column_63,
|
||||
_column_64,
|
||||
_column_65,
|
||||
_column_66,
|
||||
_column_67,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
}
|
||||
|
||||
final class Schema14 extends i0.VersionedSchema {
|
||||
Schema14({required super.database}) : super(version: 14);
|
||||
@override
|
||||
late final List<i1.DatabaseSchemaEntity> entities = [
|
||||
contacts,
|
||||
messages,
|
||||
mediaUploads,
|
||||
mediaDownloads,
|
||||
signalIdentityKeyStores,
|
||||
signalPreKeyStores,
|
||||
signalSenderKeyStores,
|
||||
signalSessionStores,
|
||||
signalContactPreKeys,
|
||||
signalContactSignedPreKeys,
|
||||
messageRetransmissions,
|
||||
];
|
||||
late final Shape13 contacts = Shape13(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'contacts',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(user_id)',
|
||||
],
|
||||
columns: [
|
||||
_column_0,
|
||||
_column_1,
|
||||
_column_2,
|
||||
_column_3,
|
||||
_column_4,
|
||||
_column_5,
|
||||
_column_6,
|
||||
_column_7,
|
||||
_column_8,
|
||||
_column_9,
|
||||
_column_39,
|
||||
_column_53,
|
||||
_column_57,
|
||||
_column_54,
|
||||
_column_40,
|
||||
_column_10,
|
||||
_column_11,
|
||||
_column_12,
|
||||
_column_13,
|
||||
_column_14,
|
||||
_column_55,
|
||||
_column_15,
|
||||
_column_16,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape10 messages = Shape10(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'messages',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_17,
|
||||
_column_18,
|
||||
_column_19,
|
||||
_column_48,
|
||||
_column_49,
|
||||
_column_20,
|
||||
_column_21,
|
||||
_column_22,
|
||||
_column_52,
|
||||
_column_23,
|
||||
_column_24,
|
||||
_column_25,
|
||||
_column_26,
|
||||
_column_27,
|
||||
_column_28,
|
||||
_column_29,
|
||||
_column_30,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape7 mediaUploads = Shape7(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'media_uploads',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_41,
|
||||
_column_42,
|
||||
_column_56,
|
||||
_column_44,
|
||||
_column_45,
|
||||
_column_46,
|
||||
_column_47,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape9 mediaDownloads = Shape9(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'media_downloads',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_50,
|
||||
_column_51,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape2 signalIdentityKeyStores = Shape2(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'signal_identity_key_stores',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(device_id, name)',
|
||||
],
|
||||
columns: [
|
||||
_column_31,
|
||||
_column_32,
|
||||
_column_33,
|
||||
_column_10,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape3 signalPreKeyStores = Shape3(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'signal_pre_key_stores',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(pre_key_id)',
|
||||
],
|
||||
columns: [
|
||||
_column_34,
|
||||
_column_35,
|
||||
_column_10,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape4 signalSenderKeyStores = Shape4(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'signal_sender_key_stores',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(sender_key_name)',
|
||||
],
|
||||
columns: [
|
||||
_column_36,
|
||||
_column_37,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape5 signalSessionStores = Shape5(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'signal_session_stores',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(device_id, name)',
|
||||
],
|
||||
columns: [
|
||||
_column_31,
|
||||
_column_32,
|
||||
_column_38,
|
||||
_column_10,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape14 signalContactPreKeys = Shape14(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'signal_contact_pre_keys',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(contact_id, pre_key_id)',
|
||||
],
|
||||
columns: [
|
||||
_column_58,
|
||||
_column_34,
|
||||
_column_35,
|
||||
_column_10,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape15 signalContactSignedPreKeys = Shape15(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'signal_contact_signed_pre_keys',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(contact_id)',
|
||||
],
|
||||
columns: [
|
||||
_column_58,
|
||||
_column_59,
|
||||
_column_60,
|
||||
_column_61,
|
||||
_column_10,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape18 messageRetransmissions = Shape18(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'message_retransmissions',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_62,
|
||||
_column_63,
|
||||
_column_64,
|
||||
_column_65,
|
||||
_column_66,
|
||||
_column_69,
|
||||
_column_67,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
}
|
||||
|
||||
class Shape18 extends i0.VersionedTable {
|
||||
Shape18({required super.source, required super.alias}) : super.aliased();
|
||||
i1.GeneratedColumn<int> get retransmissionId =>
|
||||
columnsByName['retransmission_id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<int> get contactId =>
|
||||
columnsByName['contact_id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<int> get messageId =>
|
||||
columnsByName['message_id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<i2.Uint8List> get plaintextContent =>
|
||||
columnsByName['plaintext_content']! as i1.GeneratedColumn<i2.Uint8List>;
|
||||
i1.GeneratedColumn<i2.Uint8List> get pushData =>
|
||||
columnsByName['push_data']! as i1.GeneratedColumn<i2.Uint8List>;
|
||||
i1.GeneratedColumn<i2.Uint8List> get encryptedHash =>
|
||||
columnsByName['encrypted_hash']! as i1.GeneratedColumn<i2.Uint8List>;
|
||||
i1.GeneratedColumn<DateTime> get acknowledgeByServerAt =>
|
||||
columnsByName['acknowledge_by_server_at']!
|
||||
as i1.GeneratedColumn<DateTime>;
|
||||
}
|
||||
|
||||
i1.GeneratedColumn<i2.Uint8List> _column_69(String aliasedName) =>
|
||||
i1.GeneratedColumn<i2.Uint8List>('encrypted_hash', aliasedName, true,
|
||||
type: i1.DriftSqlType.blob);
|
||||
i0.MigrationStepWithVersion migrationSteps({
|
||||
required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
|
||||
required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
|
||||
|
|
@ -2734,6 +3218,8 @@ i0.MigrationStepWithVersion migrationSteps({
|
|||
required Future<void> Function(i1.Migrator m, Schema10 schema) from9To10,
|
||||
required Future<void> Function(i1.Migrator m, Schema11 schema) from10To11,
|
||||
required Future<void> Function(i1.Migrator m, Schema12 schema) from11To12,
|
||||
required Future<void> Function(i1.Migrator m, Schema13 schema) from12To13,
|
||||
required Future<void> Function(i1.Migrator m, Schema14 schema) from13To14,
|
||||
}) {
|
||||
return (currentVersion, database) async {
|
||||
switch (currentVersion) {
|
||||
|
|
@ -2792,6 +3278,16 @@ i0.MigrationStepWithVersion migrationSteps({
|
|||
final migrator = i1.Migrator(database, schema);
|
||||
await from11To12(migrator, schema);
|
||||
return 12;
|
||||
case 12:
|
||||
final schema = Schema13(database: database);
|
||||
final migrator = i1.Migrator(database, schema);
|
||||
await from12To13(migrator, schema);
|
||||
return 13;
|
||||
case 13:
|
||||
final schema = Schema14(database: database);
|
||||
final migrator = i1.Migrator(database, schema);
|
||||
await from13To14(migrator, schema);
|
||||
return 14;
|
||||
default:
|
||||
throw ArgumentError.value('Unknown migration from $currentVersion');
|
||||
}
|
||||
|
|
@ -2810,6 +3306,8 @@ i1.OnUpgrade stepByStep({
|
|||
required Future<void> Function(i1.Migrator m, Schema10 schema) from9To10,
|
||||
required Future<void> Function(i1.Migrator m, Schema11 schema) from10To11,
|
||||
required Future<void> Function(i1.Migrator m, Schema12 schema) from11To12,
|
||||
required Future<void> Function(i1.Migrator m, Schema13 schema) from12To13,
|
||||
required Future<void> Function(i1.Migrator m, Schema14 schema) from13To14,
|
||||
}) =>
|
||||
i0.VersionedSchema.stepByStepHelper(
|
||||
step: migrationSteps(
|
||||
|
|
@ -2824,4 +3322,6 @@ i1.OnUpgrade stepByStep({
|
|||
from9To10: from9To10,
|
||||
from10To11: from10To11,
|
||||
from11To12: from11To12,
|
||||
from12To13: from12To13,
|
||||
from13To14: from13To14,
|
||||
));
|
||||
|
|
|
|||
|
|
@ -96,6 +96,8 @@ class MessageContent {
|
|||
return FlameSyncContent.fromJson(json);
|
||||
case MessageKind.ack:
|
||||
return AckContent.fromJson(json);
|
||||
case MessageKind.signalDecryptError:
|
||||
return SignalDecryptErrorContent.fromJson(json);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
@ -222,6 +224,24 @@ class ReopenedMediaFileContent extends MessageContent {
|
|||
}
|
||||
}
|
||||
|
||||
class SignalDecryptErrorContent extends MessageContent {
|
||||
List<int> encryptedHash;
|
||||
SignalDecryptErrorContent({required this.encryptedHash});
|
||||
|
||||
static SignalDecryptErrorContent fromJson(Map json) {
|
||||
return SignalDecryptErrorContent(
|
||||
encryptedHash: List<int>.from(json['encryptedHash']),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map toJson() {
|
||||
return {
|
||||
'encryptedHash': encryptedHash,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class AckContent extends MessageContent {
|
||||
int? messageIdToAck;
|
||||
int retransIdToAck;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:cryptography_plus/cryptography_plus.dart';
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:fixnum/fixnum.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
|
|
@ -10,6 +11,8 @@ import 'package:twonly/src/model/json/message.dart';
|
|||
import 'package:twonly/src/model/json/userdata.dart';
|
||||
import 'package:twonly/src/model/protobuf/api/websocket/error.pb.dart';
|
||||
import 'package:twonly/src/model/protobuf/push_notification/push_notification.pb.dart';
|
||||
import 'package:twonly/src/services/api/server_messages.dart'
|
||||
show messageGetsAck;
|
||||
import 'package:twonly/src/services/api/utils.dart';
|
||||
import 'package:twonly/src/services/notifications/pushkeys.notifications.dart';
|
||||
import 'package:twonly/src/services/signal/encryption.signal.dart';
|
||||
|
|
@ -24,137 +27,138 @@ Future tryTransmitMessages() async {
|
|||
|
||||
if (retransIds.isEmpty) return;
|
||||
|
||||
bool filterPreKeys = false;
|
||||
|
||||
if (retransIds.length > 100) {
|
||||
filterPreKeys = true; // just a workaround until I can fix the real issue :/
|
||||
}
|
||||
|
||||
for (final retransId in retransIds) {
|
||||
sendRetransmitMessage(retransId, filterPreKeys: filterPreKeys);
|
||||
sendRetransmitMessage(retransId, fromRetransmissionDb: true);
|
||||
//twonlyDB.messageRetransmissionDao.deleteRetransmissionById(retransId);
|
||||
}
|
||||
}
|
||||
|
||||
Future sendRetransmitMessage(int retransId,
|
||||
{bool filterPreKeys = false}) async {
|
||||
MessageRetransmission? retrans = await twonlyDB.messageRetransmissionDao
|
||||
.getRetransmissionById(retransId)
|
||||
.getSingleOrNull();
|
||||
{bool fromRetransmissionDb = false}) async {
|
||||
try {
|
||||
MessageRetransmission? retrans = await twonlyDB.messageRetransmissionDao
|
||||
.getRetransmissionById(retransId)
|
||||
.getSingleOrNull();
|
||||
|
||||
if (retrans == null) {
|
||||
Log.error("$retransId not found in database");
|
||||
return;
|
||||
}
|
||||
if (retrans == null) {
|
||||
Log.error("$retransId not found in database");
|
||||
return;
|
||||
}
|
||||
|
||||
MessageJson json = MessageJson.fromJson(
|
||||
jsonDecode(
|
||||
utf8.decode(
|
||||
gzip.decode(retrans.plaintextContent),
|
||||
MessageJson json = MessageJson.fromJson(
|
||||
jsonDecode(
|
||||
utf8.decode(
|
||||
gzip.decode(retrans.plaintextContent),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
if (filterPreKeys && json.kind == MessageKind.pushKey) {
|
||||
if (!retrans.willNotGetACKByUser) {
|
||||
Log.error("Why is willNotGetACKByUser false????");
|
||||
);
|
||||
DateTime timestampToCheck = DateTime.parse("2025-06-24T12:00:00");
|
||||
if (json.timestamp.isBefore(timestampToCheck)) {
|
||||
Log.info("Deleting retransmission because it is before the update...");
|
||||
await twonlyDB.messageRetransmissionDao
|
||||
.deleteRetransmissionById(retransId);
|
||||
return;
|
||||
}
|
||||
Log.info("Filtering preKeys: ${json.kind} to ${retrans.contactId}");
|
||||
await twonlyDB.messageRetransmissionDao.deleteRetransmissionById(retransId);
|
||||
return;
|
||||
}
|
||||
Log.info("Retransmitting: ${json.kind} to ${retrans.contactId}");
|
||||
// if (json.kind
|
||||
// .contains(MessageKind.pushKey.name)) {
|
||||
// await twonlyDB.messageRetransmissionDao.deleteRetransmissionById(retransId);
|
||||
// return;
|
||||
// }
|
||||
|
||||
Contact? contact = await twonlyDB.contactsDao
|
||||
.getContactByUserId(retrans.contactId)
|
||||
.getSingleOrNull();
|
||||
if (contact == null || contact.deleted) {
|
||||
Log.warn("Contact deleted $retransId or not found in database.");
|
||||
if (retrans.messageId != null) {
|
||||
await twonlyDB.messagesDao.updateMessageByMessageId(
|
||||
retrans.messageId!,
|
||||
MessagesCompanion(errorWhileSending: Value(true)),
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Log.info("Retransmitting: ${json.kind} to ${retrans.contactId}");
|
||||
|
||||
Uint8List? encryptedBytes = await signalEncryptMessage(
|
||||
retrans.contactId,
|
||||
retrans.plaintextContent,
|
||||
);
|
||||
|
||||
if (encryptedBytes == null) {
|
||||
Log.error("Could not encrypt the message. Aborting and trying again.");
|
||||
return;
|
||||
}
|
||||
|
||||
Result resp = await apiService.sendTextMessage(
|
||||
retrans.contactId,
|
||||
encryptedBytes,
|
||||
retrans.pushData,
|
||||
);
|
||||
|
||||
bool retry = true;
|
||||
|
||||
if (resp.isError) {
|
||||
Log.error("Could not retransmit message.");
|
||||
if (resp.error == ErrorCode.UserIdNotFound) {
|
||||
retry = false;
|
||||
Contact? contact = await twonlyDB.contactsDao
|
||||
.getContactByUserId(retrans.contactId)
|
||||
.getSingleOrNull();
|
||||
if (contact == null || contact.deleted) {
|
||||
Log.warn("Contact deleted $retransId or not found in database.");
|
||||
if (retrans.messageId != null) {
|
||||
await twonlyDB.messagesDao.updateMessageByMessageId(
|
||||
retrans.messageId!,
|
||||
MessagesCompanion(errorWhileSending: Value(true)),
|
||||
);
|
||||
}
|
||||
await twonlyDB.contactsDao.updateContact(
|
||||
retrans.contactId,
|
||||
ContactsCompanion(deleted: Value(true)),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (resp.isSuccess) {
|
||||
retry = false;
|
||||
if (retrans.messageId != null) {
|
||||
await twonlyDB.messagesDao.updateMessageByMessageId(
|
||||
retrans.messageId!,
|
||||
MessagesCompanion(
|
||||
acknowledgeByServer: Value(true),
|
||||
errorWhileSending: Value(false),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Uint8List? encryptedBytes = await signalEncryptMessage(
|
||||
retrans.contactId,
|
||||
retrans.plaintextContent,
|
||||
);
|
||||
|
||||
if (!retry) {
|
||||
if (!retrans.willNotGetACKByUser && json.kind == MessageKind.pushKey) {
|
||||
Log.error("Why is willNotGetACKByUser false????");
|
||||
if (encryptedBytes == null) {
|
||||
Log.error("Could not encrypt the message. Aborting and trying again.");
|
||||
return;
|
||||
}
|
||||
if (retrans.willNotGetACKByUser ||
|
||||
json.kind == MessageKind.pushKey ||
|
||||
json.kind == MessageKind.ack) {
|
||||
await twonlyDB.messageRetransmissionDao
|
||||
.deleteRetransmissionById(retransId);
|
||||
} else {
|
||||
await twonlyDB.messageRetransmissionDao.updateRetransmission(
|
||||
retransId,
|
||||
MessageRetransmissionsCompanion(
|
||||
acknowledgeByServerAt: Value(DateTime.now()),
|
||||
),
|
||||
);
|
||||
|
||||
final encryptedHash = (await Sha256().hash(encryptedBytes)).bytes;
|
||||
|
||||
await twonlyDB.messageRetransmissionDao.updateRetransmission(
|
||||
retransId,
|
||||
MessageRetransmissionsCompanion(
|
||||
encryptedHash: Value(Uint8List.fromList(encryptedHash)),
|
||||
),
|
||||
);
|
||||
|
||||
Result resp = await apiService.sendTextMessage(
|
||||
retrans.contactId,
|
||||
encryptedBytes,
|
||||
retrans.pushData,
|
||||
);
|
||||
|
||||
bool retry = true;
|
||||
|
||||
if (resp.isError) {
|
||||
Log.error("Could not retransmit message.");
|
||||
if (resp.error == ErrorCode.UserIdNotFound) {
|
||||
retry = false;
|
||||
if (retrans.messageId != null) {
|
||||
await twonlyDB.messagesDao.updateMessageByMessageId(
|
||||
retrans.messageId!,
|
||||
MessagesCompanion(errorWhileSending: Value(true)),
|
||||
);
|
||||
}
|
||||
await twonlyDB.contactsDao.updateContact(
|
||||
retrans.contactId,
|
||||
ContactsCompanion(deleted: Value(true)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (resp.isSuccess) {
|
||||
retry = false;
|
||||
if (retrans.messageId != null) {
|
||||
await twonlyDB.messagesDao.updateMessageByMessageId(
|
||||
retrans.messageId!,
|
||||
MessagesCompanion(
|
||||
acknowledgeByServer: Value(true),
|
||||
errorWhileSending: Value(false),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!retry) {
|
||||
if (!messageGetsAck(json.kind)) {
|
||||
await twonlyDB.messageRetransmissionDao
|
||||
.deleteRetransmissionById(retransId);
|
||||
} else {
|
||||
await twonlyDB.messageRetransmissionDao.updateRetransmission(
|
||||
retransId,
|
||||
MessageRetransmissionsCompanion(
|
||||
acknowledgeByServerAt: Value(DateTime.now()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
Log.error("error resending message: $e");
|
||||
await twonlyDB.messageRetransmissionDao.deleteRetransmissionById(retransId);
|
||||
}
|
||||
}
|
||||
|
||||
// encrypts and stores the message and then sends it in the background
|
||||
Future encryptAndSendMessageAsync(int? messageId, int userId, MessageJson msg,
|
||||
{PushNotification? pushNotification,
|
||||
bool willNotGetACKByUser = false}) async {
|
||||
Future encryptAndSendMessageAsync(
|
||||
int? messageId,
|
||||
int userId,
|
||||
MessageJson msg, {
|
||||
PushNotification? pushNotification,
|
||||
}) async {
|
||||
if (gIsDemoUser) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -170,7 +174,6 @@ Future encryptAndSendMessageAsync(int? messageId, int userId, MessageJson msg,
|
|||
messageId: Value(messageId),
|
||||
plaintextContent: Value(Uint8List(0)),
|
||||
pushData: Value(pushData),
|
||||
willNotGetACKByUser: Value(willNotGetACKByUser),
|
||||
),
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:cryptography_plus/cryptography_plus.dart';
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:fixnum/fixnum.dart';
|
||||
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
|
||||
|
|
@ -22,7 +23,6 @@ import 'package:twonly/src/services/notifications/pushkeys.notifications.dart';
|
|||
import 'package:twonly/src/services/notifications/setup.notifications.dart';
|
||||
import 'package:twonly/src/services/signal/encryption.signal.dart';
|
||||
import 'package:twonly/src/services/signal/identity.signal.dart';
|
||||
import 'package:twonly/src/services/signal/prekeys.signal.dart';
|
||||
import 'package:twonly/src/services/thumbnail.service.dart';
|
||||
import 'package:twonly/src/utils/log.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
|
|
@ -60,15 +60,20 @@ Future handleServerMessage(server.ServerToClient msg) async {
|
|||
DateTime lastSignalDecryptMessage = DateTime.now().subtract(Duration(hours: 1));
|
||||
DateTime lastPushKeyRequest = DateTime.now().subtract(Duration(hours: 1));
|
||||
|
||||
bool messageGetsAck(MessageKind kind) {
|
||||
return kind != MessageKind.pushKey && kind != MessageKind.ack;
|
||||
}
|
||||
|
||||
Future<client.Response> handleNewMessage(int fromUserId, Uint8List body) async {
|
||||
MessageJson? message = await signalDecryptMessage(fromUserId, body);
|
||||
if (message == null) {
|
||||
final encryptedHash = (await Sha256().hash(body)).bytes;
|
||||
await encryptAndSendMessageAsync(
|
||||
null,
|
||||
fromUserId,
|
||||
MessageJson(
|
||||
kind: MessageKind.signalDecryptError,
|
||||
content: MessageContent(),
|
||||
content: SignalDecryptErrorContent(encryptedHash: encryptedHash),
|
||||
timestamp: DateTime.now(),
|
||||
),
|
||||
);
|
||||
|
|
@ -82,9 +87,7 @@ Future<client.Response> handleNewMessage(int fromUserId, Uint8List body) async {
|
|||
|
||||
Log.info("Got: ${message.kind} from $fromUserId");
|
||||
|
||||
if (message.kind != MessageKind.ack &&
|
||||
message.kind != MessageKind.pushKey &&
|
||||
message.retransId != null) {
|
||||
if (messageGetsAck(message.kind) && message.retransId != null) {
|
||||
Log.info("Sending ACK for ${message.kind}");
|
||||
|
||||
/// ACK every message
|
||||
|
|
@ -99,7 +102,6 @@ Future<client.Response> handleNewMessage(int fromUserId, Uint8List body) async {
|
|||
retransIdToAck: message.retransId!),
|
||||
timestamp: DateTime.now(),
|
||||
),
|
||||
willNotGetACKByUser: true,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -124,15 +126,15 @@ Future<client.Response> handleNewMessage(int fromUserId, Uint8List body) async {
|
|||
}
|
||||
break;
|
||||
case MessageKind.signalDecryptError:
|
||||
if (lastSignalDecryptMessage
|
||||
.isBefore(DateTime.now().subtract(Duration(seconds: 60)))) {
|
||||
Log.error(
|
||||
"Got signal decrypt error from other user! Sending all non ACK messages again.");
|
||||
lastSignalDecryptMessage = DateTime.now();
|
||||
await twonlyDB.signalDao.deleteAllPreKeysByContactId(fromUserId);
|
||||
await requestNewPrekeysForContact(fromUserId);
|
||||
await twonlyDB.messageRetransmissionDao
|
||||
.resetAckStatusForAllMessages(fromUserId);
|
||||
Log.error(
|
||||
"Got signal decrypt error from other user! Sending all non ACK messages again.");
|
||||
|
||||
final content = message.content;
|
||||
if (content is SignalDecryptErrorContent) {
|
||||
await twonlyDB.messageRetransmissionDao.resetAckStatusFor(
|
||||
fromUserId,
|
||||
Uint8List.fromList(content.encryptedHash),
|
||||
);
|
||||
tryTransmitMessages();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -110,7 +110,6 @@ Future sendNewPushKey(int userId, PushKey pushKey) async {
|
|||
pushKey.createdAtUnixTimestamp.toInt(),
|
||||
),
|
||||
),
|
||||
willNotGetACKByUser: true, // hot fix, this can be removed later...
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:fixnum/fixnum.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
@ -8,7 +7,6 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/src/constants/secure_storage_keys.dart';
|
||||
import 'package:twonly/src/model/protobuf/push_notification/push_notification.pbserver.dart';
|
||||
import 'package:twonly/src/services/api/messages.dart';
|
||||
import 'package:twonly/src/services/notifications/pushkeys.notifications.dart';
|
||||
import 'package:twonly/src/views/components/alert_dialog.dart';
|
||||
import 'package:twonly/src/services/fcm.service.dart';
|
||||
|
|
@ -29,13 +27,6 @@ class NotificationView extends StatelessWidget {
|
|||
ListTile(
|
||||
title: Text(context.lang.settingsNotifyTroubleshooting),
|
||||
subtitle: Text(context.lang.settingsNotifyTroubleshootingDesc),
|
||||
onLongPress: (kDebugMode)
|
||||
? () async {
|
||||
await twonlyDB.messageRetransmissionDao
|
||||
.resetAckStatusForAllMessages(537506372);
|
||||
tryTransmitMessages();
|
||||
}
|
||||
: null,
|
||||
onTap: () async {
|
||||
await initFCMAfterAuthenticated();
|
||||
String? storedToken = await FlutterSecureStorage()
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ description: "twonly, a privacy-friendly way to connect with friends through sec
|
|||
# Prevent accidental publishing to pub.dev.
|
||||
publish_to: 'none'
|
||||
|
||||
version: 0.0.43+43
|
||||
version: 0.0.45+45
|
||||
|
||||
environment:
|
||||
sdk: ^3.6.0
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ import 'schema_v9.dart' as v9;
|
|||
import 'schema_v10.dart' as v10;
|
||||
import 'schema_v11.dart' as v11;
|
||||
import 'schema_v12.dart' as v12;
|
||||
import 'schema_v13.dart' as v13;
|
||||
import 'schema_v14.dart' as v14;
|
||||
|
||||
class GeneratedHelper implements SchemaInstantiationHelper {
|
||||
@override
|
||||
|
|
@ -44,10 +46,14 @@ class GeneratedHelper implements SchemaInstantiationHelper {
|
|||
return v11.DatabaseAtV11(db);
|
||||
case 12:
|
||||
return v12.DatabaseAtV12(db);
|
||||
case 13:
|
||||
return v13.DatabaseAtV13(db);
|
||||
case 14:
|
||||
return v14.DatabaseAtV14(db);
|
||||
default:
|
||||
throw MissingSchemaException(version, versions);
|
||||
}
|
||||
}
|
||||
|
||||
static const versions = const [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
|
||||
static const versions = const [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
|
||||
}
|
||||
|
|
|
|||
3845
test/drift/twonly_database/generated/schema_v13.dart
Normal file
3845
test/drift/twonly_database/generated/schema_v13.dart
Normal file
File diff suppressed because it is too large
Load diff
3881
test/drift/twonly_database/generated/schema_v14.dart
Normal file
3881
test/drift/twonly_database/generated/schema_v14.dart
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue