Add file editor Fix android service issues Optimize desktop background performance Optimize android main process performance Optimize delay test Optimize vpn protect
259 lines
6.7 KiB
Dart
259 lines
6.7 KiB
Dart
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
import 'dart:isolate';
|
|
|
|
import 'package:fl_clash/clash/clash.dart';
|
|
import 'package:fl_clash/clash/interface.dart';
|
|
import 'package:fl_clash/common/common.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 ClashCore {
|
|
static ClashCore? _instance;
|
|
late ClashHandlerInterface clashInterface;
|
|
|
|
ClashCore._internal() {
|
|
if (Platform.isAndroid) {
|
|
clashInterface = clashLib!;
|
|
} else {
|
|
clashInterface = clashService!;
|
|
}
|
|
}
|
|
|
|
factory ClashCore() {
|
|
_instance ??= ClashCore._internal();
|
|
return _instance!;
|
|
}
|
|
|
|
Future<bool> preload() {
|
|
return clashInterface.preload();
|
|
}
|
|
|
|
static Future<void> initGeo() async {
|
|
final homePath = await appPath.getHomeDirPath();
|
|
final homeDir = Directory(homePath);
|
|
final isExists = await homeDir.exists();
|
|
if (!isExists) {
|
|
await homeDir.create(recursive: true);
|
|
}
|
|
const geoFileNameList = [
|
|
mmdbFileName,
|
|
geoIpFileName,
|
|
geoSiteFileName,
|
|
asnFileName,
|
|
];
|
|
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<int> bytes = data.buffer.asUint8List();
|
|
await geoFile.writeAsBytes(bytes, flush: true);
|
|
}
|
|
} catch (e) {
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
Future<bool> init({
|
|
required ClashConfig clashConfig,
|
|
required Config config,
|
|
}) async {
|
|
await initGeo();
|
|
final homeDirPath = await appPath.getHomeDirPath();
|
|
return await clashInterface.init(homeDirPath);
|
|
}
|
|
|
|
shutdown() async {
|
|
await clashInterface.shutdown();
|
|
}
|
|
|
|
FutureOr<bool> get isInit => clashInterface.isInit;
|
|
|
|
FutureOr<String> validateConfig(String data) {
|
|
return clashInterface.validateConfig(data);
|
|
}
|
|
|
|
Future<String> updateConfig(UpdateConfigParams updateConfigParams) async {
|
|
return await clashInterface.updateConfig(updateConfigParams);
|
|
}
|
|
|
|
Future<List<Group>> getProxiesGroups() async {
|
|
final proxiesRawString = await clashInterface.getProxies();
|
|
return Isolate.run<List<Group>>(() {
|
|
if (proxiesRawString.isEmpty) return [];
|
|
final proxies = (json.decode(proxiesRawString) ?? {}) as Map;
|
|
if (proxies.isEmpty) return [];
|
|
final groupNames = [
|
|
UsedProxy.GLOBAL.name,
|
|
...(proxies[UsedProxy.GLOBAL.name]["all"] as List).where((e) {
|
|
final proxy = proxies[e] ?? {};
|
|
return GroupTypeExtension.valueList.contains(proxy['type']);
|
|
})
|
|
];
|
|
final groupsRaw = groupNames.map((groupName) {
|
|
final group = proxies[groupName];
|
|
group["all"] = ((group["all"] ?? []) as List)
|
|
.map(
|
|
(name) => proxies[name],
|
|
)
|
|
.where((proxy) => proxy != null)
|
|
.toList();
|
|
return group;
|
|
}).toList();
|
|
return groupsRaw
|
|
.map(
|
|
(e) => Group.fromJson(e),
|
|
)
|
|
.toList();
|
|
});
|
|
}
|
|
|
|
FutureOr<String> changeProxy(ChangeProxyParams changeProxyParams) async {
|
|
return await clashInterface.changeProxy(changeProxyParams);
|
|
}
|
|
|
|
Future<List<Connection>> getConnections() async {
|
|
final res = await clashInterface.getConnections();
|
|
final connectionsData = json.decode(res) as Map;
|
|
final connectionsRaw = connectionsData['connections'] as List? ?? [];
|
|
return connectionsRaw.map((e) => Connection.fromJson(e)).toList();
|
|
}
|
|
|
|
closeConnection(String id) {
|
|
clashInterface.closeConnection(id);
|
|
}
|
|
|
|
closeConnections() {
|
|
clashInterface.closeConnections();
|
|
}
|
|
|
|
Future<List<ExternalProvider>> getExternalProviders() async {
|
|
final externalProvidersRawString =
|
|
await clashInterface.getExternalProviders();
|
|
if (externalProvidersRawString.isEmpty) {
|
|
return [];
|
|
}
|
|
return Isolate.run<List<ExternalProvider>>(
|
|
() {
|
|
final externalProviders =
|
|
(json.decode(externalProvidersRawString) as List<dynamic>)
|
|
.map(
|
|
(item) => ExternalProvider.fromJson(item),
|
|
)
|
|
.toList();
|
|
return externalProviders;
|
|
},
|
|
);
|
|
}
|
|
|
|
Future<ExternalProvider?> getExternalProvider(
|
|
String externalProviderName) async {
|
|
final externalProvidersRawString =
|
|
await clashInterface.getExternalProvider(externalProviderName);
|
|
if (externalProvidersRawString.isEmpty) {
|
|
return null;
|
|
}
|
|
if (externalProvidersRawString.isEmpty) {
|
|
return null;
|
|
}
|
|
return ExternalProvider.fromJson(json.decode(externalProvidersRawString));
|
|
}
|
|
|
|
Future<String> updateGeoData(UpdateGeoDataParams params) {
|
|
return clashInterface.updateGeoData(params);
|
|
}
|
|
|
|
Future<String> sideLoadExternalProvider({
|
|
required String providerName,
|
|
required String data,
|
|
}) {
|
|
return clashInterface.sideLoadExternalProvider(
|
|
providerName: providerName, data: data);
|
|
}
|
|
|
|
Future<String> updateExternalProvider({
|
|
required String providerName,
|
|
}) async {
|
|
return clashInterface.updateExternalProvider(providerName);
|
|
}
|
|
|
|
startListener() async {
|
|
await clashInterface.startListener();
|
|
}
|
|
|
|
stopListener() async {
|
|
await clashInterface.stopListener();
|
|
}
|
|
|
|
Future<Delay> getDelay(String url, String proxyName) async {
|
|
final data = await clashInterface.asyncTestDelay(url, proxyName);
|
|
return Delay.fromJson(json.decode(data));
|
|
}
|
|
|
|
Future<Traffic> getTraffic() async {
|
|
final trafficString = await clashInterface.getTraffic();
|
|
if (trafficString.isEmpty) {
|
|
return Traffic();
|
|
}
|
|
return Traffic.fromMap(json.decode(trafficString));
|
|
}
|
|
|
|
Future<IpInfo?> getCountryCode(String ip) async {
|
|
final countryCode = await clashInterface.getCountryCode(ip);
|
|
if (countryCode.isEmpty) {
|
|
return null;
|
|
}
|
|
return IpInfo(
|
|
ip: ip,
|
|
countryCode: countryCode,
|
|
);
|
|
}
|
|
|
|
Future<Traffic> getTotalTraffic() async {
|
|
final totalTrafficString = await clashInterface.getTotalTraffic();
|
|
if (totalTrafficString.isEmpty) {
|
|
return Traffic();
|
|
}
|
|
return Traffic.fromMap(json.decode(totalTrafficString));
|
|
}
|
|
|
|
Future<int> getMemory() async {
|
|
final value = await clashInterface.getMemory();
|
|
if (value.isEmpty) {
|
|
return 0;
|
|
}
|
|
return int.parse(value);
|
|
}
|
|
|
|
resetTraffic() {
|
|
clashInterface.resetTraffic();
|
|
}
|
|
|
|
startLog() {
|
|
clashInterface.startLog();
|
|
}
|
|
|
|
stopLog() {
|
|
clashInterface.stopLog();
|
|
}
|
|
|
|
requestGc() {
|
|
clashInterface.forceGc();
|
|
}
|
|
|
|
destroy() async {
|
|
await clashInterface.destroy();
|
|
}
|
|
}
|
|
|
|
final clashCore = ClashCore();
|