mirror of
https://github.com/immich-app/immich
synced 2025-11-14 17:36:12 +00:00
refactor(mobile): migrate all Hive boxes to Isar database (#2036)
This commit is contained in:
parent
0616a66b05
commit
eccde8fa07
33 changed files with 1540 additions and 383 deletions
|
|
@ -1,8 +1,7 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:immich_mobile/constants/hive_box.dart';
|
||||
import 'package:immich_mobile/shared/models/store.dart';
|
||||
import 'package:immich_mobile/utils/url_helper.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
|
@ -19,13 +18,9 @@ class ApiService {
|
|||
late DeviceInfoApi deviceInfoApi;
|
||||
|
||||
ApiService() {
|
||||
if (Hive.isBoxOpen(userInfoBox)) {
|
||||
final endpoint = Hive.box(userInfoBox).get(serverEndpointKey) as String?;
|
||||
if (endpoint != null && endpoint.isNotEmpty) {
|
||||
setEndpoint(endpoint);
|
||||
}
|
||||
} else {
|
||||
debugPrint("Cannot init ApiServer endpoint, userInfoBox not open yet.");
|
||||
final endpoint = Store.tryGet(StoreKey.serverEndpoint);
|
||||
if (endpoint != null && endpoint.isNotEmpty) {
|
||||
setEndpoint(endpoint);
|
||||
}
|
||||
}
|
||||
String? _authToken;
|
||||
|
|
@ -49,7 +44,7 @@ class ApiService {
|
|||
setEndpoint(endpoint);
|
||||
|
||||
// Save in hivebox for next startup
|
||||
Hive.box(userInfoBox).put(serverEndpointKey, endpoint);
|
||||
Store.put(StoreKey.serverEndpoint, endpoint);
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||
import 'package:immich_mobile/shared/models/asset.dart';
|
||||
import 'package:immich_mobile/shared/models/exif_info.dart';
|
||||
import 'package:immich_mobile/shared/models/store.dart';
|
||||
import 'package:immich_mobile/shared/models/user.dart';
|
||||
import 'package:immich_mobile/shared/providers/api.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/db.provider.dart';
|
||||
import 'package:immich_mobile/shared/services/api.service.dart';
|
||||
|
|
@ -44,7 +43,7 @@ class AssetService {
|
|||
.where()
|
||||
.remoteIdIsNotNull()
|
||||
.filter()
|
||||
.ownerIdEqualTo(Store.get<User>(StoreKey.currentUser)!.isarId)
|
||||
.ownerIdEqualTo(Store.get(StoreKey.currentUser).isarId)
|
||||
.count();
|
||||
final List<AssetResponseDto>? dtos =
|
||||
await _getRemoteAssets(hasCache: numOwnedRemoteAssets > 0);
|
||||
|
|
@ -63,7 +62,7 @@ class AssetService {
|
|||
required bool hasCache,
|
||||
}) async {
|
||||
try {
|
||||
final etag = hasCache ? Store.get(StoreKey.assetETag) : null;
|
||||
final etag = hasCache ? Store.tryGet(StoreKey.assetETag) : null;
|
||||
final Pair<List<AssetResponseDto>, String?>? remote =
|
||||
await _apiService.assetApi.getAllAssetsWithETag(eTag: etag);
|
||||
if (remote == null) {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:immich_mobile/constants/hive_box.dart';
|
||||
import 'package:immich_mobile/shared/models/immich_logger_message.model.dart';
|
||||
import 'package:immich_mobile/shared/models/logger_message.model.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
/// [ImmichLogger] is a custom logger that is built on top of the [logging] package.
|
||||
/// The logs are written to a Hive box and onto console, using `debugPrint` method.
|
||||
/// The logs are written to the database and onto console, using `debugPrint` method.
|
||||
///
|
||||
/// The logs are deleted when exceeding the `maxLogEntries` (default 200) property
|
||||
/// in the class.
|
||||
|
|
@ -17,48 +17,61 @@ import 'package:share_plus/share_plus.dart';
|
|||
/// Logs can be shared by calling the `shareLogs` method, which will open a share dialog
|
||||
/// and generate a csv file.
|
||||
class ImmichLogger {
|
||||
static final ImmichLogger _instance = ImmichLogger._internal();
|
||||
final maxLogEntries = 200;
|
||||
final Box<ImmichLoggerMessage> _box = Hive.box(immichLoggerBox);
|
||||
final Isar _db = Isar.getInstance()!;
|
||||
final List<LoggerMessage> _msgBuffer = [];
|
||||
Timer? _timer;
|
||||
|
||||
List<ImmichLoggerMessage> get messages =>
|
||||
_box.values.toList().reversed.toList();
|
||||
factory ImmichLogger() => _instance;
|
||||
|
||||
ImmichLogger() {
|
||||
ImmichLogger._internal() {
|
||||
_removeOverflowMessages();
|
||||
}
|
||||
|
||||
init() {
|
||||
Logger.root.level = Level.INFO;
|
||||
Logger.root.onRecord.listen(_writeLogToHiveBox);
|
||||
Logger.root.onRecord.listen(_writeLogToDatabase);
|
||||
}
|
||||
|
||||
_removeOverflowMessages() {
|
||||
if (_box.length > maxLogEntries) {
|
||||
var numberOfEntryToBeDeleted = _box.length - maxLogEntries;
|
||||
for (var i = 0; i < numberOfEntryToBeDeleted; i++) {
|
||||
_box.deleteAt(0);
|
||||
}
|
||||
List<LoggerMessage> get messages {
|
||||
final inDb =
|
||||
_db.loggerMessages.where(sort: Sort.desc).anyId().findAllSync();
|
||||
return _msgBuffer.isEmpty ? inDb : _msgBuffer.reversed.toList() + inDb;
|
||||
}
|
||||
|
||||
void _removeOverflowMessages() {
|
||||
final msgCount = _db.loggerMessages.countSync();
|
||||
if (msgCount > maxLogEntries) {
|
||||
final numberOfEntryToBeDeleted = msgCount - maxLogEntries;
|
||||
_db.loggerMessages.where().limit(numberOfEntryToBeDeleted).deleteAll();
|
||||
}
|
||||
}
|
||||
|
||||
_writeLogToHiveBox(LogRecord record) {
|
||||
final Box<ImmichLoggerMessage> box = Hive.box(immichLoggerBox);
|
||||
var formattedMessage = record.message;
|
||||
|
||||
void _writeLogToDatabase(LogRecord record) {
|
||||
debugPrint('[${record.level.name}] [${record.time}] ${record.message}');
|
||||
box.add(
|
||||
ImmichLoggerMessage(
|
||||
message: formattedMessage,
|
||||
level: record.level.name,
|
||||
createdAt: record.time,
|
||||
context1: record.loggerName,
|
||||
context2: record.stackTrace?.toString(),
|
||||
),
|
||||
final lm = LoggerMessage(
|
||||
message: record.message,
|
||||
level: record.level.toLogLevel(),
|
||||
createdAt: record.time,
|
||||
context1: record.loggerName,
|
||||
context2: record.stackTrace?.toString(),
|
||||
);
|
||||
_msgBuffer.add(lm);
|
||||
|
||||
// delayed batch writing to database: increases performance when logging
|
||||
// messages in quick succession and reduces NAND wear
|
||||
_timer ??= Timer(const Duration(seconds: 5), _flushBufferToDatabase);
|
||||
}
|
||||
|
||||
void _flushBufferToDatabase() {
|
||||
_timer = null;
|
||||
_db.writeTxnSync(() => _db.loggerMessages.putAllSync(_msgBuffer));
|
||||
_msgBuffer.clear();
|
||||
}
|
||||
|
||||
void clearLogs() {
|
||||
_box.clear();
|
||||
_timer?.cancel();
|
||||
_timer = null;
|
||||
_msgBuffer.clear();
|
||||
_db.writeTxn(() => _db.loggerMessages.clear());
|
||||
}
|
||||
|
||||
Future<void> shareLogs() async {
|
||||
|
|
@ -93,4 +106,12 @@ class ImmichLogger {
|
|||
// Clean up temp file
|
||||
await logFile.delete();
|
||||
}
|
||||
|
||||
/// Flush pending log messages to persistent storage
|
||||
void flush() {
|
||||
if (_timer != null) {
|
||||
_timer!.cancel();
|
||||
_flushBufferToDatabase();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ class SyncService {
|
|||
}
|
||||
|
||||
if (album.shared || dto.shared) {
|
||||
final userId = Store.get<User>(StoreKey.currentUser)!.isarId;
|
||||
final userId = Store.get(StoreKey.currentUser).isarId;
|
||||
final foreign =
|
||||
await album.assets.filter().not().ownerIdEqualTo(userId).findAll();
|
||||
existing.addAll(foreign);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class UserService {
|
|||
if (self) {
|
||||
return _db.users.where().findAll();
|
||||
}
|
||||
final int userId = Store.get<User>(StoreKey.currentUser)!.isarId;
|
||||
final int userId = Store.get(StoreKey.currentUser).isarId;
|
||||
return _db.users.where().isarIdNotEqualTo(userId).findAll();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue