Add service mode and strict route

This commit is contained in:
problematicconsumer
2023-11-11 23:10:58 +03:30
parent 5125c1cc13
commit 305bead110
12 changed files with 132 additions and 85 deletions

View File

@@ -164,10 +164,10 @@
"clearSelection": "Clear selection" "clearSelection": "Clear selection"
}, },
"config": { "config": {
"mode": "Mode", "serviceMode": "Service Mode",
"modes": { "serviceModes": {
"none": "None",
"proxy": "Proxy", "proxy": "Proxy",
"systemProxy": "System Proxy",
"tun": "VPN" "tun": "VPN"
}, },
"section": { "section": {
@@ -199,7 +199,10 @@
"enableClashApi": "Enable Clash API", "enableClashApi": "Enable Clash API",
"clashApiPort": "Clash API Port", "clashApiPort": "Clash API Port",
"enableTun": "Enable TUN", "enableTun": "Enable TUN",
"setSystemProxy": "Set System Proxy" "setSystemProxy": "Set System Proxy",
"enableFakeDns": "Enable Fake DNS",
"bypassLan": "Bypass Lan",
"strictRoute": "Strict Route"
} }
}, },
"about": { "about": {

View File

@@ -164,10 +164,10 @@
"clearSelection": "حذف انتخاب‌ها" "clearSelection": "حذف انتخاب‌ها"
}, },
"config": { "config": {
"mode": "حالت", "serviceMode": "حالت سرویس",
"modes": { "serviceModes": {
"none": "هیچ یک",
"proxy": "پروکسی", "proxy": "پروکسی",
"systemProxy": "پروکسی سیستم",
"tun": "VPN" "tun": "VPN"
}, },
"section": { "section": {
@@ -199,7 +199,10 @@
"enableClashApi": "فعالسازی کلش", "enableClashApi": "فعالسازی کلش",
"clashApiPort": "پورت کلش", "clashApiPort": "پورت کلش",
"enableTun": "فعال سازی تونل", "enableTun": "فعال سازی تونل",
"setSystemProxy": "تنظیم پروکسی سیستم" "setSystemProxy": "تنظیم پروکسی سیستم",
"enableFakeDns": "Enable Fake DNS",
"bypassLan": "Bypass Lan",
"strictRoute": "Strict Route"
} }
}, },
"about": { "about": {

View File

@@ -164,10 +164,10 @@
"clearSelection": "Очистить выбор" "clearSelection": "Очистить выбор"
}, },
"config": { "config": {
"mode": "Режим", "serviceMode": "Сервисный режим",
"modes": { "serviceModes": {
"none": "Нет",
"proxy": "Прокси", "proxy": "Прокси",
"systemProxy": "Системный прокси",
"tun": "VPN" "tun": "VPN"
}, },
"section": { "section": {
@@ -199,7 +199,10 @@
"enableClashApi": "Использовать Clash API", "enableClashApi": "Использовать Clash API",
"clashApiPort": "Порт Clash API", "clashApiPort": "Порт Clash API",
"enableTun": "Использовать TUN", "enableTun": "Использовать TUN",
"setSystemProxy": "Установить системный прокси" "setSystemProxy": "Установить системный прокси",
"enableFakeDns": "Enable Fake DNS",
"bypassLan": "Bypass Lan",
"strictRoute": "Strict Route"
} }
}, },
"about": { "about": {

View File

@@ -164,10 +164,10 @@
"clearSelection": "清空选项" "clearSelection": "清空选项"
}, },
"config": { "config": {
"mode": "式", "serviceMode": "服务方式",
"modes": { "serviceModes": {
"none": "", "proxy": "代理人",
"proxy": "代理", "systemProxy": "系统代理",
"tun": "VPN" "tun": "VPN"
}, },
"section": { "section": {
@@ -199,7 +199,10 @@
"enableClashApi": "启用 Clash API", "enableClashApi": "启用 Clash API",
"clashApiPort": "Clash API 端口", "clashApiPort": "Clash API 端口",
"enableTun": "启用 TUN", "enableTun": "启用 TUN",
"setSystemProxy": "设置系统代理" "setSystemProxy": "设置系统代理",
"enableFakeDns": "Enable Fake DNS",
"bypassLan": "Bypass Lan",
"strictRoute": "Strict Route"
} }
}, },
"about": { "about": {

View File

@@ -4,7 +4,6 @@ import 'package:hiddify/core/prefs/prefs.dart';
import 'package:hiddify/data/data_providers.dart'; import 'package:hiddify/data/data_providers.dart';
import 'package:hiddify/domain/singbox/singbox.dart'; import 'package:hiddify/domain/singbox/singbox.dart';
import 'package:hiddify/utils/pref_notifier.dart'; import 'package:hiddify/utils/pref_notifier.dart';
import 'package:hiddify/utils/utils.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'config_options_store.g.dart'; part 'config_options_store.g.dart';
@@ -13,19 +12,19 @@ bool _debugConfigBuilder = false;
final _default = ConfigOptions.initial; final _default = ConfigOptions.initial;
@Riverpod(keepAlive: true) @Riverpod(keepAlive: true)
class CoreModeStore extends _$CoreModeStore { class ServiceModeStore extends _$ServiceModeStore {
late final _pref = Pref( late final _pref = Pref(
ref.watch(sharedPreferencesProvider), ref.watch(sharedPreferencesProvider),
"mode", "service-mode",
PlatformUtils.isDesktop ? CoreMode.proxy : CoreMode.tun, ServiceMode.defaultMode,
mapFrom: CoreMode.values.byName, mapFrom: ServiceMode.values.byName,
mapTo: (value) => value.name, mapTo: (value) => value.name,
); );
@override @override
CoreMode build() => _pref.getValue(); ServiceMode build() => _pref.getValue();
Future<void> update(CoreMode value) { Future<void> update(ServiceMode value) {
state = value; state = value;
return _pref.update(value); return _pref.update(value);
} }
@@ -83,9 +82,14 @@ final enableClashApiStore =
PrefNotifier.provider("enable-clash-api", _default.enableClashApi); PrefNotifier.provider("enable-clash-api", _default.enableClashApi);
final clashApiPortStore = final clashApiPortStore =
PrefNotifier.provider("clash-api-port", _default.clashApiPort); PrefNotifier.provider("clash-api-port", _default.clashApiPort);
final enableTunStore = PrefNotifier.provider("enable-tun", _default.enableTun); // final enableTunStore = PrefNotifier.provider("enable-tun", _default.enableTun);
final setSystemProxyStore = // final setSystemProxyStore =
PrefNotifier.provider("set-system-proxy", _default.setSystemProxy); // PrefNotifier.provider("set-system-proxy", _default.setSystemProxy);
final strictRouteStore =
PrefNotifier.provider("strict-route", _default.strictRoute);
final bypassLanStore = PrefNotifier.provider("bypass-lan", _default.bypassLan);
final enableFakeDnsStore =
PrefNotifier.provider("enable-fake-dns", _default.enableFakeDns);
// HACK temporary // HACK temporary
@riverpod @riverpod
@@ -138,38 +142,24 @@ ConfigOptions configPreferences(ConfigPreferencesRef ref) {
localDnsPort: ref.watch(localDnsPortStore), localDnsPort: ref.watch(localDnsPortStore),
tunImplementation: ref.watch(tunImplementationStore), tunImplementation: ref.watch(tunImplementationStore),
mtu: ref.watch(mtuStore), mtu: ref.watch(mtuStore),
strictRoute: ref.watch(strictRouteStore),
connectionTestUrl: ref.watch(connectionTestUrlStore), connectionTestUrl: ref.watch(connectionTestUrlStore),
urlTestInterval: ref.watch(urlTestIntervalStore), urlTestInterval: ref.watch(urlTestIntervalStore),
enableClashApi: ref.watch(enableClashApiStore), enableClashApi: ref.watch(enableClashApiStore),
clashApiPort: ref.watch(clashApiPortStore), clashApiPort: ref.watch(clashApiPortStore),
enableTun: ref.watch(enableTunStore), // enableTun: ref.watch(enableTunStore),
setSystemProxy: ref.watch(setSystemProxyStore), // setSystemProxy: ref.watch(setSystemProxyStore),
bypassLan: ref.watch(bypassLanStore),
enableFakeDns: ref.watch(enableFakeDnsStore),
rules: ref.watch(rulesProvider), rules: ref.watch(rulesProvider),
); );
} }
@riverpod @riverpod
ConfigOptions configOptions(ConfigOptionsRef ref) { ConfigOptions configOptions(ConfigOptionsRef ref) {
final mode = ref.watch(coreModeStoreProvider); final serviceMode = ref.watch(serviceModeStoreProvider);
return ConfigOptions( return ref.watch(configPreferencesProvider).copyWith(
executeConfigAsIs: kDebugMode && _debugConfigBuilder, enableTun: serviceMode == ServiceMode.tun,
logLevel: ref.watch(logLevelStore), setSystemProxy: serviceMode == ServiceMode.systemProxy,
resolveDestination: ref.watch(resolveDestinationStore),
ipv6Mode: ref.watch(ipv6ModeStore),
remoteDnsAddress: ref.watch(remoteDnsAddressStore),
remoteDnsDomainStrategy: ref.watch(remoteDnsDomainStrategyStore),
directDnsAddress: ref.watch(directDnsAddressStore),
directDnsDomainStrategy: ref.watch(directDnsDomainStrategyStore),
mixedPort: ref.watch(mixedPortStore),
localDnsPort: ref.watch(localDnsPortStore),
tunImplementation: ref.watch(tunImplementationStore),
mtu: ref.watch(mtuStore),
connectionTestUrl: ref.watch(connectionTestUrlStore),
urlTestInterval: ref.watch(urlTestIntervalStore),
enableClashApi: ref.watch(enableClashApiStore),
clashApiPort: ref.watch(clashApiPortStore),
enableTun: mode == CoreMode.tun || ref.watch(enableTunStore),
setSystemProxy: mode == CoreMode.proxy || ref.watch(setSystemProxyStore),
rules: ref.watch(rulesProvider),
); );
} }

View File

@@ -26,6 +26,7 @@ class ConfigOptions with _$ConfigOptions {
@Default(6450) int localDnsPort, @Default(6450) int localDnsPort,
@Default(TunImplementation.mixed) TunImplementation tunImplementation, @Default(TunImplementation.mixed) TunImplementation tunImplementation,
@Default(9000) int mtu, @Default(9000) int mtu,
@Default(true) bool strictRoute,
@Default("http://cp.cloudflare.com/") String connectionTestUrl, @Default("http://cp.cloudflare.com/") String connectionTestUrl,
@IntervalConverter() @IntervalConverter()
@Default(Duration(minutes: 10)) @Default(Duration(minutes: 10))

View File

@@ -1,13 +0,0 @@
import 'package:hiddify/core/prefs/locale_prefs.dart';
enum CoreMode {
none,
proxy,
tun;
String present(TranslationsEn t) => switch (this) {
none => t.settings.config.modes.none,
proxy => t.settings.config.modes.proxy,
tun => t.settings.config.modes.tun,
};
}

View File

@@ -0,0 +1,24 @@
import 'package:hiddify/core/prefs/locale_prefs.dart';
import 'package:hiddify/utils/platform_utils.dart';
enum ServiceMode {
proxy,
systemProxy,
tun;
static ServiceMode get defaultMode =>
PlatformUtils.isDesktop ? systemProxy : tun;
static List<ServiceMode> get choices {
if (PlatformUtils.isDesktop) {
return values;
}
return [proxy, tun];
}
String present(TranslationsEn t) => switch (this) {
proxy => t.settings.config.serviceModes.proxy,
systemProxy => t.settings.config.serviceModes.systemProxy,
tun => t.settings.config.serviceModes.tun,
};
}

View File

@@ -1,8 +1,8 @@
export 'box_log.dart'; export 'box_log.dart';
export 'config_options.dart'; export 'config_options.dart';
export 'core_mode.dart';
export 'core_status.dart'; export 'core_status.dart';
export 'outbounds.dart'; export 'outbounds.dart';
export 'proxy_type.dart'; export 'proxy_type.dart';
export 'rules.dart'; export 'rules.dart';
export 'service_mode.dart';
export 'singbox_facade.dart'; export 'singbox_facade.dart';

View File

@@ -19,6 +19,7 @@ class ConfigOptionsPage extends HookConsumerWidget {
final t = ref.watch(translationsProvider); final t = ref.watch(translationsProvider);
final options = ref.watch(configPreferencesProvider); final options = ref.watch(configPreferencesProvider);
final serviceMode = ref.watch(serviceModeStoreProvider);
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
@@ -59,6 +60,11 @@ class ConfigOptionsPage extends HookConsumerWidget {
), ),
const SettingsDivider(), const SettingsDivider(),
SettingsSection(t.settings.config.section.route), SettingsSection(t.settings.config.section.route),
// SwitchListTile(
// title: Text(t.settings.config.bypassLan),
// value: options.bypassLan,
// onChanged: ref.read(bypassLanStore.notifier).update,
// ),
SwitchListTile( SwitchListTile(
title: Text(t.settings.config.resolveDestination), title: Text(t.settings.config.resolveDestination),
value: options.resolveDestination, value: options.resolveDestination,
@@ -141,20 +147,47 @@ class ConfigOptionsPage extends HookConsumerWidget {
.update(domainStrategy); .update(domainStrategy);
}, },
), ),
// SwitchListTile(
// title: Text(t.settings.config.enableFakeDns),
// value: options.enableFakeDns,
// onChanged: ref.read(enableFakeDnsStore.notifier).update,
// ),
const SettingsDivider(), const SettingsDivider(),
SettingsSection(t.settings.config.section.inbound), SettingsSection(t.settings.config.section.inbound),
if (PlatformUtils.isDesktop) ...[ // if (PlatformUtils.isDesktop) ...[
SwitchListTile( // SwitchListTile(
title: Text(t.settings.config.enableTun), // title: Text(t.settings.config.enableTun),
value: options.enableTun, // value: options.enableTun,
onChanged: ref.read(enableTunStore.notifier).update, // onChanged: ref.read(enableTunStore.notifier).update,
// ),
// SwitchListTile(
// title: Text(t.settings.config.setSystemProxy),
// value: options.setSystemProxy,
// onChanged: ref.read(setSystemProxyStore.notifier).update,
// ),
// ],
ListTile(
title: Text(t.settings.config.serviceMode),
subtitle: Text(serviceMode.present(t)),
onTap: () async {
final pickedMode = await SettingsPickerDialog(
title: t.settings.config.serviceMode,
selected: serviceMode,
options: ServiceMode.choices,
getTitle: (e) => e.present(t),
resetValue: ServiceMode.defaultMode,
).show(context);
if (pickedMode == null) return;
await ref
.read(serviceModeStoreProvider.notifier)
.update(pickedMode);
},
), ),
SwitchListTile( SwitchListTile(
title: Text(t.settings.config.setSystemProxy), title: Text(t.settings.config.strictRoute),
value: options.setSystemProxy, value: options.strictRoute,
onChanged: ref.read(setSystemProxyStore.notifier).update, onChanged: ref.read(strictRouteStore.notifier).update,
), ),
],
ListTile( ListTile(
title: Text(t.settings.config.tunImplementation), title: Text(t.settings.config.tunImplementation),
subtitle: Text(options.tunImplementation.name), subtitle: Text(options.tunImplementation.name),

View File

@@ -31,7 +31,7 @@ class SystemTrayController extends _$SystemTrayController
} }
final connection = await ref.watch(connectivityControllerProvider.future); final connection = await ref.watch(connectivityControllerProvider.future);
final mode = ref.watch(coreModeStoreProvider); final serviceMode = ref.watch(serviceModeStoreProvider);
final t = ref.watch(translationsProvider); final t = ref.watch(translationsProvider);
@@ -56,19 +56,19 @@ class SystemTrayController extends _$SystemTrayController
onClick: handleClickSetAsSystemProxy, onClick: handleClickSetAsSystemProxy,
), ),
MenuItem.submenu( MenuItem.submenu(
label: t.settings.config.mode, label: t.settings.config.serviceMode,
submenu: Menu( submenu: Menu(
items: [ items: [
...CoreMode.values.map( ...ServiceMode.values.map(
(e) => MenuItem.checkbox( (e) => MenuItem.checkbox(
checked: e == mode, checked: e == serviceMode,
key: e.name, key: e.name,
label: e.present(t), label: e.present(t),
onClick: (menuItem) async { onClick: (menuItem) async {
final newMode = CoreMode.values.byName(menuItem.key!); final newMode = ServiceMode.values.byName(menuItem.key!);
loggy.debug("switching core mode: [$newMode]"); loggy.debug("switching service mode: [$newMode]");
await ref await ref
.read(coreModeStoreProvider.notifier) .read(serviceModeStoreProvider.notifier)
.update(newMode); .update(newMode);
}, },
), ),

Submodule libcore updated: f89ede4990...5c8b283d9c