import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/core/core.dart'; import 'package:fl_clash/core/interface.dart'; import 'package:fl_clash/enum/enum.dart'; import 'package:fl_clash/models/models.dart'; import 'package:flutter/services.dart'; import 'package:path/path.dart'; class CoreController { static CoreController? _instance; late CoreHandlerInterface _interface; CoreController._internal() { if (system.isAndroid) { _interface = coreLib!; } else { _interface = coreService!; } } factory CoreController() { _instance ??= CoreController._internal(); return _instance!; } bool get isCompleted => _interface.completer.isCompleted; Future preload() { return _interface.preload(); } static Future initGeo() async { final homePath = await appPath.homeDirPath; final homeDir = Directory(homePath); final isExists = await homeDir.exists(); if (!isExists) { await homeDir.create(recursive: true); } const geoFileNameList = [MMDB, GEOIP, GEOSITE, ASN]; try { for (final geoFileName in geoFileNameList) { final geoFile = File(join(homePath, geoFileName)); final isExists = await geoFile.exists(); if (isExists) { continue; } final data = await rootBundle.load('assets/data/$geoFileName'); List bytes = data.buffer.asUint8List(); await geoFile.writeAsBytes(bytes, flush: true); } } catch (e) { exit(0); } } Future init(int version) async { await initGeo(); final homeDirPath = await appPath.homeDirPath; return await _interface.init( InitParams(homeDir: homeDirPath, version: version), ); } Future shutdown() async { await _interface.shutdown(); } FutureOr get isInit => _interface.isInit; Future validateConfig(String path) async { final res = await _interface.validateConfig(path); return res; } Future validateConfigWithData(String data) async { final path = await appPath.tempFilePath; final file = File(path); await file.safeWriteAsString(data); final res = await _interface.validateConfig(path); await File(path).safeDelete(); return res; } Future updateConfig(UpdateParams updateParams) async { return await _interface.updateConfig(updateParams); } Future setupConfig({ required SetupParams params, required SetupState setupState, VoidCallback? preloadInvoke, }) async { final res = _interface.setupConfig(params); if (preloadInvoke != null) { preloadInvoke(); } return res; } Future> getProxiesGroups({ required ProxiesSortType sortType, required DelayMap delayMap, required Map selectedMap, required String defaultTestUrl, }) async { final proxiesData = await _interface.getProxies(); return toGroupsTask( ComputeGroupsState( proxiesData: proxiesData, sortType: sortType, delayMap: delayMap, selectedMap: selectedMap, defaultTestUrl: defaultTestUrl, ), ); } FutureOr changeProxy(ChangeProxyParams changeProxyParams) async { return await _interface.changeProxy(changeProxyParams); } Future> getConnections() async { final res = await _interface.getConnections(); final connectionsData = json.decode(res) as Map; final connectionsRaw = connectionsData['connections'] as List? ?? []; return connectionsRaw.map((e) => TrackerInfo.fromJson(e)).toList(); } void closeConnection(String id) { _interface.closeConnection(id); } void closeConnections() { _interface.closeConnections(); } void resetConnections() { _interface.resetConnections(); } Future> getExternalProviders() async { final externalProvidersRawString = await _interface.getExternalProviders(); if (externalProvidersRawString.isEmpty) { return []; } final externalProviders = (await externalProvidersRawString.commonToJSON>()) .map((item) => ExternalProvider.fromJson(item)) .toList(); return externalProviders; } Future getExternalProvider( String externalProviderName, ) async { final externalProvidersRawString = await _interface.getExternalProvider( externalProviderName, ); if (externalProvidersRawString.isEmpty) { return null; } return ExternalProvider.fromJson(json.decode(externalProvidersRawString)); } Future updateGeoData(UpdateGeoDataParams params) { return _interface.updateGeoData(params); } Future sideLoadExternalProvider({ required String providerName, required String data, }) { return _interface.sideLoadExternalProvider( providerName: providerName, data: data, ); } Future updateExternalProvider({required String providerName}) async { return _interface.updateExternalProvider(providerName); } Future startListener() async { return await _interface.startListener(); } Future stopListener() async { return await _interface.stopListener(); } Future getDelay(String url, String proxyName) async { final data = await _interface.asyncTestDelay(url, proxyName); return Delay.fromJson(json.decode(data)); } Future> getConfig(int id) async { final profilePath = await appPath.getProfilePath(id.toString()); final res = await _interface.getConfig(profilePath); if (res.isSuccess) { res.data['rules'] = res.data['rule']; res.data.remove('rule'); return res.data; } else { throw res.message; } } Future getTraffic(bool onlyStatisticsProxy) async { final trafficString = await _interface.getTraffic(onlyStatisticsProxy); if (trafficString.isEmpty) { return Traffic(); } return Traffic.fromJson(json.decode(trafficString)); } Future getCountryCode(String ip) async { final countryCode = await _interface.getCountryCode(ip); if (countryCode.isEmpty) { return null; } return IpInfo(ip: ip, countryCode: countryCode); } Future getTotalTraffic(bool onlyStatisticsProxy) async { final totalTrafficString = await _interface.getTotalTraffic( onlyStatisticsProxy, ); if (totalTrafficString.isEmpty) { return Traffic(); } return Traffic.fromJson(json.decode(totalTrafficString)); } Future getMemory() async { final value = await _interface.getMemory(); if (value.isEmpty) { return 0; } return int.parse(value); } void resetTraffic() { _interface.resetTraffic(); } void startLog() { _interface.startLog(); } void stopLog() { _interface.stopLog(); } Future requestGc() async { await _interface.forceGc(); } Future destroy() async { await _interface.destroy(); } Future crash() async { await _interface.crash(); } Future deleteFile(String path) async { return await _interface.deleteFile(path); } } final coreController = CoreController();