Обновлен проект. Добавлена БД

This commit is contained in:
2025-03-03 23:57:55 +03:00
parent 273e68557a
commit cb6ce05059
726 changed files with 9424 additions and 478 deletions

View File

@@ -0,0 +1,3 @@
// We use a conditional export to expose the right connection factory depending
// on the platform.
export 'native.dart';

View File

@@ -0,0 +1,128 @@
// Dart imports:
import 'dart:io';
import 'dart:isolate';
// Flutter imports:
import 'package:flutter/foundation.dart' show kDebugMode;
// Package imports:
import 'package:drift/drift.dart';
import 'package:drift/isolate.dart';
import 'package:drift/native.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:remever/inject.dart';
import 'package:remever/services/core/enc_keys_service.dart';
/// Obtains a database connection for running drift in a Dart VM.
///
/// The [NativeDatabase] from drift will synchronously use sqlite3's C APIs.
/// To move synchronous database work off the main thread, we use a
/// [DriftIsolate], which can run queries in a background isolate under the
/// hood.
///
DatabaseConnection connect() {
return DatabaseConnection.delayed(
Future<DatabaseConnection>.sync(() async {
// Background isolates can't use platform channels, so let's use
// `path_provider` in the main isolate and just send the result containing
// the path over to the background isolate.
final Directory appDir = await getApplicationDocumentsDirectory();
final Directory dbDir = Directory(p.join(appDir.path, 'databases'));
if (!dbDir.existsSync()) {
await dbDir.create(recursive: true);
}
final String dbPath = p.join(appDir.path, 'databases', 'app.db.enc');
final EncKeysService encKeyService = getIt<EncKeysService>();
final String key = await encKeyService.getRawKey('db');
final ReceivePort receiveDriftIsolate = ReceivePort();
await Isolate.spawn(
_entrypointForDriftIsolate,
_IsolateStartRequest(receiveDriftIsolate.sendPort, dbPath, key),
);
final DriftIsolate driftIsolate =
await receiveDriftIsolate.first as DriftIsolate;
return driftIsolate.connect();
}),
);
}
/// The entrypoint of isolates can only take a single message, but we need two
/// (a send port to reach the originating isolate and the database's path that
/// should be opened on the background isolate). So, we bundle this information
/// in a single class.
class _IsolateStartRequest {
final SendPort talkToMain;
final String databasePath;
final String key;
_IsolateStartRequest(this.talkToMain, this.databasePath, this.key);
}
/// The entrypoint for a background isolate launching a drift server.
///
/// The main isolate can then connect to that isolate server to transparently
/// run queries in the background.
void _entrypointForDriftIsolate(_IsolateStartRequest request) {
/// @see https://drift.simonbinder.eu/docs/other-engines/encryption/
// open
// ..overrideFor(OperatingSystem.android, openCipherOnAndroid)
// ..overrideFor(
// OperatingSystem.linux,
// () => DynamicLibrary.open('libsqlcipher.so'),
// )
// ..overrideFor(
// OperatingSystem.windows,
// () => DynamicLibrary.open('sqlcipher.dll'),
// );
if (kDebugMode) {
print('[DRIFT] Path -> ${request.databasePath}');
}
// The native database synchronously uses sqlite3's C API with `dart:ffi` for
// a fast database implementation that doesn't require platform channels.
final NativeDatabase databaseImpl = NativeDatabase(
File(request.databasePath),
logStatements: false,
// setup: (Database db) {
// // Check that we're actually running with SQLCipher by quering the
// // cipher_version pragma.
// if (Platform.isAndroid) {
// final ResultSet result = db.select('pragma cipher_version');
// if (result.isEmpty) {
// throw UnsupportedError(
// 'This database needs to run with SQLCipher, but that library is '
// 'not available!',
// );
// }
// }
// // Then, apply the key to encrypt the database. Unfortunately, this
// // pragma doesn't seem to support prepared statements so we inline the
// // key.
// final String escapedKey = request.key.replaceAll("'", "''");
// db.execute("pragma key = '$escapedKey'");
// // Test that the key is correct by selecting from a table
// db.execute('select count(*) from sqlite_master');
// },
);
// We can use DriftIsolate.inCurrent because this function is the entrypoint
// of a background isolate itself.
final DriftIsolate driftServer = DriftIsolate.inCurrent(
() => DatabaseConnection(databaseImpl),
);
// Inform the main isolate about the server we just created.
request.talkToMain.send(driftServer);
}