Merge pull request #1754 from famedly/krille/move-file-storage-to-mixin

refactor: Move file storage to mixin to not import dart:io
This commit is contained in:
Krille-chan 2024-04-12 11:11:45 +02:00 committed by GitHub
commit 4ef461bb79
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 130 additions and 54 deletions

View File

@ -47,6 +47,11 @@ jobs:
rm -r example rm -r example
./scripts/prepare.sh ./scripts/prepare.sh
./scripts/test.sh ./scripts/test.sh
- name: Ensure SDK compiles on web
run: |
pushd web_test
dart pub get
dart run webdev build
coverage_without_olm: coverage_without_olm:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@ -0,0 +1,55 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:matrix/matrix.dart';
mixin DatabaseFileStorage {
bool get supportsFileStoring => fileStorageLocation != null;
late final Uri? fileStorageLocation;
late final Duration? deleteFilesAfterDuration;
Future<void> storeFile(Uri mxcUri, Uint8List bytes, int time) async {
final fileStorageLocation = this.fileStorageLocation;
if (!supportsFileStoring || fileStorageLocation == null) return;
final dir = Directory.fromUri(fileStorageLocation);
final file = File('${dir.path}/${mxcUri.toString().split('/').last}');
if (await file.exists()) return;
await file.writeAsBytes(bytes);
}
Future<Uint8List?> getFile(Uri mxcUri) async {
final fileStorageLocation = this.fileStorageLocation;
if (!supportsFileStoring || fileStorageLocation == null) return null;
final dir = Directory.fromUri(fileStorageLocation);
final file = File('${dir.path}/${mxcUri.toString().split('/').last}');
if (await file.exists()) return await file.readAsBytes();
return null;
}
Future<void> deleteOldFiles(int savedAt) async {
final dirUri = fileStorageLocation;
final deleteFilesAfterDuration = this.deleteFilesAfterDuration;
if (!supportsFileStoring ||
dirUri == null ||
deleteFilesAfterDuration == null) {
return;
}
final dir = Directory.fromUri(dirUri);
final entities = await dir.list().toList();
for (final file in entities) {
if (file is! File) continue;
final stat = await file.stat();
if (DateTime.now().difference(stat.modified) > deleteFilesAfterDuration) {
Logs().v('Delete old file', file.path);
await file.delete();
}
}
}
}

View File

@ -0,0 +1,20 @@
import 'dart:typed_data';
mixin DatabaseFileStorage {
bool get supportsFileStoring => false;
late final Uri? fileStorageLocation;
late final Duration? deleteFilesAfterDuration;
Future<void> storeFile(Uri mxcUri, Uint8List bytes, int time) async {
return;
}
Future<Uint8List?> getFile(Uri mxcUri) async {
return null;
}
Future<void> deleteOldFiles(int savedAt) async {
return;
}
}

View File

