Files
immich/mobile-v2/lib/utils/isolate_helper.dart
shenlong-tanwen 0e8b19e269 use asynccache
2025-02-26 08:58:19 +05:30

94 lines
2.8 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'dart:isolate';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:immich_mobile/domain/repositories/database.repository.dart';
import 'package:immich_mobile/service_locator.dart';
import 'package:immich_mobile/utils/immich_api_client.dart';
import 'package:immich_mobile/utils/log_manager.dart';
@immutable
class _ImApiClientData {
final String endpoint;
final Map<String, String> headersMap;
const _ImApiClientData({required this.endpoint, required this.headersMap});
}
class InvalidIsolateUsageException implements Exception {
const InvalidIsolateUsageException();
@override
String toString() =>
"IsolateHelper should only be used from the root isolate";
}
// !! Should be used only from the root isolate
class IsolateHelper {
// Cache the ApiClient to reconstruct it later after inside the isolate
late final _ImApiClientData? _clientData;
IsolateHelper();
void preIsolateHandling() {
final apiClient = di<ImApiClient>();
_clientData = _ImApiClientData(
endpoint: apiClient.basePath,
headersMap: apiClient.defaultHeaderMap,
);
}
Future<void> postIsolateHandling() async {
assert(_clientData != null);
// Reconstruct client from cached data
final client = ImApiClient(endpoint: _clientData!.endpoint);
for (final entry in _clientData.headersMap.entries) {
client.addDefaultHeader(entry.key, entry.value);
}
// Register all services in the isolates memory
ServiceLocator.configureServicesForIsolate(
database: DriftDatabaseRepository(),
apiClient: client,
);
// Init log manager to continue listening to log events
await LogManager.I.init(shouldBuffer: false);
}
static Future<T> run<T>(FutureOr<T> Function() computation) async {
final token = RootIsolateToken.instance;
if (token == null) {
throw const InvalidIsolateUsageException();
}
final helper = IsolateHelper()..preIsolateHandling();
return await Isolate.run(() async {
BackgroundIsolateBinaryMessenger.ensureInitialized(token);
DartPluginRegistrant.ensureInitialized();
// Delay to ensure the isolate is ready
await Future.delayed(Durations.short2);
await helper.postIsolateHandling();
try {
final result = await computation();
// Wait for isolate to end; i.e, logs to be flushed
await Future.delayed(Durations.short2);
return result;
} finally {
// Always close the new database connection on Isolate end
await di<DriftDatabaseRepository>().close();
}
});
}
static Future<Map<String, dynamic>> decodeJson(Uint8List json) async {
return await Isolate.run(
() => const Utf8Decoder().fuse(const JsonDecoder()).convert(json)
as Map<String, dynamic>,
);
}
}