improve media download handling in case of an error

This commit is contained in:
otsmr 2025-07-24 21:46:09 +02:00
parent fc7cb16271
commit 02045e8fc0
12 changed files with 3945 additions and 433 deletions

File diff suppressed because one or more lines are too long

View file

@ -1,43 +0,0 @@
import 'dart:convert';
import 'package:drift/drift.dart';
import 'package:twonly/src/database/tables/media_download_table.dart';
import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/utils/log.dart';
part 'media_downloads_dao.g.dart';
@DriftAccessor(tables: [MediaDownloads])
class MediaDownloadsDao extends DatabaseAccessor<TwonlyDatabase>
with _$MediaDownloadsDaoMixin {
MediaDownloadsDao(super.db);
Future<void> updateMediaDownload(
int messageId, MediaDownloadsCompanion updatedValues) {
return (update(mediaDownloads)..where((c) => c.messageId.equals(messageId)))
.write(updatedValues);
}
Future<int?> insertMediaDownload(MediaDownloadsCompanion values) async {
try {
return await into(mediaDownloads).insert(values);
} catch (e) {
Log.error('Error while inserting media upload: $e');
return null;
}
}
Future<void> deleteMediaDownload(int messageId) {
return (delete(mediaDownloads)..where((t) => t.messageId.equals(messageId)))
.go();
}
SingleOrNullSelectable<MediaDownload> getMediaDownloadById(int messageId) {
return select(mediaDownloads)..where((t) => t.messageId.equals(messageId));
}
SingleOrNullSelectable<MediaDownload> getMediaDownloadByDownloadToken(
List<int> downloadToken) {
return select(mediaDownloads)
..where((t) => t.downloadToken.equals(json.encode(downloadToken)));
}
}

View file

@ -1,8 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'media_downloads_dao.dart';
// ignore_for_file: type=lint
mixin _$MediaDownloadsDaoMixin on DatabaseAccessor<TwonlyDatabase> {
$MediaDownloadsTable get mediaDownloads => attachedDatabase.mediaDownloads;
}

View file

@ -1,8 +0,0 @@
import 'package:drift/drift.dart';
import 'package:twonly/src/database/tables/media_uploads_table.dart';
@DataClassName('MediaDownload')
class MediaDownloads extends Table {
IntColumn get messageId => integer()();
TextColumn get downloadToken => text().map(IntListTypeConverter())();
}

View file