@ -18,9 +18,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'dart:typed_data';
import 'package:sqflite_common/sqflite.dart'; import 'package:sqflite_common/sqflite.dart';
@ -36,6 +34,9 @@ import 'package:matrix/src/utils/run_benchmarked.dart';
import 'package:matrix/src/database/indexeddb_box.dart' import 'package:matrix/src/database/indexeddb_box.dart'
if (dart.library.io) 'package:matrix/src/database/sqflite_box.dart'; if (dart.library.io) 'package:matrix/src/database/sqflite_box.dart';
import 'package:matrix/src/database/database_file_storage_stub.dart'
if (dart.library.io) 'package:matrix/src/database/database_file_storage_io.dart';
/// Database based on SQlite3 on native and IndexedDB on web. For native you /// Database based on SQlite3 on native and IndexedDB on web. For native you
/// have to pass a `Database` object, which can be created with the sqflite /// have to pass a `Database` object, which can be created with the sqflite
/// package like this: /// package like this:
@ -50,7 +51,7 @@ import 'package:matrix/src/database/indexeddb_box.dart'
/// [sqflite_common_ffi](https://pub.dev/packages/sqflite_common_ffi). /// [sqflite_common_ffi](https://pub.dev/packages/sqflite_common_ffi).
/// Learn more at: /// Learn more at:
/// https://github.com/famedly/matrix-dart-sdk/issues/1642#issuecomment-1865827227 /// https://github.com/famedly/matrix-dart-sdk/issues/1642#issuecomment-1865827227
class MatrixSdkDatabase extends DatabaseApi { class MatrixSdkDatabase extends DatabaseApi with DatabaseFileStorage {
static const int version = 7; static const int version = 7;
final String name; final String name;
late BoxCollection _collection; late BoxCollection _collection;
@ -100,12 +101,15 @@ class MatrixSdkDatabase extends DatabaseApi {
late Box<String> _seenDeviceIdsBox; late Box<String> _seenDeviceIdsBox;
late Box<String> _seenDeviceKeysBox; late Box<String> _seenDeviceKeysBox;
@override
bool get supportsFileStoring => fileStoragePath != null;
@override @override
final int maxFileSize; final int maxFileSize;
final Directory? fileStoragePath;
final Duration? deleteFilesAfterDuration; // there was a field of type `dart:io:Directory` here. This one broke the
// dart js standalone compiler. Migration via URI as file system identifier.
@Deprecated(
'Breaks support for web standalone. Use [fileStorageLocation] instead.')
Object? get fileStoragePath => fileStorageLocation?.toFilePath();
static const String _clientBoxName = 'box_client'; static const String _clientBoxName = 'box_client';
@ -168,9 +172,18 @@ class MatrixSdkDatabase extends DatabaseApi {
this.idbFactory, this.idbFactory,
this.sqfliteFactory, this.sqfliteFactory,
this.maxFileSize = 0, this.maxFileSize = 0,
this.fileStoragePath, // TODO : remove deprecated member migration on next major release
this.deleteFilesAfterDuration, @Deprecated(
}); 'Breaks support for web standalone. Use [fileStorageLocation] instead.')
dynamic fileStoragePath,
Uri? fileStorageLocation,
Duration? deleteFilesAfterDuration,
}) {
final legacyPath = fileStoragePath?.path;
this.fileStorageLocation = fileStorageLocation ??
(legacyPath is String ? Uri.tryParse(legacyPath) : null);
this.deleteFilesAfterDuration = deleteFilesAfterDuration;
}
Future<void> open() async { Future<void> open() async {
_collection = await BoxCollection.open( _collection = await BoxCollection.open(
@ -309,26 +322,6 @@ class MatrixSdkDatabase extends DatabaseApi {
return; return;
} }
@override
Future<void> deleteOldFiles(int savedAt) async {
final dir = fileStoragePath;
final deleteFilesAfterDuration = this.deleteFilesAfterDuration;
if (!supportsFileStoring ||
dir == null ||
deleteFilesAfterDuration == null) {
return;
}
final entities = await dir.list().toList();
for (final file in entities) {
if (file is! File) continue;
final stat = await file.stat();
if (DateTime.now().difference(stat.modified) > deleteFilesAfterDuration) {
Logs().v('Delete old file', file.path);
await file.delete();
}
}
}
@override @override
Future<void> forgetRoom(String roomId) async { Future<void> forgetRoom(String roomId) async {
await _timelineFragmentsBox.delete(TupleKey(roomId, '').toString()); await _timelineFragmentsBox.delete(TupleKey(roomId, '').toString());
@ -451,18 +444,6 @@ class MatrixSdkDatabase extends DatabaseApi {
return await _getEventsByIds(eventIds.cast<String>(), room); return await _getEventsByIds(eventIds.cast<String>(), room);
}); });
@override
Future<Uint8List?> getFile(Uri mxcUri) async {
final fileStoragePath = this.fileStoragePath;
if (!supportsFileStoring || fileStoragePath == null) return null;
final file =
File('${fileStoragePath.path}/${mxcUri.toString().split('/').last}');
if (await file.exists()) return await file.readAsBytes();
return null;
}
@override @override
Future<StoredInboundGroupSession?> getInboundGroupSession( Future<StoredInboundGroupSession?> getInboundGroupSession(
String roomId, String roomId,
@ -1136,18 +1117,6 @@ class MatrixSdkDatabase extends DatabaseApi {
} }
} }
@override
Future<void> storeFile(Uri mxcUri, Uint8List bytes, int time) async {
final fileStoragePath = this.fileStoragePath;
if (!supportsFileStoring || fileStoragePath == null) return;
final file =
File('${fileStoragePath.path}/${mxcUri.toString().split('/').last}');
if (await file.exists()) return;
await file.writeAsBytes(bytes);
}
@override @override
Future<void> storeInboundGroupSession( Future<void> storeInboundGroupSession(
String roomId, String roomId,

3
web_test/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# https://dart.dev/guides/libraries/private-files
# Created by `dart pub`
.dart_tool/

1
web_test/README.md Normal file
View File

@ -0,0 +1 @@
This is a bare-bone sample project in order to ensure webdev can compile the SDK.

17
web_test/pubspec.yaml Normal file
View File

@ -0,0 +1,17 @@
name: web_test
description: A test project for the webdev compiler.
version: 1.0.0
publish_to: none
environment:
sdk: ^3.2.0
# Add regular dependencies here.
dependencies:
matrix:
path: ..
dev_dependencies:
build_runner: ^2.4.9
build_web_compilers: ^4.0.10
webdev: ^3.4.0

6
web_test/web/main.dart Normal file
View File

@ -0,0 +1,6 @@
import 'package:matrix/matrix.dart';
Future<void> main() async {
final client = Client('web_test');
await client.init();
}