import 'dart:async'; import 'dart:isolate'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:mangayomi/eval/lib.dart'; import 'package:mangayomi/main.dart'; import 'package:mangayomi/models/source.dart'; import 'package:mangayomi/providers/storage_provider.dart'; import 'package:mangayomi/services/http/m_client.dart'; import 'package:mangayomi/utils/log/log.dart'; class _IsolateData { final SendPort sendPort; final RootIsolateToken rootIsolateToken; _IsolateData({required this.sendPort, required this.rootIsolateToken}); } class GetIsolateService { bool _isRunning = false; Isolate? _getIsolateService; ReceivePort? _receivePort; SendPort? _sendPort; Future start() async { if (!_isRunning) { try { await _initGetIsolateService(); } catch (_) { await stop(); } } } Future _initGetIsolateService() async { _receivePort = ReceivePort(); final rootToken = RootIsolateToken.instance!; _getIsolateService = await Isolate.spawn( _getIsolateServiceEntryPoint, _IsolateData( sendPort: _receivePort!.sendPort, rootIsolateToken: rootToken, ), ); final completer = Completer(); _receivePort!.listen((message) { if (message is SendPort) { completer.complete(message); } if (message is String) { if (message.startsWith('LoggerLevel.warning:')) { Logger.add( LoggerLevel.warning, message.replaceFirst('LoggerLevel.warning:', ''), ); } else { Logger.add(LoggerLevel.info, message); } if (kDebugMode) { print(message.replaceFirst('LoggerLevel.warning:', '')); } } }); _sendPort = await completer.future; _isRunning = true; } static Future _getIsolateServiceEntryPoint( _IsolateData isolateData, ) async { BackgroundIsolateBinaryMessenger.ensureInitialized( isolateData.rootIsolateToken, ); await initializeDateFormatting(); isar = await StorageProvider().initDB(null, inspector: kDebugMode); final receivePort = ReceivePort(); Zone.current .fork( specification: ZoneSpecification( print: (self, parent, zone, line) { isolateData.sendPort.send(line); }, ), ) .run(() async { isolateData.sendPort.send(receivePort.sendPort); receivePort.listen((message) async { if (message is Map) { try { final url = message['url'] as String?; final page = message['page'] as int?; final query = message['query'] as String?; final filterList = message['filterList'] as List?; final source = message['source'] as Source?; final proxyServer = message['proxyServer'] as String?; final serviceType = message['serviceType'] as String?; final useLoggerValue = message['useLogger'] as bool?; final responsePort = message['responsePort'] as SendPort; cfPort = message['cfPort'] as int; if (useLoggerValue != null) { useLogger = useLoggerValue; } if (serviceType == 'getDetail') { final result = await getExtensionService( source!, proxyServer ?? '', ).getDetail(url!); responsePort.send({'success': true, 'data': result}); } else if (serviceType == 'getPopular') { final result = await getExtensionService( source!, proxyServer ?? '', ).getPopular(page!); responsePort.send({'success': true, 'data': result}); } else if (serviceType == 'getLatestUpdates') { final result = await getExtensionService( source!, proxyServer ?? '', ).getLatestUpdates(page!); responsePort.send({'success': true, 'data': result}); } else if (serviceType == 'search') { final result = await getExtensionService( source!, proxyServer ?? '', ).search(query!, page!, filterList!); responsePort.send({'success': true, 'data': result}); } else if (serviceType == 'getVideoList') { final result = await getExtensionService( source!, proxyServer ?? '', ).getVideoList(url!); responsePort.send({'success': true, 'data': result}); } else if (serviceType == 'getPageList') { final result = await getExtensionService( source!, proxyServer ?? '', ).getPageList(url!); responsePort.send({'success': true, 'data': result}); } } catch (e) { final responsePort = message['responsePort'] as SendPort; responsePort.send({'success': false, 'error': e.toString()}); } useLogger = false; } else if (message == 'dispose') { receivePort.close(); } }); }); } Future get({ String? url, int? page, String? query, List? filterList, Source? source, String? serviceType, String? proxyServer, bool? autoUpdateExtensions, String? androidProxyServer, bool? useLogger, }) async { if (_sendPort == null) { throw Exception('Isolate not running'); } final responsePort = ReceivePort(); final completer = Completer(); responsePort.listen((response) { responsePort.close(); if (response is Map) { if (response['success'] == true) { completer.complete(response['data'] as T); } else { completer.completeError(response['error']); } } }); _sendPort!.send({ 'url': url, 'page': page, 'query': query, 'filterList': filterList, 'serviceType': serviceType, 'source': source, 'proxyServer': proxyServer, 'responsePort': responsePort.sendPort, 'useLogger': useLogger, 'cfPort': cfPort, }); return completer.future; } Future stop() async { if (!_isRunning) { return; } _sendPort?.send('dispose'); _getIsolateService?.kill(priority: Isolate.immediate); _receivePort?.close(); _sendPort = null; _getIsolateService = null; _receivePort = null; _isRunning = false; } } final getIsolateService = GetIsolateService();