Optimize performance

Update core

Optimize core stability

Fix linux tun authority check error

Fix some issues
This commit is contained in:
chen08209
2025-02-09 18:39:38 +08:00
parent 96328f66e9
commit 4e679f776e
138 changed files with 13013 additions and 8723 deletions

View File

@@ -1,9 +1,9 @@
import 'dart:async';
import 'dart:io';
import 'package:animations/animations.dart';
import 'package:fl_clash/clash/clash.dart';
import 'package:fl_clash/enum/enum.dart';
import 'package:fl_clash/l10n/l10n.dart';
import 'package:fl_clash/plugins/service.dart';
import 'package:fl_clash/widgets/scaffold.dart';
import 'package:flutter/material.dart';
@@ -17,9 +17,12 @@ import 'models/models.dart';
typedef UpdateTasks = List<FutureOr Function()>;
class GlobalState {
static GlobalState? _instance;
bool isService = false;
Timer? timer;
Timer? groupsUpdateTimer;
late Config config;
late AppState appState;
late PackageInfo packageInfo;
Function? updateCurrentDelayDebounce;
PageController? pageController;
@@ -30,11 +33,43 @@ class GlobalState {
final navigatorKey = GlobalKey<NavigatorState>();
late AppController appController;
GlobalKey<CommonScaffoldState> homeScaffoldKey = GlobalKey();
bool lastTunEnable = false;
int? lastProfileModified;
bool get isStart => startTime != null && startTime!.isBeforeNow;
GlobalState._internal();
factory GlobalState() {
_instance ??= GlobalState._internal();
return _instance!;
}
initApp(int version) async {
appState = AppState(
version: version,
viewWidth: other.getScreenSize().width,
requests: FixedList(1000),
logs: FixedList(1000),
traffics: FixedList(30),
totalTraffic: Traffic(),
);
await init();
}
init() async {
packageInfo = await PackageInfo.fromPlatform();
config = await preferences.getConfig() ??
Config(
themeProps: defaultThemeProps,
);
await globalState.migrateOldData(config);
await AppLocalizations.load(
other.getLocaleForString(config.appSetting.locale) ??
WidgetsBinding.instance.platformDispatcher.locale,
);
}
String get ua => config.patchClashConfig.globalUa ?? packageInfo.ua;
startUpdateTasks([UpdateTasks? tasks]) async {
if (timer != null && timer!.isActive == true) return;
if (tasks != null) {
@@ -47,10 +82,10 @@ class GlobalState {
}
executorUpdateTask() async {
if (timer != null && timer!.isActive == true) return;
for (final task in tasks) {
await task();
}
timer = null;
}
stopUpdateTasks() {
@@ -59,88 +94,11 @@ class GlobalState {
timer = null;
}
Future<void> initCore({
required AppState appState,
required ClashConfig clashConfig,
required Config config,
}) async {
await globalState.init(
appState: appState,
config: config,
clashConfig: clashConfig,
);
await applyProfile(
appState: appState,
config: config,
clashConfig: clashConfig,
);
}
Future<void> updateClashConfig({
required AppState appState,
required ClashConfig clashConfig,
required Config config,
bool isPatch = true,
}) async {
await config.currentProfile?.checkAndUpdate();
final useClashConfig = clashConfig.copyWith();
if (clashConfig.tun.enable != lastTunEnable &&
lastTunEnable == false &&
!Platform.isAndroid) {
final code = await system.authorizeCore();
switch (code) {
case AuthorizeCode.none:
break;
case AuthorizeCode.success:
lastTunEnable = useClashConfig.tun.enable;
await restartCore(
appState: appState,
clashConfig: clashConfig,
config: config,
);
return;
case AuthorizeCode.error:
useClashConfig.tun = useClashConfig.tun.copyWith(
enable: false,
);
}
}
if (config.appSetting.openLogs) {
clashCore.startLog();
} else {
clashCore.stopLog();
}
final res = await clashCore.updateConfig(
getUpdateConfigParams(config, clashConfig, isPatch),
);
if (res.isNotEmpty) throw res;
lastTunEnable = useClashConfig.tun.enable;
lastProfileModified = await config.getCurrentProfile()?.profileLastModified;
}
handleStart([UpdateTasks? tasks]) async {
startTime ??= DateTime.now();
await clashCore.startListener();
await service?.startVpn();
startUpdateTasks(tasks);
startTime ??= DateTime.now();
}
restartCore({
required AppState appState,
required ClashConfig clashConfig,
required Config config,
bool isPatch = true,
}) async {
await clashService?.reStart();
await initCore(
appState: appState,
clashConfig: clashConfig,
config: config,
);
if (isStart) {
await handleStart();
}
}
Future updateStartTime() async {
@@ -150,85 +108,16 @@ class GlobalState {
Future handleStop() async {
startTime = null;
await clashCore.stopListener();
clashLib?.stopTun();
await clashLib?.stopTun();
await service?.stopVpn();
stopUpdateTasks();
}
Future applyProfile({
required AppState appState,
required Config config,
required ClashConfig clashConfig,
}) async {
clashCore.requestGc();
await updateClashConfig(
appState: appState,
clashConfig: clashConfig,
config: config,
isPatch: false,
);
await updateGroups(appState);
await updateProviders(appState);
}
updateProviders(AppState appState) async {
appState.providers = await clashCore.getExternalProviders();
}
CoreState getCoreState(Config config, ClashConfig clashConfig) {
return CoreState(
enable: config.vpnProps.enable,
accessControl: config.isAccessControl ? config.accessControl : null,
ipv6: config.vpnProps.ipv6,
allowBypass: config.vpnProps.allowBypass,
bypassDomain: config.networkProps.bypassDomain,
systemProxy: config.vpnProps.systemProxy,
currentProfileName:
config.currentProfile?.label ?? config.currentProfileId ?? "",
routeAddress: clashConfig.routeAddress,
);
}
getUpdateConfigParams(Config config, ClashConfig clashConfig, bool isPatch) {
return UpdateConfigParams(
profileId: config.currentProfileId ?? "",
config: clashConfig,
params: ConfigExtendedParams(
isPatch: isPatch,
isCompatible: true,
selectedMap: config.currentSelectedMap,
overrideDns: config.overrideDns,
testUrl: config.appSetting.testUrl,
onlyStatisticsProxy: config.appSetting.onlyStatisticsProxy,
),
);
}
init({
required AppState appState,
required Config config,
required ClashConfig clashConfig,
}) async {
appState.isInit = await clashCore.isInit;
if (!appState.isInit) {
appState.isInit = await clashCore.init(
config: config,
clashConfig: clashConfig,
);
clashLib?.setState(
getCoreState(config, clashConfig),
);
}
}
Future<void> updateGroups(AppState appState) async {
appState.groups = await clashCore.getProxiesGroups();
}
Future<bool?> showMessage<bool>({
Future<bool?> showMessage({
required String title,
required InlineSpan message,
String? confirmText,
bool cancelable = true,
}) async {
return await showCommonDialog<bool>(
child: Builder(
@@ -251,12 +140,13 @@ class GlobalState {
),
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(false);
},
child: Text(appLocalizations.cancel),
),
if (cancelable)
TextButton(
onPressed: () {
Navigator.of(context).pop(false);
},
child: Text(appLocalizations.cancel),
),
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
@@ -270,22 +160,6 @@ class GlobalState {
);
}
changeProxy({
required Config config,
required String groupName,
required String proxyName,
}) async {
await clashCore.changeProxy(
ChangeProxyParams(
groupName: groupName,
proxyName: proxyName,
),
);
if (config.appSetting.closeConnections) {
clashCore.closeConnections();
}
}
Future<T?> showCommonDialog<T>({
required Widget child,
bool dismissible = true,
@@ -301,17 +175,6 @@ class GlobalState {
);
}
updateTraffic({
required Config config,
AppFlowingState? appFlowingState,
}) async {
final traffic = await clashCore.getTraffic();
if (appFlowingState != null) {
appFlowingState.addTraffic(traffic);
appFlowingState.totalTraffic = await clashCore.getTotalTraffic();
}
}
Future<T?> safeRun<T>(
FutureOr<T> Function() futureFunction, {
String? title,
@@ -321,6 +184,7 @@ class GlobalState {
final res = await futureFunction();
return res;
} catch (e) {
commonPrint.log("$e");
if (silence) {
showNotifier(e.toString());
} else {
@@ -353,6 +217,49 @@ class GlobalState {
}
launchUrl(Uri.parse(url));
}
Future<void> migrateOldData(Config config) async {
final clashConfig = await preferences.getClashConfig();
if (clashConfig != null) {
config = config.copyWith(
patchClashConfig: clashConfig,
);
preferences.clearClashConfig();
preferences.saveConfig(config);
}
}
CoreState getCoreState() {
final currentProfile = config.currentProfile;
return CoreState(
vpnProps: config.vpnProps,
onlyStatisticsProxy: config.appSetting.onlyStatisticsProxy,
currentProfileName: currentProfile?.label ?? currentProfile?.id ?? "",
bypassDomain: config.networkProps.bypassDomain,
);
}
getUpdateConfigParams([bool? isPatch]) {
final currentProfile = config.currentProfile;
final clashConfig = config.patchClashConfig;
return UpdateConfigParams(
profileId: config.currentProfileId ?? "",
config: clashConfig.copyWith(
globalUa: ua,
tun: clashConfig.tun.copyWith(
routeAddress: config.networkProps.routeMode == RouteMode.bypassPrivate
? defaultBypassPrivateRouteAddress
: clashConfig.tun.routeAddress,
),
),
params: ConfigExtendedParams(
isPatch: isPatch ?? false,
selectedMap: currentProfile?.selectedMap ?? {},
overrideDns: config.overrideDns,
testUrl: config.appSetting.testUrl,
),
);
}
}
final globalState = GlobalState();