Update healthcheck policy

This commit is contained in:
chen08209
2024-05-06 10:32:39 +08:00
parent feb9688a29
commit 9aa9180f1f
13 changed files with 273 additions and 68 deletions

View File

@@ -7,14 +7,17 @@ import (
"github.com/metacubex/mihomo/component/process"
"github.com/metacubex/mihomo/component/resolver"
"github.com/metacubex/mihomo/config"
"github.com/metacubex/mihomo/constant/provider"
"github.com/metacubex/mihomo/dns"
"github.com/metacubex/mihomo/hub/executor"
"github.com/metacubex/mihomo/listener"
"github.com/metacubex/mihomo/log"
"github.com/metacubex/mihomo/tunnel"
"math"
"os"
"os/exec"
"runtime"
"sync"
"syscall"
)
@@ -170,6 +173,29 @@ func patchConfig(general *config.General) {
resolver.DisableIPv6 = !general.IPv6
}
const concurrentCount = math.MaxInt
func hcCompatibleProvider(proxyProviders map[string]provider.ProxyProvider) {
wg := sync.WaitGroup{}
ch := make(chan struct{}, concurrentCount)
for _, proxyProvider := range proxyProviders {
proxyProvider := proxyProvider
if proxyProvider.VehicleType() == provider.Compatible {
log.Infoln("Start initial Compatible provider %s", proxyProvider.Name())
wg.Add(1)
ch <- struct{}{}
go func() {
defer func() { <-ch; wg.Done() }()
if err := proxyProvider.Initial(); err != nil {
log.Errorln("initial Compatible provider %s error: %v", proxyProvider.Name(), err)
}
}()
}
}
}
func applyConfig(isPatch bool) {
cfg, err := config.ParseRawConfig(currentConfig)
if err != nil {

View File

@@ -251,6 +251,11 @@ func getProvider(name *C.char) *C.char {
return C.CString(string(data))
}
//export healthcheck
func healthcheck() {
hcCompatibleProvider(tunnel.Providers())
}
//export initNativeApiBridge
func initNativeApiBridge(api unsafe.Pointer, port C.longlong) {
bridge.InitDartApi(api)
@@ -273,13 +278,4 @@ func init() {
Data: delayData,
})
}
adapter.NowChangeHook = func(name, value string) {
bridge.SendMessage(bridge.Message{
Type: bridge.Now,
Data: Now{
Name: name,
Value: value,
},
})
}
}

View File

@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:dynamic_color/dynamic_color.dart';
import 'package:fl_clash/l10n/l10n.dart';
import 'package:fl_clash/common/common.dart';

View File