@ -3,13 +3,11 @@ import 'package:drift_flutter/drift_flutter.dart'
show DriftNativeOptions, driftDatabase;
import 'package:path_provider/path_provider.dart';
import 'package:twonly/src/database/daos/contacts_dao.dart';
import 'package:twonly/src/database/daos/media_downloads_dao.dart';
import 'package:twonly/src/database/daos/media_uploads_dao.dart';
import 'package:twonly/src/database/daos/message_retransmissions.dao.dart';
import 'package:twonly/src/database/daos/messages_dao.dart';
import 'package:twonly/src/database/daos/signal_dao.dart';
import 'package:twonly/src/database/tables/contacts_table.dart';
import 'package:twonly/src/database/tables/media_download_table.dart';
import 'package:twonly/src/database/tables/media_uploads_table.dart';
import 'package:twonly/src/database/tables/message_retransmissions.dart';
import 'package:twonly/src/database/tables/messages_table.dart';
@ -29,7 +27,6 @@ part 'twonly_database.g.dart';
Contacts,
Messages,
MediaUploads,
MediaDownloads,
SignalIdentityKeyStores,
SignalPreKeyStores,
SignalSenderKeyStores,
@ -41,7 +38,6 @@ part 'twonly_database.g.dart';
MessagesDao,
ContactsDao,
MediaUploadsDao,
MediaDownloadsDao,
SignalDao,
MessageRetransmissionDao
])
@ -54,7 +50,7 @@ class TwonlyDatabase extends _$TwonlyDatabase {
TwonlyDatabase.forTesting(DatabaseConnection super.connection);
@override
int get schemaVersion => 15;
int get schemaVersion => 16;
static QueryExecutor _openConnection() {
return driftDatabase(
@ -91,7 +87,7 @@ class TwonlyDatabase extends _$TwonlyDatabase {
));
},
from4To5: (m, schema) async {
await m.createTable(mediaDownloads);
await m.createTable(schema.mediaDownloads);
await m.addColumn(schema.messages, schema.messages.mediaDownloadId);
await m.addColumn(schema.messages, schema.messages.mediaUploadId);
},
@ -140,6 +136,9 @@ class TwonlyDatabase extends _$TwonlyDatabase {
await m.addColumn(
schema.messages, schema.messages.mediaRetransmissionState);
},
from15To16: (m, schema) async {
await m.deleteTable('media_downloads');
},
),
);
}
@ -164,7 +163,6 @@ class TwonlyDatabase extends _$TwonlyDatabase {
Future<void> deleteDataForTwonlySafe() async {
await delete(messages).go();
await delete(messageRetransmissions).go();
await delete(mediaDownloads).go();
await delete(mediaUploads).go();
await update(contacts).write(
const ContactsCompanion(

View file

@ -2341,206 +2341,6 @@ class MediaUploadsCompanion extends UpdateCompanion<MediaUpload> {
}
}
class $MediaDownloadsTable extends MediaDownloads
with TableInfo<$MediaDownloadsTable, MediaDownload> {
@override
final GeneratedDatabase attachedDatabase;
final String? _alias;
$MediaDownloadsTable(this.attachedDatabase, [this._alias]);
static const VerificationMeta _messageIdMeta =
const VerificationMeta('messageId');
@override
late final GeneratedColumn<int> messageId = GeneratedColumn<int>(
'message_id', aliasedName, false,
type: DriftSqlType.int, requiredDuringInsert: true);
@override
late final GeneratedColumnWithTypeConverter<List<int>, String> downloadToken =
GeneratedColumn<String>('download_token', aliasedName, false,
type: DriftSqlType.string, requiredDuringInsert: true)
.withConverter<List<int>>(
$MediaDownloadsTable.$converterdownloadToken);
@override
List<GeneratedColumn> get $columns => [messageId, downloadToken];
@override
String get aliasedName => _alias ?? actualTableName;
@override
String get actualTableName => $name;
static const String $name = 'media_downloads';
@override
VerificationContext validateIntegrity(Insertable<MediaDownload> instance,
{bool isInserting = false}) {
final context = VerificationContext();
final data = instance.toColumns(true);
if (data.containsKey('message_id')) {
context.handle(_messageIdMeta,
messageId.isAcceptableOrUnknown(data['message_id']!, _messageIdMeta));
} else if (isInserting) {
context.missing(_messageIdMeta);
}
return context;
}
@override
Set<GeneratedColumn> get $primaryKey => const {};
@override
MediaDownload map(Map<String, dynamic> data, {String? tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
return MediaDownload(
messageId: attachedDatabase.typeMapping
.read(DriftSqlType.int, data['${effectivePrefix}message_id'])!,
downloadToken: $MediaDownloadsTable.$converterdownloadToken.fromSql(
attachedDatabase.typeMapping.read(
DriftSqlType.string, data['${effectivePrefix}download_token'])!),
);
}
@override
$MediaDownloadsTable createAlias(String alias) {
return $MediaDownloadsTable(attachedDatabase, alias);
}
static TypeConverter<List<int>, String> $converterdownloadToken =
IntListTypeConverter();
}
class MediaDownload extends DataClass implements Insertable<MediaDownload> {
final int messageId;
final List<int> downloadToken;
const MediaDownload({required this.messageId, required this.downloadToken});
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
map['message_id'] = Variable<int>(messageId);
{
map['download_token'] = Variable<String>(
$MediaDownloadsTable.$converterdownloadToken.toSql(downloadToken));
}
return map;
}
MediaDownloadsCompanion toCompanion(bool nullToAbsent) {
return MediaDownloadsCompanion(
messageId: Value(messageId),
downloadToken: Value(downloadToken),
);
}
factory MediaDownload.fromJson(Map<String, dynamic> json,
{ValueSerializer? serializer}) {
serializer ??= driftRuntimeOptions.defaultSerializer;
return MediaDownload(
messageId: serializer.fromJson<int>(json['messageId']),
downloadToken: serializer.fromJson<List<int>>(json['downloadToken']),
);
}
@override
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
serializer ??= driftRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'messageId': serializer.toJson<int>(messageId),
'downloadToken': serializer.toJson<List<int>>(downloadToken),
};
}
MediaDownload copyWith({int? messageId, List<int>? downloadToken}) =>
MediaDownload(
messageId: messageId ?? this.messageId,
downloadToken: downloadToken ?? this.downloadToken,
);
MediaDownload copyWithCompanion(MediaDownloadsCompanion data) {
return MediaDownload(
messageId: data.messageId.present ? data.messageId.value : this.messageId,
downloadToken: data.downloadToken.present
? data.downloadToken.value
: this.downloadToken,
);
}
@override
String toString() {
return (StringBuffer('MediaDownload(')
..write('messageId: $messageId, ')
..write('downloadToken: $downloadToken')
..write(')'))
.toString();
}
@override
int get hashCode => Object.hash(messageId, downloadToken);
@override
bool operator ==(Object other) =>
identical(this, other) ||
(other is MediaDownload &&
other.messageId == this.messageId &&
other.downloadToken == this.downloadToken);
}
class MediaDownloadsCompanion extends UpdateCompanion<MediaDownload> {
final Value<int> messageId;
final Value<List<int>> downloadToken;
final Value<int> rowid;
const MediaDownloadsCompanion({
this.messageId = const Value.absent(),
this.downloadToken = const Value.absent(),
this.rowid = const Value.absent(),
});
MediaDownloadsCompanion.insert({
required int messageId,
required List<int> downloadToken,
this.rowid = const Value.absent(),
}) : messageId = Value(messageId),
downloadToken = Value(downloadToken);
static Insertable<MediaDownload> custom({
Expression<int>? messageId,
Expression<String>? downloadToken,
Expression<int>? rowid,
}) {
return RawValuesInsertable({
if (messageId != null) 'message_id': messageId,
if (downloadToken != null) 'download_token': downloadToken,
if (rowid != null) 'rowid': rowid,
});
}
MediaDownloadsCompanion copyWith(
{Value<int>? messageId,
Value<List<int>>? downloadToken,
Value<int>? rowid}) {
return MediaDownloadsCompanion(
messageId: messageId ?? this.messageId,
downloadToken: downloadToken ?? this.downloadToken,
rowid: rowid ?? this.rowid,
);
}
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
if (messageId.present) {
map['message_id'] = Variable<int>(messageId.value);
}
if (downloadToken.present) {
map['download_token'] = Variable<String>($MediaDownloadsTable
.$converterdownloadToken
.toSql(downloadToken.value));
}
if (rowid.present) {
map['rowid'] = Variable<int>(rowid.value);
}
return map;
}
@override
String toString() {
return (StringBuffer('MediaDownloadsCompanion(')
..write('messageId: $messageId, ')
..write('downloadToken: $downloadToken, ')
..write('rowid: $rowid')
..write(')'))
.toString();
}
}
class $SignalIdentityKeyStoresTable extends SignalIdentityKeyStores
with TableInfo<$SignalIdentityKeyStoresTable, SignalIdentityKeyStore> {
@override
@ -4568,7 +4368,6 @@ abstract class _$TwonlyDatabase extends GeneratedDatabase {
late final $ContactsTable contacts = $ContactsTable(this);
late final $MessagesTable messages = $MessagesTable(this);
late final $MediaUploadsTable mediaUploads = $MediaUploadsTable(this);
late final $MediaDownloadsTable mediaDownloads = $MediaDownloadsTable(this);
late final $SignalIdentityKeyStoresTable signalIdentityKeyStores =
$SignalIdentityKeyStoresTable(this);
late final $SignalPreKeyStoresTable signalPreKeyStores =
@ -4587,8 +4386,6 @@ abstract class _$TwonlyDatabase extends GeneratedDatabase {
late final ContactsDao contactsDao = ContactsDao(this as TwonlyDatabase);
late final MediaUploadsDao mediaUploadsDao =
MediaUploadsDao(this as TwonlyDatabase);
late final MediaDownloadsDao mediaDownloadsDao =
MediaDownloadsDao(this as TwonlyDatabase);
late final SignalDao signalDao = SignalDao(this as TwonlyDatabase);
late final MessageRetransmissionDao messageRetransmissionDao =
MessageRetransmissionDao(this as TwonlyDatabase);
@ -4600,7 +4397,6 @@ abstract class _$TwonlyDatabase extends GeneratedDatabase {
contacts,
messages,
mediaUploads,
mediaDownloads,
signalIdentityKeyStores,
signalPreKeyStores,
signalSenderKeyStores,
@ -5999,139 +5795,6 @@ typedef $$MediaUploadsTableProcessedTableManager = ProcessedTableManager<
),
MediaUpload,
PrefetchHooks Function()>;
typedef $$MediaDownloadsTableCreateCompanionBuilder = MediaDownloadsCompanion
Function({
required int messageId,
required List<int> downloadToken,
Value<int> rowid,
});
typedef $$MediaDownloadsTableUpdateCompanionBuilder = MediaDownloadsCompanion
Function({
Value<int> messageId,
Value<List<int>> downloadToken,
Value<int> rowid,
});
class $$MediaDownloadsTableFilterComposer
extends Composer<_$TwonlyDatabase, $MediaDownloadsTable> {
$$MediaDownloadsTableFilterComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
ColumnFilters<int> get messageId => $composableBuilder(
column: $table.messageId, builder: (column) => ColumnFilters(column));
ColumnWithTypeConverterFilters<List<int>, List<int>, String>
get downloadToken => $composableBuilder(
column: $table.downloadToken,
builder: (column) => ColumnWithTypeConverterFilters(column));
}
class $$MediaDownloadsTableOrderingComposer
extends Composer<_$TwonlyDatabase, $MediaDownloadsTable> {
$$MediaDownloadsTableOrderingComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
ColumnOrderings<int> get messageId => $composableBuilder(
column: $table.messageId, builder: (column) => ColumnOrderings(column));
ColumnOrderings<String> get downloadToken => $composableBuilder(
column: $table.downloadToken,
builder: (column) => ColumnOrderings(column));
}
class $$MediaDownloadsTableAnnotationComposer
extends Composer<_$TwonlyDatabase, $MediaDownloadsTable> {
$$MediaDownloadsTableAnnotationComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
GeneratedColumn<int> get messageId =>
$composableBuilder(column: $table.messageId, builder: (column) => column);
GeneratedColumnWithTypeConverter<List<int>, String> get downloadToken =>
$composableBuilder(
column: $table.downloadToken, builder: (column) => column);
}
class $$MediaDownloadsTableTableManager extends RootTableManager<
_$TwonlyDatabase,
$MediaDownloadsTable,
MediaDownload,
$$MediaDownloadsTableFilterComposer,
$$MediaDownloadsTableOrderingComposer,
$$MediaDownloadsTableAnnotationComposer,
$$MediaDownloadsTableCreateCompanionBuilder,
$$MediaDownloadsTableUpdateCompanionBuilder,
(
MediaDownload,
BaseReferences<_$TwonlyDatabase, $MediaDownloadsTable, MediaDownload>
),
MediaDownload,
PrefetchHooks Function()> {
$$MediaDownloadsTableTableManager(
_$TwonlyDatabase db, $MediaDownloadsTable table)
: super(TableManagerState(
db: db,
table: table,
createFilteringComposer: () =>
$$MediaDownloadsTableFilterComposer($db: db, $table: table),
createOrderingComposer: () =>
$$MediaDownloadsTableOrderingComposer($db: db, $table: table),
createComputedFieldComposer: () =>
$$MediaDownloadsTableAnnotationComposer($db: db, $table: table),
updateCompanionCallback: ({
Value<int> messageId = const Value.absent(),
Value<List<int>> downloadToken = const Value.absent(),
Value<int> rowid = const Value.absent(),
}) =>
MediaDownloadsCompanion(
messageId: messageId,
downloadToken: downloadToken,
rowid: rowid,
),
createCompanionCallback: ({
required int messageId,
required List<int> downloadToken,
Value<int> rowid = const Value.absent(),
}) =>
MediaDownloadsCompanion.insert(
messageId: messageId,
downloadToken: downloadToken,
rowid: rowid,
),
withReferenceMapper: (p0) => p0
.map((e) => (e.readTable(table), BaseReferences(db, table, e)))
.toList(),
prefetchHooksCallback: null,
));
}
typedef $$MediaDownloadsTableProcessedTableManager = ProcessedTableManager<
_$TwonlyDatabase,
$MediaDownloadsTable,
MediaDownload,
$$MediaDownloadsTableFilterComposer,
$$MediaDownloadsTableOrderingComposer,
$$MediaDownloadsTableAnnotationComposer,
$$MediaDownloadsTableCreateCompanionBuilder,
$$MediaDownloadsTableUpdateCompanionBuilder,
(
MediaDownload,
BaseReferences<_$TwonlyDatabase, $MediaDownloadsTable, MediaDownload>
),
MediaDownload,
PrefetchHooks Function()>;
typedef $$SignalIdentityKeyStoresTableCreateCompanionBuilder
= SignalIdentityKeyStoresCompanion Function({
required int deviceId,
@ -7481,8 +7144,6 @@ class $TwonlyDatabaseManager {
$$MessagesTableTableManager(_db, _db.messages);
$$MediaUploadsTableTableManager get mediaUploads =>
$$MediaUploadsTableTableManager(_db, _db.mediaUploads);
$$MediaDownloadsTableTableManager get mediaDownloads =>
$$MediaDownloadsTableTableManager(_db, _db.mediaDownloads);
$$SignalIdentityKeyStoresTableTableManager get signalIdentityKeyStores =>
$$SignalIdentityKeyStoresTableTableManager(
_db, _db.signalIdentityKeyStores);

View file

@ -3497,6 +3497,222 @@ class Shape20 extends i0.VersionedTable {
columnsByName['encryption_data']! as i1.GeneratedColumn<String>;
}
final class Schema16 extends i0.VersionedSchema {
Schema16({required super.database}) : super(version: 16);
@override
late final List<i1.DatabaseSchemaEntity> entities = [
contacts,
messages,
mediaUploads,
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 Shape19 messages = Shape19(
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_70,
_column_26,
_column_27,
_column_28,
_column_29,
_column_30,
],
attachedDatabase: database,
),
alias: null);
late final Shape20 mediaUploads = Shape20(
source: i0.VersionedTable(
entityName: 'media_uploads',
withoutRowId: false,
isStrict: false,
tableConstraints: [],
columns: [
_column_41,
_column_42,
_column_56,
_column_44,
_column_45,
],
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);
}
i0.MigrationStepWithVersion migrationSteps({
required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
@ -3512,6 +3728,7 @@ i0.MigrationStepWithVersion migrationSteps({
required Future<void> Function(i1.Migrator m, Schema13 schema) from12To13,
required Future<void> Function(i1.Migrator m, Schema14 schema) from13To14,
required Future<void> Function(i1.Migrator m, Schema15 schema) from14To15,
required Future<void> Function(i1.Migrator m, Schema16 schema) from15To16,
}) {
return (currentVersion, database) async {
switch (currentVersion) {
@ -3585,6 +3802,11 @@ i0.MigrationStepWithVersion migrationSteps({
final migrator = i1.Migrator(database, schema);
await from14To15(migrator, schema);
return 15;
case 15:
final schema = Schema16(database: database);
final migrator = i1.Migrator(database, schema);
await from15To16(migrator, schema);
return 16;
default:
throw ArgumentError.value('Unknown migration from $currentVersion');
}
@ -3606,6 +3828,7 @@ i1.OnUpgrade stepByStep({
required Future<void> Function(i1.Migrator m, Schema13 schema) from12To13,
required Future<void> Function(i1.Migrator m, Schema14 schema) from13To14,
required Future<void> Function(i1.Migrator m, Schema15 schema) from14To15,
required Future<void> Function(i1.Migrator m, Schema16 schema) from15To16,
}) =>
i0.VersionedSchema.stepByStepHelper(
step: migrationSteps(
@ -3623,4 +3846,5 @@ i1.OnUpgrade stepByStep({
from12To13: from12To13,
from13To14: from13To14,
from14To15: from14To15,
from15To16: from15To16,
));

View file

@ -120,32 +120,34 @@ Future<void> handleDownloadStatusUpdateInternal(
Mutex protectDownload = Mutex();
Future<void> startDownloadMedia(Message message, bool force) async {
if (message.contentJson == null) return;
final content = MessageContent.fromJson(
message.kind, jsonDecode(message.contentJson!) as Map);
if (content is! MediaMessageContent) return;
if (content.downloadToken == null) return;
var media = await twonlyDB.mediaDownloadsDao
.getMediaDownloadById(message.messageId)
.getSingleOrNull();
if (media == null) {
await twonlyDB.mediaDownloadsDao.insertMediaDownload(
MediaDownloadsCompanion(
messageId: Value(message.messageId),
downloadToken: Value(content.downloadToken!),
),
);
media = await twonlyDB.mediaDownloadsDao
.getMediaDownloadById(message.messageId)
.getSingleOrNull();
Log.info(
'Download blocked for ${message.messageId} because of network state.');
if (message.contentJson == null) {
Log.error('Content of ${message.messageId} not found.');
await handleMediaError(message);
return;
}
if (media == null) return;
final content = MessageContent.fromJson(
message.kind,
jsonDecode(message.contentJson!) as Map,
);
if (content is! MediaMessageContent) {
Log.error('Content of ${message.messageId} is not media file.');
await handleMediaError(message);
return;
}
if (content.downloadToken == null) {
Log.error('Download token not defined for ${message.messageId}.');
await handleMediaError(message);
return;
}
if (!force && !await isAllowedToDownload(content.isVideo)) {
Log.warn(
'Download blocked for ${message.messageId} because of network state.');
return;
}
@ -185,10 +187,10 @@ Future<void> startDownloadMedia(Message message, bool force) async {
try {
final task = DownloadTask(
url: apiUrl,
taskId: 'download_${media.messageId}',
taskId: 'download_${message.messageId}',
directory: 'media/received/',
baseDirectory: BaseDirectory.applicationSupport,
filename: '${media.messageId}.encrypted',
filename: '${message.messageId}.encrypted',
priority: 0,
retries: 10,
);
@ -198,7 +200,7 @@ Future<void> startDownloadMedia(Message message, bool force) async {
);
try {
await downloadFileFast(media.messageId, apiUrl);
await downloadFileFast(message.messageId, apiUrl);
} catch (e) {
Log.error('Fast download failed: $e');
await FileDownloader().enqueue(task);

View file

@ -555,8 +555,9 @@ Future<void> handleMediaUpload(MediaUpload media) async {
timestamp: media.metadata!.messageSendAt,
);
final plaintextContent =
Uint8List.fromList(gzip.encode(utf8.encode(jsonEncode(msg.toJson()))));
final plaintextContent = Uint8List.fromList(
gzip.encode(utf8.encode(jsonEncode(msg.toJson()))),
);
final contact = await twonlyDB.contactsDao
.getContactByUserId(message.contactId)

View file

@ -398,9 +398,12 @@ Future<client.Response> handleNewMessage(int fromUserId, Uint8List body) async {
);
if (messageId == null) {
Log.error('could not insert message into db');
return client.Response()..error = ErrorCode.InternalError;
}
Log.info('Inserted a new message with id: $messageId');
if (message.kind == MessageKind.media) {
await twonlyDB.contactsDao.incFlameCounter(
fromUserId,

View file

@ -18,6 +18,7 @@ import 'schema_v12.dart' as v12;
import 'schema_v13.dart' as v13;
import 'schema_v14.dart' as v14;
import 'schema_v15.dart' as v15;
import 'schema_v16.dart' as v16;
class GeneratedHelper implements SchemaInstantiationHelper {
@override
@ -53,6 +54,8 @@ class GeneratedHelper implements SchemaInstantiationHelper {
return v14.DatabaseAtV14(db);
case 15:
return v15.DatabaseAtV15(db);
case 16:
return v16.DatabaseAtV16(db);
default:
throw MissingSchemaException(version, versions);
}
@ -73,6 +76,7 @@ class GeneratedHelper implements SchemaInstantiationHelper {
12,
13,
14,
15
15,
16
];
}

File diff suppressed because it is too large Load diff