Fix core crash caused by windows resource manager restart Optimize logs, requests, access to pages Fix macos bypass domain issues
406 lines
8.9 KiB
Dart
406 lines
8.9 KiB
Dart
import 'dart:async';
|
|
import 'dart:convert';
|
|
|
|
import 'package:fl_clash/clash/message.dart';
|
|
import 'package:fl_clash/common/constant.dart';
|
|
import 'package:fl_clash/common/future.dart';
|
|
import 'package:fl_clash/common/other.dart';
|
|
import 'package:fl_clash/enum/enum.dart';
|
|
import 'package:fl_clash/models/models.dart';
|
|
import 'package:flutter/material.dart' hide Action;
|
|
|
|
mixin ClashInterface {
|
|
Future<bool> init(String homeDir);
|
|
|
|
Future<bool> preload();
|
|
|
|
Future<bool> shutdown();
|
|
|
|
Future<bool> get isInit;
|
|
|
|
Future<bool> forceGc();
|
|
|
|
FutureOr<String> validateConfig(String data);
|
|
|
|
Future<String> asyncTestDelay(String url, String proxyName);
|
|
|
|
FutureOr<String> updateConfig(UpdateConfigParams updateConfigParams);
|
|
|
|
FutureOr<String> getProxies();
|
|
|
|
FutureOr<String> changeProxy(ChangeProxyParams changeProxyParams);
|
|
|
|
Future<bool> startListener();
|
|
|
|
Future<bool> stopListener();
|
|
|
|
FutureOr<String> getExternalProviders();
|
|
|
|
FutureOr<String>? getExternalProvider(String externalProviderName);
|
|
|
|
Future<String> updateGeoData(UpdateGeoDataParams params);
|
|
|
|
Future<String> sideLoadExternalProvider({
|
|
required String providerName,
|
|
required String data,
|
|
});
|
|
|
|
Future<String> updateExternalProvider(String providerName);
|
|
|
|
FutureOr<String> getTraffic();
|
|
|
|
FutureOr<String> getTotalTraffic();
|
|
|
|
FutureOr<String> getCountryCode(String ip);
|
|
|
|
FutureOr<String> getMemory();
|
|
|
|
resetTraffic();
|
|
|
|
startLog();
|
|
|
|
stopLog();
|
|
|
|
FutureOr<String> getConnections();
|
|
|
|
FutureOr<bool> closeConnection(String id);
|
|
|
|
FutureOr<bool> closeConnections();
|
|
}
|
|
|
|
mixin AndroidClashInterface {
|
|
Future<bool> setFdMap(int fd);
|
|
|
|
Future<bool> setProcessMap(ProcessMapItem item);
|
|
|
|
Future<bool> setState(CoreState state);
|
|
|
|
Future<bool> stopTun();
|
|
|
|
Future<bool> updateDns(String value);
|
|
|
|
Future<DateTime?> startTun(int fd);
|
|
|
|
Future<AndroidVpnOptions?> getAndroidVpnOptions();
|
|
|
|
Future<String> getCurrentProfileName();
|
|
|
|
Future<DateTime?> getRunTime();
|
|
}
|
|
|
|
abstract class ClashHandlerInterface with ClashInterface {
|
|
Map<String, Completer> callbackCompleterMap = {};
|
|
|
|
Future<bool> nextHandleResult(ActionResult result, Completer? completer) =>
|
|
Future.value(false);
|
|
|
|
handleResult(ActionResult result) async {
|
|
final completer = callbackCompleterMap[result.id];
|
|
try {
|
|
switch (result.method) {
|
|
case ActionMethod.initClash:
|
|
case ActionMethod.shutdown:
|
|
case ActionMethod.getIsInit:
|
|
case ActionMethod.startListener:
|
|
case ActionMethod.resetTraffic:
|
|
case ActionMethod.closeConnections:
|
|
case ActionMethod.closeConnection:
|
|
case ActionMethod.stopListener:
|
|
completer?.complete(result.data as bool);
|
|
return;
|
|
case ActionMethod.changeProxy:
|
|
case ActionMethod.getProxies:
|
|
case ActionMethod.getTraffic:
|
|
case ActionMethod.getTotalTraffic:
|
|
case ActionMethod.asyncTestDelay:
|
|
case ActionMethod.getConnections:
|
|
case ActionMethod.getExternalProviders:
|
|
case ActionMethod.getExternalProvider:
|
|
case ActionMethod.validateConfig:
|
|
case ActionMethod.updateConfig:
|
|
case ActionMethod.updateGeoData:
|
|
case ActionMethod.updateExternalProvider:
|
|
case ActionMethod.sideLoadExternalProvider:
|
|
case ActionMethod.getCountryCode:
|
|
case ActionMethod.getMemory:
|
|
completer?.complete(result.data as String);
|
|
return;
|
|
case ActionMethod.message:
|
|
clashMessage.controller.add(result.data as String);
|
|
completer?.complete(true);
|
|
return;
|
|
default:
|
|
final isHandled = await nextHandleResult(result, completer);
|
|
if (isHandled) {
|
|
return;
|
|
}
|
|
completer?.complete(result.data);
|
|
}
|
|
} catch (_) {
|
|
debugPrint(result.id);
|
|
}
|
|
}
|
|
|
|
sendMessage(String message);
|
|
|
|
reStart();
|
|
|
|
FutureOr<bool> destroy();
|
|
|
|
Future<T> invoke<T>({
|
|
required ActionMethod method,
|
|
dynamic data,
|
|
Duration? timeout,
|
|
FutureOr<T> Function()? onTimeout,
|
|
}) async {
|
|
final id = "${method.name}#${other.id}";
|
|
|
|
callbackCompleterMap[id] = Completer<T>();
|
|
|
|
dynamic defaultValue;
|
|
|
|
if (T == String) {
|
|
defaultValue = "";
|
|
}
|
|
if (T == bool) {
|
|
defaultValue = false;
|
|
}
|
|
|
|
sendMessage(
|
|
json.encode(
|
|
Action(
|
|
id: id,
|
|
method: method,
|
|
data: data,
|
|
defaultValue: defaultValue,
|
|
),
|
|
),
|
|
);
|
|
|
|
return (callbackCompleterMap[id] as Completer<T>).safeFuture(
|
|
timeout: timeout,
|
|
onLast: () {
|
|
callbackCompleterMap.remove(id);
|
|
},
|
|
onTimeout: onTimeout ??
|
|
() {
|
|
return defaultValue;
|
|
},
|
|
functionName: id,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Future<bool> init(String homeDir) {
|
|
return invoke<bool>(
|
|
method: ActionMethod.initClash,
|
|
data: homeDir,
|
|
);
|
|
}
|
|
|
|
@override
|
|
shutdown() async {
|
|
return await invoke<bool>(
|
|
method: ActionMethod.shutdown,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Future<bool> get isInit {
|
|
return invoke<bool>(
|
|
method: ActionMethod.getIsInit,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Future<bool> forceGc() {
|
|
return invoke<bool>(
|
|
method: ActionMethod.forceGc,
|
|
);
|
|
}
|
|
|
|
@override
|
|
FutureOr<String> validateConfig(String data) {
|
|
return invoke<String>(
|
|
method: ActionMethod.validateConfig,
|
|
data: data,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Future<String> updateConfig(UpdateConfigParams updateConfigParams) async {
|
|
return await invoke<String>(
|
|
method: ActionMethod.updateConfig,
|
|
data: json.encode(updateConfigParams),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Future<String> getProxies() {
|
|
return invoke<String>(
|
|
method: ActionMethod.getProxies,
|
|
);
|
|
}
|
|
|
|
@override
|
|
FutureOr<String> changeProxy(ChangeProxyParams changeProxyParams) {
|
|
return invoke<String>(
|
|
method: ActionMethod.changeProxy,
|
|
data: json.encode(changeProxyParams),
|
|
);
|
|
}
|
|
|
|
@override
|
|
FutureOr<String> getExternalProviders() {
|
|
return invoke<String>(
|
|
method: ActionMethod.getExternalProviders,
|
|
);
|
|
}
|
|
|
|
@override
|
|
FutureOr<String> getExternalProvider(String externalProviderName) {
|
|
return invoke<String>(
|
|
method: ActionMethod.getExternalProvider,
|
|
data: externalProviderName,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Future<String> updateGeoData(UpdateGeoDataParams params) {
|
|
return invoke<String>(
|
|
method: ActionMethod.updateGeoData,
|
|
data: json.encode(params),
|
|
timeout: Duration(minutes: 1));
|
|
}
|
|
|
|
@override
|
|
Future<String> sideLoadExternalProvider({
|
|
required String providerName,
|
|
required String data,
|
|
}) {
|
|
return invoke<String>(
|
|
method: ActionMethod.sideLoadExternalProvider,
|
|
data: json.encode({
|
|
"providerName": providerName,
|
|
"data": data,
|
|
}),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Future<String> updateExternalProvider(String providerName) {
|
|
return invoke<String>(
|
|
method: ActionMethod.updateExternalProvider,
|
|
data: providerName,
|
|
timeout: Duration(minutes: 1),
|
|
);
|
|
}
|
|
|
|
@override
|
|
FutureOr<String> getConnections() {
|
|
return invoke<String>(
|
|
method: ActionMethod.getConnections,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Future<bool> closeConnections() {
|
|
return invoke<bool>(
|
|
method: ActionMethod.closeConnections,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Future<bool> closeConnection(String id) {
|
|
return invoke<bool>(
|
|
method: ActionMethod.closeConnection,
|
|
data: id,
|
|
);
|
|
}
|
|
|
|
@override
|
|
FutureOr<String> getTotalTraffic() {
|
|
return invoke<String>(
|
|
method: ActionMethod.getTotalTraffic,
|
|
);
|
|
}
|
|
|
|
@override
|
|
FutureOr<String> getTraffic() {
|
|
return invoke<String>(
|
|
method: ActionMethod.getTraffic,
|
|
);
|
|
}
|
|
|
|
@override
|
|
resetTraffic() {
|
|
invoke(method: ActionMethod.resetTraffic);
|
|
}
|
|
|
|
@override
|
|
startLog() {
|
|
invoke(method: ActionMethod.startLog);
|
|
}
|
|
|
|
@override
|
|
stopLog() {
|
|
invoke<bool>(
|
|
method: ActionMethod.stopLog,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Future<bool> startListener() {
|
|
return invoke<bool>(
|
|
method: ActionMethod.startListener,
|
|
);
|
|
}
|
|
|
|
@override
|
|
stopListener() {
|
|
return invoke<bool>(
|
|
method: ActionMethod.stopListener,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Future<String> asyncTestDelay(String url, String proxyName) {
|
|
final delayParams = {
|
|
"proxy-name": proxyName,
|
|
"timeout": httpTimeoutDuration.inMilliseconds,
|
|
"test-url": url,
|
|
};
|
|
return invoke<String>(
|
|
method: ActionMethod.asyncTestDelay,
|
|
data: json.encode(delayParams),
|
|
timeout: Duration(
|
|
milliseconds: 6000,
|
|
),
|
|
onTimeout: () {
|
|
return json.encode(
|
|
Delay(
|
|
name: proxyName,
|
|
value: -1,
|
|
url: url,
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
@override
|
|
FutureOr<String> getCountryCode(String ip) {
|
|
return invoke<String>(
|
|
method: ActionMethod.getCountryCode,
|
|
data: ip,
|
|
);
|
|
}
|
|
|
|
@override
|
|
FutureOr<String> getMemory() {
|
|
return invoke<String>(
|
|
method: ActionMethod.getMemory,
|
|
);
|
|
}
|
|
}
|