@@ -124,6 +124,10 @@ class ClashCore {
return true;
}
healthcheck(){
clashFFI.healthcheck();
}
VersionInfo getVersionInfo() {
final versionInfoRaw = clashFFI.getVersionInfo();
final versionInfo = json.decode(versionInfoRaw.cast<Utf8>().toDartString());

View File

@@ -1040,6 +1040,14 @@ class ClashFFI {
late final _getProvider = _getProviderPtr
.asFunction<ffi.Pointer<ffi.Char> Function(ffi.Pointer<ffi.Char>)>();
void healthcheck() {
return _healthcheck();
}
late final _healthcheckPtr =
_lookup<ffi.NativeFunction<ffi.Void Function()>>('healthcheck');
late final _healthcheck = _healthcheckPtr.asFunction<void Function()>();
void initNativeApiBridge(
ffi.Pointer<ffi.Void> api,
int port,

View File

@@ -56,9 +56,7 @@ class AppController {
updateRunTime() {
if (proxyManager.startTime != null) {
final startTimeStamp = proxyManager.startTime!.millisecondsSinceEpoch;
final nowTimeStamp = DateTime
.now()
.millisecondsSinceEpoch;
final nowTimeStamp = DateTime.now().millisecondsSinceEpoch;
appState.runTime = nowTimeStamp - startTimeStamp;
} else {
appState.runTime = null;
@@ -133,7 +131,7 @@ class AppController {
);
}
Function? _changeProfileDebounce;
Function? _changeProfileDebounce;
changeProfileDebounce(String? profileId) {
if (profileId == config.currentProfileId) return;
@@ -159,8 +157,8 @@ class AppController {
if (!profile.autoUpdate) return;
final isNotNeedUpdate = profile.lastUpdateDate
?.add(
profile.autoUpdateDuration,
)
profile.autoUpdateDuration,
)
.isBeforeNow();
if (isNotNeedUpdate == false) continue;
await profile.update();
@@ -177,7 +175,7 @@ class AppController {
clearCurrentDelay() {
final currentProxyName =
appState.getCurrentProxyName(config.currentProxyName, clashConfig.mode);
appState.getCurrentProxyName(config.currentProxyName, clashConfig.mode);
if (currentProxyName == null) return;
appState.setDelay(Delay(name: currentProxyName, value: null));
}
@@ -225,19 +223,30 @@ class AppController {
}
afterInit() async {
if (appState.isInit) {
if (config.autoRun) {
await updateSystemProxy(true);
} else {
await proxyManager.updateStartTime();
await updateSystemProxy(proxyManager.isStart);
}
autoUpdateProfiles();
updateLogStatus();
if (!config.silentLaunch) {
window?.show();
}
if (config.autoRun) {
await updateSystemProxy(true);
} else {
await proxyManager.updateStartTime();
await updateSystemProxy(proxyManager.isStart);
}
autoUpdateProfiles();
updateLogStatus();
if (!config.silentLaunch) {
window?.show();
}
periodicUpdateGroups();
}
periodicUpdateGroups() {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (globalState.updateGroupsTimer != null) {
globalState.updateGroupsTimer!.cancel();
}
globalState.updateGroupsTimer =
Timer.periodic(const Duration(seconds: 5), (Timer t) {
updateGroups();
});
});
}
setDelay(Delay delay) {
@@ -264,7 +273,7 @@ class AppController {
toProfiles() {
final index = globalState.currentNavigationItems.indexWhere(
(element) => element.label == "profiles",
(element) => element.label == "profiles",
);
if (index != -1) {
toPage(index);
@@ -277,7 +286,7 @@ class AppController {
final commonScaffoldState = globalState.homeScaffoldKey.currentState;
if (commonScaffoldState?.mounted != true) return;
commonScaffoldState?.loadingRun(
() async {
() async {
await Future.delayed(const Duration(milliseconds: 300));
final profile = Profile(
url: url,
@@ -298,7 +307,7 @@ class AppController {
initLink() {
linkManager.initAppLinksListen(
(url) {
(url) {
globalState.showMessage(
title: "${appLocalizations.add}${appLocalizations.profile}",
message: TextSpan(
@@ -307,20 +316,14 @@ class AppController {
TextSpan(
text: " $url ",
style: TextStyle(
color: Theme
.of(context)
.colorScheme
.primary,
color: Theme.of(context).colorScheme.primary,
decoration: TextDecoration.underline,
decorationColor: Theme
.of(context)
.colorScheme
.primary,
decorationColor: Theme.of(context).colorScheme.primary,
),
),
TextSpan(
text:
"${appLocalizations.create}${appLocalizations.profile}"),
"${appLocalizations.create}${appLocalizations.profile}"),
],
),
onTab: () {
@@ -340,7 +343,7 @@ class AppController {
final commonScaffoldState = globalState.homeScaffoldKey.currentState;
if (commonScaffoldState?.mounted != true) return;
commonScaffoldState?.loadingRun(
() async {
() async {
await Future.delayed(const Duration(milliseconds: 300));
final bytes = result.data?.bytes;
if (bytes == null) {

View File

@@ -83,11 +83,7 @@ class _ProxiesFragmentState extends State<ProxiesFragment>
);
},
builder: (_, state, __) {
if (_tabController != null) {
_tabController!.dispose();
_tabController = null;
}
_tabController = TabController(
_tabController ??= TabController(
length: state.groups.length,
vsync: this,
initialIndex: state.currentIndex,
@@ -290,7 +286,7 @@ class _ProxiesTabViewState extends State<ProxiesTabView> {
}
_buildGrid({
required ProxiesSortType proxiesSortType,
required List<Proxy> proxies,
required int columns,
}) {
return SingleChildScrollView(
@@ -309,7 +305,7 @@ class _ProxiesTabViewState extends State<ProxiesTabView> {
),
builder: (_, state, __) {
return AnimateGrid<Proxy>(
items: _getProxies(group.all, proxiesSortType),
items: proxies,
columns: columns,
itemHeight: _getItemHeight(),
keyBuilder: (item) {
@@ -342,9 +338,13 @@ class _ProxiesTabViewState extends State<ProxiesTabView> {
@override
Widget build(BuildContext context) {
return Selector<Config, ProxiesSortType>(
selector: (_, config) => config.proxiesSortType,
builder: (_, proxiesSortType, __) {
return Selector2<AppState, Config, ProxiesSortSelectorState>(
selector: (_, appState, config) => ProxiesSortSelectorState(
proxiesSortType: config.proxiesSortType,
sortNum: appState.sortNum,
),
builder: (_, state, __) {
final proxies = _getProxies(group.all, state.proxiesSortType);
return Align(
alignment: Alignment.topCenter,
child: SlotLayout(
@@ -352,21 +352,21 @@ class _ProxiesTabViewState extends State<ProxiesTabView> {
Breakpoints.small: SlotLayout.from(
key: const Key('proxies_grid_small'),
builder: (_) => _buildGrid(
proxiesSortType: proxiesSortType,
proxies: proxies,
columns: 2,
),
),
Breakpoints.medium: SlotLayout.from(
key: const Key('proxies_grid_medium'),
builder: (_) => _buildGrid(
proxiesSortType: proxiesSortType,
proxies: proxies,
columns: 3,
),
),
Breakpoints.large: SlotLayout.from(
key: const Key('proxies_grid_large'),
builder: (_) => _buildGrid(
proxiesSortType: proxiesSortType,
proxies: proxies,
columns: 4,
),
),
@@ -399,22 +399,17 @@ class _DelayTestButtonContainerState extends State<DelayTestButtonContainer>
_getDelayMap() async {
_controller.forward();
// for (final proxy in group.all) {
// context.appController.setDelay(
// Delay(
// name: proxy.name,
// value: 0,
// ),
// );
// clashCore.delay(
// proxy.name,
// );
// }
for (final delay in context.appController.appState.delayMap.entries) {
context.appController.setDelay(Delay(
name: delay.key,
value: 0,
));
}
clashCore.healthcheck();
await Future.delayed(
appConstant.httpTimeoutDuration + appConstant.moreDuration,
);
_controller.reverse();
setState(() {});
}
@override

View File

@@ -22,6 +22,7 @@ class AppState with ChangeNotifier {
String _currentLabel;
SystemColorSchemes _systemColorSchemes;
List<Group> _groups;
num _sortNum;
AppState()
: _navigationItems = [],
@@ -32,6 +33,7 @@ class AppState with ChangeNotifier {
_logs = [],
_groups = [],
_packages = [],
_sortNum = 0,
_systemColorSchemes = SystemColorSchemes();
String get currentLabel => _currentLabel;
@@ -159,6 +161,15 @@ class AppState with ChangeNotifier {
}
}
num get sortNum => _sortNum;
set sortNum(num value) {
if (_sortNum != value) {
_sortNum = value;
notifyListeners();
}
}
List<Group> getCurrentGroups(Mode mode) {
switch (mode) {
case Mode.direct:

View File

@@ -2032,3 +2032,145 @@ abstract class _ProxiesCardSelectorState implements ProxiesCardSelectorState {
_$$ProxiesCardSelectorStateImplCopyWith<_$ProxiesCardSelectorStateImpl>
get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc
mixin _$ProxiesSortSelectorState {
ProxiesSortType get proxiesSortType => throw _privateConstructorUsedError;
num get sortNum => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$ProxiesSortSelectorStateCopyWith<ProxiesSortSelectorState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ProxiesSortSelectorStateCopyWith<$Res> {
factory $ProxiesSortSelectorStateCopyWith(ProxiesSortSelectorState value,
$Res Function(ProxiesSortSelectorState) then) =
_$ProxiesSortSelectorStateCopyWithImpl<$Res, ProxiesSortSelectorState>;
@useResult
$Res call({ProxiesSortType proxiesSortType, num sortNum});
}
/// @nodoc
class _$ProxiesSortSelectorStateCopyWithImpl<$Res,
$Val extends ProxiesSortSelectorState>
implements $ProxiesSortSelectorStateCopyWith<$Res> {
_$ProxiesSortSelectorStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
@pragma('vm:prefer-inline')
@override
$Res call({
Object? proxiesSortType = null,
Object? sortNum = null,
}) {
return _then(_value.copyWith(
proxiesSortType: null == proxiesSortType
? _value.proxiesSortType
: proxiesSortType // ignore: cast_nullable_to_non_nullable
as ProxiesSortType,
sortNum: null == sortNum
? _value.sortNum
: sortNum // ignore: cast_nullable_to_non_nullable
as num,
) as $Val);
}
}
/// @nodoc
abstract class _$$ProxiesSortSelectorStateImplCopyWith<$Res>
implements $ProxiesSortSelectorStateCopyWith<$Res> {
factory _$$ProxiesSortSelectorStateImplCopyWith(
_$ProxiesSortSelectorStateImpl value,
$Res Function(_$ProxiesSortSelectorStateImpl) then) =
__$$ProxiesSortSelectorStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({ProxiesSortType proxiesSortType, num sortNum});
}
/// @nodoc
class __$$ProxiesSortSelectorStateImplCopyWithImpl<$Res>
extends _$ProxiesSortSelectorStateCopyWithImpl<$Res,
_$ProxiesSortSelectorStateImpl>
implements _$$ProxiesSortSelectorStateImplCopyWith<$Res> {
__$$ProxiesSortSelectorStateImplCopyWithImpl(
_$ProxiesSortSelectorStateImpl _value,
$Res Function(_$ProxiesSortSelectorStateImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? proxiesSortType = null,
Object? sortNum = null,
}) {
return _then(_$ProxiesSortSelectorStateImpl(
proxiesSortType: null == proxiesSortType
? _value.proxiesSortType
: proxiesSortType // ignore: cast_nullable_to_non_nullable
as ProxiesSortType,
sortNum: null == sortNum
? _value.sortNum
: sortNum // ignore: cast_nullable_to_non_nullable
as num,
));
}
}
/// @nodoc
class _$ProxiesSortSelectorStateImpl implements _ProxiesSortSelectorState {
const _$ProxiesSortSelectorStateImpl(
{required this.proxiesSortType, required this.sortNum});
@override
final ProxiesSortType proxiesSortType;
@override
final num sortNum;
@override
String toString() {
return 'ProxiesSortSelectorState(proxiesSortType: $proxiesSortType, sortNum: $sortNum)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ProxiesSortSelectorStateImpl &&
(identical(other.proxiesSortType, proxiesSortType) ||
other.proxiesSortType == proxiesSortType) &&
(identical(other.sortNum, sortNum) || other.sortNum == sortNum));
}
@override
int get hashCode => Object.hash(runtimeType, proxiesSortType, sortNum);
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$ProxiesSortSelectorStateImplCopyWith<_$ProxiesSortSelectorStateImpl>
get copyWith => __$$ProxiesSortSelectorStateImplCopyWithImpl<
_$ProxiesSortSelectorStateImpl>(this, _$identity);
}
abstract class _ProxiesSortSelectorState implements ProxiesSortSelectorState {
const factory _ProxiesSortSelectorState(
{required final ProxiesSortType proxiesSortType,
required final num sortNum}) = _$ProxiesSortSelectorStateImpl;
@override
ProxiesSortType get proxiesSortType;
@override
num get sortNum;
@override
@JsonKey(ignore: true)
_$$ProxiesSortSelectorStateImplCopyWith<_$ProxiesSortSelectorStateImpl>
get copyWith => throw _privateConstructorUsedError;
}

View File

@@ -118,3 +118,11 @@ class ProxiesCardSelectorState with _$ProxiesCardSelectorState{
required String? currentProxyName,
}) = _ProxiesCardSelectorState;
}
@freezed
class ProxiesSortSelectorState with _$ProxiesSortSelectorState{
const factory ProxiesSortSelectorState({
required ProxiesSortType proxiesSortType,
required num sortNum,
}) = _ProxiesSortSelectorState;
}

View File

@@ -14,8 +14,9 @@ import 'common/common.dart';
class GlobalState {
Timer? timer;
Timer? currentDelayTimer;
Timer? updateGroupsTimer;
Function? updateCurrentDelayDebounce;
Function? updateSortNumDebounce;
PageController? pageController;
final navigatorKey = GlobalKey<NavigatorState>();
final Map<int, String?> packageNameMap = {};

View File

@@ -39,6 +39,15 @@ class _ClashMessageContainerState extends State<ClashMessageContainer>
@override
void onDelay(Delay delay) {
context.appController.setDelay(delay);
WidgetsBinding.instance.addPostFrameCallback((_) {
globalState.updateSortNumDebounce ??= debounce<Function()>(
() {
context.appController.appState.sortNum++;
},
milliseconds: appConstant.httpTimeoutDuration.inMilliseconds,
);
globalState.updateSortNumDebounce!();
});
super.onDelay(delay);
}