alroyso 6 months ago
parent
commit
f7a4a52a43

+ 3 - 3
lib/app/clash/mode/clash_config.dart

@@ -83,10 +83,10 @@ class ClashConfig {
       if (globalClientFingerprint != null) 'global-client-fingerprint': globalClientFingerprint,
       if (profile != null) 'profile': profile,
       if (sniffer != null) 'sniffer': sniffer!.toJson(),
-      'dns': dns.toJson(),
+      if (dns != null)  'dns': dns?.toJson(),
       if (tun != null) 'tun': tun!.toJson(),
-      'proxies': proxies,
-      'proxy-groups': proxyGroups.map((e) => e.toJson()).toList(),
+      if (proxies != null) 'proxies': proxies,
+      if (proxyGroups != null)'proxy-groups': proxyGroups?.map((e) => e.toJson()).toList(),
       'rules': rules,
     };
   }

+ 32 - 2
lib/app/clash/mode/config.dart

@@ -27,7 +27,7 @@ class GuiConfig {
     startAtLogin = json['startAtLogin'];
     breakConnections = json['breakConnections'];
     language = json['language'];
-    servicePort = json['port'];
+    servicePort = json['servicePort'];
   }
 
   Map<String, dynamic> toJson() {
@@ -39,7 +39,7 @@ class GuiConfig {
     data['startAtLogin'] = startAtLogin;
     data['breakConnections'] = breakConnections;
     data['language'] = language;
-    data['port'] = servicePort;
+    data['servicePort'] = servicePort;
     return data;
   }
 
@@ -51,3 +51,33 @@ class GuiConfig {
 
 
 
+class VersionConfig {
+  late String serviceVersion;
+  late String coreVersion;
+  late String appVersion;
+
+  VersionConfig({
+    required this.serviceVersion,
+    required this.coreVersion,
+    required this.appVersion,
+  });
+
+  VersionConfig.fromJson(Map<String, dynamic> json) {
+    serviceVersion = json['serviceVersion'];
+    coreVersion = json['coreVersion'];
+    appVersion = json['appVersion'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final data = <String, dynamic>{};
+    data['serviceVersion'] = serviceVersion;
+    data['coreVersion'] = coreVersion;
+    data['appVersion'] = appVersion;
+    return data;
+  }
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}

+ 16 - 18
lib/app/clash/service/clash_service.dart

@@ -8,22 +8,17 @@ import '../../const/const.dart';
 import '../../controller/controllers.dart';
 import '../../data/model/NodeMode.dart';
 import '../../utils/shell.dart';
+import '../../utils/utils.dart';
 import '../mode/clash_config.dart';
 
 
-enum RunningState {
-  starting,
-  running,
-  stopping,
-  stoped,
-  error,
-}
 
-class ClashService {
+
+class ClashService extends GetxController {
   Process? clashCoreProcess;
   final coreStatus = RunningState.stoped.obs;
   final serviceMode = false.obs;
-
+  bool get clashServiceIsRuning => coreStatus.value == RunningState.running;
   Future<bool> startClashCore() async {
     final timeout = const Duration(seconds: 30);
     final checkInterval = const Duration(milliseconds: 200);
@@ -80,6 +75,7 @@ class ClashService {
     }
   }
 
+
   Future<void> stopClashCore() async {
     coreStatus.value = RunningState.stopping;
     await controllers.global.closeProxy();
@@ -88,19 +84,21 @@ class ClashService {
     coreStatus.value = RunningState.stoped;
   }
 
-  Future<void> initClashCoreConfig() async {
-    controllers.config.config.value.selected = 'init_proxy.yaml';
+  Future<bool> initClashCoreConfig() async {
+    controllers.config.config.value.selected = Files.makeInitProxyConfig.path;
     await startClashCore();
     if (coreStatus.value == RunningState.error) {
       controllers.global.updateMsg("启动内核失败...");
+      return false;
     } else {
       await controllers.core.updateVersion();
       controllers.global.updateMsg("启动内核成功...");
+      return true;
     }
   }
 
   Future<void> stopClash() async {
-    controllers.config.config.value.selected = 'init_proxy.yaml';
+    controllers.config.config.value.selected = Files.makeInitProxyConfig.path;
     if (coreStatus.value == RunningState.running) {
       await controllers.config.readClashCoreApi();
       controllers.core.setApi(controllers.config.clashCoreApiAddress.value, controllers.config.clashCoreApiSecret.value);
@@ -110,7 +108,7 @@ class ClashService {
 
   Future<void> reloadClashCore() async {
     try {
-      controllers.config.config.value.selected = 'proxy.yaml';
+      controllers.config.config.value.selected = Files.makeProxyConfig.path;
       if (coreStatus.value == RunningState.running) {
         controllers.global.updateMsg("切换配置...");
         await controllers.config.readClashCoreApi();
@@ -172,14 +170,14 @@ class ClashService {
           'geosite:geolocation-!cn': kForeignDNS,
         },
       ),
-      tun: controllers.global.routeModesSelect.value == "tun" ? Tun(
-        enable: true,
+      tun:  Tun(
+        enable: controllers.global.routeModesSelect.value == "tun" ? true:false,
         stack: 'system',
         autoRoute: true,
         autoRedirect: true,
         autoDetectInterface: true,
         dnsHijack: ['any:53'],
-      ) : null,
+      ),
       proxies: [],
       proxyGroups: [
         ProxyGroup(
@@ -250,8 +248,8 @@ class ClashService {
         default:
           continue;
       }
-      config.proxies.add(proxy.toJson());
-      config.proxyGroups[0].proxies.add(node.name ?? '');
+      config.proxies?.add(proxy.toJson());
+      config.proxyGroups?[0].proxies.add(node.name ?? '');
     }
 
     return config.toYaml();

+ 3 - 0
lib/app/component/connection_widget.dart

@@ -44,6 +44,9 @@ class _ConnectionWidgetState extends State<ConnectionWidget> {
       case ConnectionStatus.stopped:
         currentImage = 'assets/images/main/stopped.gif';
         break;
+      case ConnectionStatus.connected:
+        currentImage = 'assets/images/main/stopped.gif';
+        break;
     }
   }
 

+ 4 - 0
lib/app/const/const.dart

@@ -163,6 +163,10 @@ class Files {
     return File(path.join(Paths.config.path, 'init_proxy.yaml'));
   }
 
+  static File get versionConfig {
+    return File(path.join(Paths.config.path, '.version.json'));
+  }
+
   static File get configCountryMmdb {
     return File(path.join(Paths.config.path, 'Country.mmdb'));
   }

+ 65 - 315
lib/app/controller/GlobalController.dart

@@ -1,19 +1,13 @@
-import 'dart:ffi';
 import 'dart:io';
-import 'package:flutter/services.dart';
 import 'package:flutter/widgets.dart';
 import 'package:get/get.dart';
 import 'package:naiyouwl/app/bean/proxie.dart';
 import 'package:naiyouwl/app/common/LogHelper.dart';
 import 'package:naiyouwl/app/common/SharedPreferencesUtil.dart';
-import 'package:naiyouwl/app/common/constants.dart';
 import 'package:naiyouwl/app/controller/controllers.dart';
 import 'package:naiyouwl/app/data/model/NodeMode.dart';
 import 'package:naiyouwl/app/network/api_service.dart';
-import 'package:naiyouwl/app/network/dio_client.dart';
-import 'package:naiyouwl/app/utils/shell.dart';
 import 'package:naiyouwl/app/utils/system_proxy.dart';
-import 'package:naiyouwl/app/utils/utils.dart';
 import 'package:proxy_manager/proxy_manager.dart';
 import 'package:shared_preferences/shared_preferences.dart';
 import 'package:tray_manager/tray_manager.dart';
@@ -21,11 +15,16 @@ import 'package:window_manager/window_manager.dart';
 import 'package:path/path.dart' as path;
 import 'package:wl_base_help/wl_base_help.dart';
 import '../clash/service/clash_service.dart';
+import '../common/constants.dart';
 import '../const/const.dart';
+import '../data/model/UserMode.dart';
+import '../network/dio_client.dart';
+import '../utils/shell.dart';
+import '../utils/utils.dart';
 
 class GlobalController extends GetxController {
   final proxyManager = ProxyManager();
-  bool systemProxy = false;
+  var systemProxy = false.obs;
   late BuildContext context;
   final List<String> modes = ['rule', 'global'];
   final List<String> routeModes = ['sys', 'tun'];
@@ -44,16 +43,9 @@ class GlobalController extends GetxController {
   final _wlBaseHelpPlugin = WlBaseHelp();
   var sysInfo = ''.obs;
   var sysVersion = kVersion.obs;
+  var connectStatus = false.obs;
 
   final selectedNode = Rx<NodeMode?>(null);
-  // // 策略组
-  // var proxieGroups = <ProxieProxiesItem>[].obs;
-  // // 代理集
-  // var proxieProviders = <ProxieProviderItem>[].obs;
-  // // 代理
-  // var proxieProxies = <ProxieProxiesItem>[].obs;
-  // // 所有节点
-  // var allProxies = <String, ProxieProxiesItem>{}.obs;
 
   final List<String> groupInternalTypes = ['DIRECT', 'REJECT', 'GLOBAL'];
   final List<String> groupTypes = [
@@ -62,150 +54,90 @@ class GlobalController extends GetxController {
     ProxieProxieType.fallback,
     ProxieProxieType.loadbalance,
   ];
+
   Future<void> init(BuildContext context) async {
     this.context = context;
     watchExit();
-    // if(Platform.isWindows){
-    //   createConsole();
-    //   hideConsole();
-    // }
+    await controllers.config.initConfig();
+    await controllers.cc_service.initConfig();
+    sysInfo.value =  await platformState();
     await SharedPreferencesUtil().delete("last_successful_url");
-    // init plugins
     await controllers.tray.initTray();
     controllers.window.initWindow();
+    await controllers.cc_service.isCanOperationService();
   }
 
-
   void updateMsg(String msg) {
     msgStatus.value = msg;
   }
 
   Future<void> updateMode(String route) async {
-    if(allowStatusUpdate){
-
-      return;
-    }
+    if(allowStatusUpdate) return;
     modesSelect.value = route;
-    final coreStatus = controllers.service.coreStatus.value;
-    if( coreStatus == RunningState.running){
-      controllers.core.fetchConfigUpdate({'mode': modesSelect.value});
-    }
+    await controllers.core.fetchConfigUpdate({
+      "mode": modesSelect.value
+    });
+    await controllers.global.swift(selectedNode.value?.name ?? "");
   }
 
   void updateUserInfo(User user) {
-    // 更新用户信息
-    if (user != null) {
-      // 可以根据需要更新相关的用户信息字段
-      // 例如:
-      // username.value = user.username;
-      // email.value = user.email;
-      // 等等...
-      
-      // 如果需要持久化存储用户信息,可以考虑使用 SharedPreferences
-      // SharedPreferencesUtil.setString('username', user.username);
-      
-      // 更新UI或其他相关状态
-      update();
-    }
+    update();
   }
-  Future<void> updateRoute(String route) async {
-    if(allowStatusUpdate){
 
-      return;
-    }
-    // if(route == "tun"){
-    //   final res = await showNormalDialog( context,content: '启用网卡模式需要管理员',title: '提示', cancelText: '取消', enterText: '确认安装');
-    //   if (res != true) return;
-    //   controllers.service.serviceModeSwitch(true);
-    // }
+  Future<void> updateRoute(String route) async {
+    if(allowStatusUpdate) return;
     routeModesSelect.value = route;
     LogHelper().d("当前ROUTE模式${routeModesSelect.value}");
   }
+
   Future<void> fetchNodes() async {
     nodeModes.value = await ApiService().getNode("/api/client/v4/nodes?vless=1");
-    //await makeProxy();
-    // if(controllers.service.coreStatus.value == RunningState.stoped){
-    //   await controllers.service.reloadClashCore();
-    // }
-    // if (controllers.service.coreStatus.value != RunningState.running) return;
-    // await controllers.core.updateVersion();
-    // await updateDate();
-    //
-
-
   }
 
-
-
-
   Future<void> updateNode() async {
     NodeMode? targetNode;
     if (selectedNode.value == null) {
       targetNode = await findNodeWithMinUsers(nodeModes);
+      selectedNode.value = targetNode;
     } else {
       targetNode = selectedNode.value;
     }
     if (targetNode != null){
       selectNode(targetNode);
       await swift(targetNode.name ?? "");
-
     }
   }
 
   Future<void> showConsole() async {
     await _wlBaseHelpPlugin.showConsole();
   }
+
   Future<void> hideConsole() async {
     await _wlBaseHelpPlugin.hideConsole();
   }
-  Future<void> startSysMode() async {
-
-    await makeProxy();
-
-    //await updateDate();
-  }
-  Future<void> startTunMode() async {
-    await makeProxy();
-  }
 
   Future<void> swift(String name) async {
-
     try{
       var g = "proxy";
-      if(modesSelect.value == "global")
-      {
+      if(modesSelect.value == "global") {
         g = "GLOBAL";
       }
 
       await controllers.core.fetchSetProxieGroup(g, name);
       final conn = await controllers.core.fetchConnection();
-      if(conn == null) { return; }
+      if(conn == null) return;
       for (final it in conn.connections) {
         if (it.chains.contains(name)) controllers.core.fetchCloseConnections(it.id);
       }
-    }catch (e) {
+    } catch (e) {
       //LogHelper().d(e.toString());
     }
-
-
-  }
-
-
-
-
-  Future<void> makeTestProxy() async {
-    final clashService = ClashService();
-
-    if (!await Paths.config.exists()) await Paths.config.create(recursive: true);
-    await clashService.saveConfigToFile(path.join(Paths.config.path, 'proxyfino.yaml'), nodeModes);
   }
+  // 创建代理配置文件
   Future<void> makeProxy() async {
-
-
-
-     await controllers.config.makeClashConfig(nodeModes);
-     // await controllers.service.reloadClashCore();
-
+    // final clashService = ClashService();
+    //if (!await Paths.config.exists()) await Paths.config.create(recursive: true);
+    await controllers.service.saveConfigToFile(path.join(Paths.config.path, Files.makeProxyConfig.path), nodeModes);
   }
   Future<NodeMode> findNodeWithMinUsers(List<NodeMode> nodes) async {
     return nodes
@@ -214,13 +146,6 @@ class GlobalController extends GetxController {
   }
 
 
-
-
-  Future<SystemProxyConfig> getSysProxy() async{
-     return  await SystemProxy.instance.get();
-  }
-
-
   Future<void> TunProxySwitch(bool open) async {
     tunProxySwitchIng.value = true;
     routeModesSelect.value = open ? "tun": "sys";
@@ -228,119 +153,24 @@ class GlobalController extends GetxController {
     tunProxySwitchIng.value = false;
   }
 
-
-
   Future<void> systemProxySwitch(bool open) async {
     systemProxySwitchIng.value = true;
-    //await SystemProxy.instance.set(open ? controllers.core.proxyConfig : SystemProxyConfig());
-    await controllers.config.setSystemProxy(open);
-    if(open)
-    {
-      await openProxy();
-
-    } else {
-      await closeProxy();
-
-    }
     systemProxySwitchIng.value = false;
   }
 
-  // Future<dynamic> _updateProxie() async {
-  //   final proxie = await controllers.core.fetchProxie();
-  //   final global = proxie.proxies["GLOBAL"]!;
-  //   proxieGroups.value = global.all!
-  //       .where((it) => !groupInternalTypes.contains(it) && groupTypes.contains(proxie.proxies[it]!.type))
-  //       .map((it) => proxie.proxies[it]!)
-  //       .toList();
-  //   proxieProxies.value = global.all!
-  //       .where((it) => !groupInternalTypes.contains(it) && !groupTypes.contains(proxie.proxies[it]!.type))
-  //       .map((it) => proxie.proxies[it]!)
-  //       .toList();
-  //   if (controllers.core.config.value.mode == 'global') proxieGroups.insert(0, global);
-  // }
-  //
-  // Future<dynamic> _updateProxieProvider() async {
-  //   proxieProviders.value = (await controllers.core.fetchProxieProvider()).providers.values.where((it) => it.vehicleType != 'Compatible').toList();
-  //   for (final it in proxieProviders) {
-  //     it.proxies.sort((a, b) {
-  //       if (a.delay == 0) return 1;
-  //       if (b.delay == 0) return -1;
-  //       return a.delay - b.delay;
-  //     });
-  //   }
-  // }
-
-  // Future<void> updateDate() async {
-  //   //LogHelper().d('controller.proxie.updateDate()');
-  //   try
-  //   {
-  //     await controllers.core.updateConfig();
-  //     await _updateProxie();
-  //     await _updateProxieProvider();
-  //     allProxies.clear();
-  //     for (final provide in proxieProviders) {
-  //       for (final it in provide.proxies) {
-  //         allProxies[it.name] = it;
-  //       }
-  //     }
-  //     for (final it in proxieProxies) {
-  //       allProxies[it.name] = it;
-  //       //LogHelper().d('controller.proxieProxies');
-  //     }
-  //     for (final it in proxieGroups) {
-  //       allProxies[it.name] = it;
-  //       //LogHelper().d('controller.proxieGroups');
-  //     }
-  //     proxieGroups.refresh();
-  //     proxieProxies.refresh();
-  //     proxieProviders.refresh();
-  //     allProxies.refresh();
-  //   } catch (e){
-  //     LogHelper().d("updateDate -- ${e.toString()}");
-  //   }
-  //
-  // }
-
-
-  // Future<void> handleSetProxieGroup(ProxieProxiesItem proxie, String value) async {
-  //   if (proxie.now == value) return;
-  //   await controllers.core.fetchSetProxieGroup(proxie.name, value);
-  //   await updateDate();
-  //   if (controllers.config.config.value.breakConnections) {
-  //     final conn = await controllers.core.fetchConnection();
-  //     for (final it in conn.connections) {
-  //       if (it.chains.contains(proxie.name)) controllers.core.fetchCloseConnections(it.id);
-  //     }
-  //   }
-  // }
-  //
-  // Future<void> handleSetSelectProxieGroup(NodeMode proxie, String value) async {
-  //   if (proxie.name == value) return;
-  //   await controllers.core.fetchSetProxieGroup(proxie.name ?? "", value);
-  //   await updateDate();
-  //   final conn = await controllers.core.fetchConnection();
-  //   for (final it in conn.connections) {
-  //     if (it.chains.contains(proxie.name)) controllers.core.fetchCloseConnections(it.id);
-  //   }
-  // }
-
   void watchExit() {
-    // watch process kill
-    // ref https://github.com/dart-lang/sdk/issues/12170
     if (Platform.isMacOS) {
-      // windows not support https://github.com/dart-lang/sdk/issues/28603
-      // for macos 任务管理器退出进程
       ProcessSignal.sigterm.watch().listen((_) {
         stdout.writeln('exit: sigterm');
         handleExit();
       });
     }
-    // for macos, windows ctrl+c
     ProcessSignal.sigint.watch().listen((_) {
       stdout.writeln('exit: sigint');
       handleExit();
     });
   }
+
   void selectNode(NodeMode node) {
     nodeId.value = node.id ?? 0;
     controllers.global.selectedNode.value = node;
@@ -349,46 +179,19 @@ class GlobalController extends GetxController {
 
   Future<void> _storeSelectedNode(NodeMode node) async {
     final prefs = await SharedPreferences.getInstance();
-    // 为简化起见,我们只存储node的ID,但您可以根据需要存储更多信息
-
     prefs.setInt('selectedNodeId', node.id ?? -1);
     await loadSelectedNode();
   }
 
-
   Future<void> loadSelectedNode() async {
     final prefs = await SharedPreferences.getInstance();
     final selectedNodeId = prefs.getInt('selectedNodeId');
     if (selectedNodeId != null) {
-      //selectedIndex.value = nodeModes.indexWhere((item) => item.id == selectedNodeId);
       selectedNode.value = nodeModes.firstWhere((node) => node.id == selectedNodeId);
     }
   }
 
-
-  void initRegularlyUpdate() {
-    Future.delayed(const Duration(minutes: 5)).then((_) async {
-      for (final it in controllers.config.config.value.subs) {
-        try {
-          if (it.url == null || it.url!.isEmpty) continue;
-          if (((DateTime.now().millisecondsSinceEpoch ~/ 1000) - (it.updateTime ?? 0)) < controllers.config.config.value.updateInterval) continue;
-          final chenged = await controllers.config.updateSub(it);
-          if (!chenged) continue;
-          if (it.name != controllers.config.config.value.selected) continue;
-          // restart clash core
-          await controllers.service.reloadClashCore();
-          await Future.delayed(const Duration(seconds: 20));
-        } catch (_) {}
-      }
-      initRegularlyUpdate();
-    });
-  }
-  /// 打开代理
-
   Future<void> openProxy() async {
-
-
-
     int? port = controllers.config.mixedPort.value;
     if (port == 0) {
       port = null;
@@ -403,69 +206,27 @@ class GlobalController extends GetxController {
     }
     port = port ?? mixedPort ?? 0;
     if (port != 0) {
-      if(Platform.isWindows){
-        String loa = '127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*';
-        int? exitCode;
-        // Process sysproxy = await Process.start(Files.assetsSysProxyWin.path,,mode: ProcessStartMode.inheritStdio);
-        // sysproxy.exitCode.then((code) => exitCode = code);
-        try {
-          var result = await Process.run(
-            Files.assetsSysProxyWin.path,
-            ['global','127.0.0.1:$port',loa],
-            runInShell: true,
-          );
-          LogHelper().d(result.stderr);
-          LogHelper().d(result.stdout);
-        } on ProcessException catch (e) {
-          //.e('Failed to start $coreName: ${e.message}');
-          await proxyManager.setAsSystemProxy(
-            ProxyTypes.http,
-            "127.0.0.1",
-            port,
-          );
-
-          await proxyManager.setAsSystemProxy(
-            ProxyTypes.https,
-            "127.0.0.1",
-            port,
-          );
-          await proxyManager.setAsSystemProxy(
-            ProxyTypes.socks,
-            "127.0.0.1",
-            port,
-          );
-        }
-      } else {
-        await proxyManager.setAsSystemProxy(
-          ProxyTypes.http,
-          "127.0.0.1",
-          port,
-        );
-        await proxyManager.setAsSystemProxy(
-          ProxyTypes.https,
-          "127.0.0.1",
-          port,
-        );
+      await proxyManager.setAsSystemProxy(
+        ProxyTypes.http,
+        "127.0.0.1",
+        port,
+      );
+      await proxyManager.setAsSystemProxy(
+        ProxyTypes.https,
+        "127.0.0.1",
+        port,
+      );
+
+      await proxyManager.setAsSystemProxy(
+        ProxyTypes.socks,
+        "127.0.0.1",
+        port,
+      );
 
-        await proxyManager.setAsSystemProxy(
-          ProxyTypes.socks,
-          "127.0.0.1",
-          port,
-        );
-        systemProxy = true;
-      }
     }
 
-
-
-    //
-    // port = port ?? mixedPort ?? 0;
-    // if (port != 0) {
-
-    // }
     socksPort = socksPort ?? mixedPort ?? 0;
     if (socksPort != 0) {
-
       if (!Platform.isWindows) {
         await proxyManager.setAsSystemProxy(
           ProxyTypes.socks,
@@ -473,57 +234,48 @@ class GlobalController extends GetxController {
           socksPort,
         );
       }
-      systemProxy = true;
+
     }
-  }
 
-  /// 关闭代理
+    systemProxy.value = true;
+  }
 
   Future<void> closeProxy() async {
-    //
-    if (Platform.isWindows) {
-      try {
-        var result =  await Process.run(
-          Files.assetsSysProxyWin.path,
-          ['set','1','','',''],
-          runInShell: true,
-        );
-        LogHelper().d(result.stderr);
-        LogHelper().d(result.stdout);
-      } on ProcessException catch (e) {
-        //.e('Failed to start $coreName: ${e.message}');
-        throw Exception('Failed to start sysproxy: ${e.message}');
-      }
-      proxyManager.cleanSystemProxy();
-    }
-
-    systemProxy = false;
+    await proxyManager.cleanSystemProxy();
+    systemProxy.value = false;
   }
+
   Future<void> stopAllCore() async {
     await systemProxySwitch(false);
     if(Platform.isWindows){
       await controllers.service.stopClashCore();
     } else if(Platform.isMacOS) {
-      await controllers.cc_service.fetchStop();
+      if (controllers.cc_service.serviceIsRuning) {
+        await controllers.cc_service.fetchStop();
+      } else {
+        await controllers.service.stopClashCore();
+      }
+
     }
-    if(!controllers.service.serviceMode.value){{
+    if(!controllers.service.serviceMode.value){
       if(Platform.isWindows){
-        await onKillProcess(path.basename(Files.assetsCCore.path));
+        await onKillProcess(path.basename(Files.assetsClashService.path));
       }
       await killProcess(path.basename(Files.assetsCCore.path));
-    }}
+      await killProcess(path.basename(Files.assetsClashService.path));
+    }
 
     if(!controllers.service.serviceMode.value){
       await killProcess(path.basename(Files.assetsClashService.path));
     }
-
   }
+
   Future<void> handleExit() async {
     await stopAllCore();
     await trayManager.destroy();
     await windowManager.destroy();
-    // exit(0);
   }
+
   void handleApiError(dynamic error) {
     if (error is AppException) {
       LogHelper().d('API error with status code: ${error.statusCode}');
@@ -533,14 +285,12 @@ class GlobalController extends GetxController {
       LogHelper().d('Other error: $error');
       errorMsg.value = error.toString();
     }
-
   }
 
   @override
   void dispose() {
     controllers.tray.dispose();
     controllers.window.dispose();
-    //controllers.protocol.dispose();
     super.dispose();
   }
 }

+ 104 - 9
lib/app/controller/config.dart

@@ -1,5 +1,6 @@
 import 'dart:io';
 import 'dart:convert';
+import 'dart:ui';
 import 'package:get/get.dart';
 import 'package:naiyouwl/app/clash/mode/config.dart';
 import 'package:naiyouwl/app/clash/mode/clash_config.dart';
@@ -11,6 +12,8 @@ import 'package:yaml/yaml.dart';
 import 'package:yaml_edit/yaml_edit.dart';
 import 'package:flutter_emoji/flutter_emoji.dart';
 
+import '../common/constants.dart';
+
 final Map<String, dynamic> _defaultConfig = {
   'selected': 'example.yaml',
   'updateInterval': 86400,
@@ -22,8 +25,15 @@ final Map<String, dynamic> _defaultConfig = {
   'servicePort': 9899,
 };
 
+final Map<String, dynamic> _defaultVersionConfig = {
+  'serviceVersion': '1.0.0',
+  'coreVersion': '1.18.8',
+  'appVersion': kVersion,
+};
+
 class ConfigController extends GetxController {
   var config = GuiConfig.fromJson(_defaultConfig).obs;
+  var versionConfig = VersionConfig.fromJson(_defaultVersionConfig).obs;
 
   var clashCoreApiAddress = '127.0.0.1:9799'.obs;
   var clashCoreApiSecret = ''.obs;
@@ -31,10 +41,27 @@ class ConfigController extends GetxController {
   var clashCoreTunEnable = false.obs;
   var mixedPort = 9788.obs;
   var apiAddressPort = 9799.obs;
+  var servicePort  = 9899.obs;
 
   Future<void> initConfig() async {
+
+    if (await Paths.config.exists()) {
+      if (await Files.versionConfig.exists()) {
+        final localVersionConfig = json.decode(await Files.versionConfig.readAsString());
+        final localAppVersion = localVersionConfig['appVersion'];
+        if (compareVersions(localAppVersion, kVersion) < 0) {
+          await Paths.config.delete(recursive: true);
+          await Paths.config.create(recursive: true);
+        }
+      } else {
+        await Paths.config.delete(recursive: true);
+        await Paths.config.create(recursive: true);
+      }
+    }
     // 创建用户配置目录
-    if (!await Paths.config.exists()) await Paths.config.create(recursive: true);
+    if (!await Paths.config.exists()) {
+      await Paths.config.create(recursive: true);
+    }
 
     // 复制资源文件到配置目录
     await _copyAssetToConfig(Files.assetsCountryMmdb, Files.configCountryMmdb);
@@ -56,11 +83,41 @@ class ConfigController extends GetxController {
       config.value = GuiConfig.fromJson(_defaultConfig);
     }
 
+    // 读取或创建版本配置文件
+    if (await Files.versionConfig.exists()) {
+      final local = json.decode(await Files.versionConfig.readAsString());
+      versionConfig.value = VersionConfig.fromJson({..._defaultVersionConfig, ...local});
+    } else {
+      versionConfig.value = VersionConfig.fromJson(_defaultVersionConfig);
+    }
+
+    print(Files.configConfig.path);
+
     // 保存 GuiConfig 到 gui_config.json
     await saveGuiConfig();
 
+    // 保存 VersionConfig 到 version_config.json
+    await saveVersionConfig();
+
     await makeInitConfig();
   }
+  
+  // 比较两个版本号
+  int compareVersions(String v1, String v2) {
+    var parts1 = v1.split('.');
+    var parts2 = v2.split('.');
+    
+    for (int i = 0; i < 3; i++) {
+      int p1 = int.parse(parts1[i]);
+      int p2 = int.parse(parts2[i]);
+      if (p1 != p2) {
+        return p1 - p2;
+      }
+    }
+    
+    return 0;
+  }
+
   // 返回一个可修改的 GUI 配置对象
   GuiConfig getEditableGuiConfig() {
     return config.value;
@@ -72,18 +129,31 @@ class ConfigController extends GetxController {
     await saveGuiConfig();
   }
 
+  // 返回一个可修改的版本配置对象
+  VersionConfig getEditableVersionConfig() {
+    return versionConfig.value;
+  }
+
+  // 更新版本配置
+  Future<void> updateVersionConfig(VersionConfig updatedVersionConfig) async {
+    versionConfig.value = updatedVersionConfig;
+    await saveVersionConfig();
+  }
+
   // 示例使用方法:
   // var editableConfig = getEditableGuiConfig();
   // editableConfig.language = 'en_US';
   // editableConfig.startAtLogin = true;
   // await updateGuiConfig(editableConfig);
 
-
-
   Future<void> saveGuiConfig() async {
     await Files.configConfig.writeAsString(json.encode(config.value.toJson()));
   }
 
+  Future<void> saveVersionConfig() async {
+    await Files.versionConfig.writeAsString(json.encode(versionConfig.value.toJson()));
+  }
+
   Future<void> _copyAssetToConfig(File source, File destination) async {
     if (!await destination.exists()) {
       await source.copy(destination.path);
@@ -99,10 +169,13 @@ class ConfigController extends GetxController {
     print("clash api address ${clashCoreApiAddress.value}");
     clashCoreApiSecret.value = (configMap['secret'] as String? ?? '');
     mixedPort.value = (configMap['mixed-port'] as int? ?? 9788);
-    clashCoreTunEnable.value = (configMap['tun'] as YamlMap?)?['enable'] as bool == true;
+
+
+    var tun =  (configMap['tun'] as YamlMap?)?['enable'];
+    clashCoreTunEnable.value = tun == null ? false : tun;
     clashCoreDns.value = '';
-    if ((configMap['dns'] as YamlMap?)?['enable'] as bool == true &&
-        ((configMap['dns'] as YamlMap?)?['listen'] as String? ?? '').isNotEmpty) {
+    var dnsEnable = (configMap['dns'] as YamlMap?)?['enable'];
+    if(dnsEnable != null) {
       final dns = ((configMap['dns'] as YamlMap)['listen'] as String? ?? '').split(':');
       if (dns.length == 2) {
         final ip = dns[0];
@@ -115,7 +188,7 @@ class ConfigController extends GetxController {
   }
 
   Future<void> makeInitConfig() async {
-    var mode = Get.find<Controllers>().global.modesSelect.value;
+    var mode = controllers.global.modesSelect.value;
     
     var clashConfig = ClashConfig(
       mixedPort: mixedPort.value,
@@ -129,14 +202,36 @@ class ConfigController extends GetxController {
       tcpConcurrent: false,
       findProcessMode: 'strict',
       globalClientFingerprint: 'chrome',
+        dns: DNS(
+          enable: false,
+          listen: kDnsListenPort,
+          ipv6: false,
+          enhancedMode: kRedirHostMode,
+          fakeIpFilter: null,
+          nameserver: kDomesticDNS,
+          proxyServerNameserver: kDomesticDNS,
+          nameserverPolicy: {
+            'geosite:cn,private': kDomesticDNS,
+            'geosite:geolocation-!cn': kForeignDNS,
+          },
+        ),
+        tun: Tun(
+          enable: false,
+          stack: 'system',
+          autoRoute: true,
+          autoRedirect: true,
+          autoDetectInterface: true,
+          dnsHijack: ['any:53'],
+        ),
       proxies: [],
+
       rules: [
         'GEOIP,CN,DIRECT',
         'MATCH,DIRECT'
-      ], dns: null
+      ]
     );
 
-    final initConfigFile = File(path.join(Paths.config.path, 'init.yaml'));
+    final initConfigFile = File(path.join(Paths.config.path, Files.makeInitProxyConfig.path ));
     await initConfigFile.writeAsString(clashConfig.toYaml());
   }
 

+ 15 - 2
lib/app/controller/core.dart

@@ -146,9 +146,22 @@ class CoreController extends GetxController {
 
   Future<void> fetchConfigUpdate(Map<String, dynamic> config) async {
     try {
-      var ut = Uri.parse('http://$url/configs?force=true');
-      final res = await  client.patch(ut,headers: headers);
+
+      ///configs
+      ///
+      // {"mode":"global"}
+      //请求 URL:
+      // http://127.0.0.1:9799/configs
+      // 请求方法:
+      // PATCH
+      var ut = Uri.parse('http://$url/configs');
+      final res = await client.patch(ut, headers: headers, body: jsonEncode(config));
       print("fetchConfigUpdate ---- ${res.statusCode}");
+      if (res.statusCode == 204) {
+        print("配置更新成功");
+      } else {
+        print("配置更新失败,状态码: ${res.statusCode}");
+      }
       // var jsonResponse =
       // jsonDecode(res.body) as Map<String, dynamic>;
       // print(jsonResponse);

+ 81 - 16
lib/app/controller/service.dart

@@ -12,18 +12,24 @@ import 'package:naiyouwl/app/utils/shell.dart';
 import 'package:path/path.dart' as path;
 import 'package:http/http.dart' as http;
 
-import '../clash/service/clash_service.dart';
+import '../utils/utils.dart';
 
 final headers = {"User-Agent": "ccore-for-flutter/0.0.1"};
 
 class ServiceController extends GetxController {
 
-  var url = "127.0.0.1:${controllers.config.config.value.servicePort}";
+  var url = "";
   var client = http.Client();
   var serviceMode = false.obs;
   var coreStatus = RunningState.stoped.obs;
   var serviceStatus = RunningState.stoped.obs;
+  var installStatus = false.obs; // 新增变量用于记录安装/卸载状态
+  bool get serviceIsRuning => serviceStatus.value == RunningState.running;
 
+  Future<void> initConfig() async{
+    url = "127.0.0.1:${controllers.config.config.value.servicePort}";
+    //controllers.config.setSerivcePort(controllers.config.config.value.servicePort);
+  }
 
   Future<void> startTunService() async {
     try {
@@ -56,8 +62,9 @@ class ServiceController extends GetxController {
   }
 
   Future<void> fetchStartInit() async {
-    controllers.config.config.value.selected = 'init_proxy.yaml';
-    controllers.global.updateMsg("启动内核---${controllers.config.config.value.selected}");
+
+    controllers.config.config.value.selected = Files.makeInitProxyConfig.path;
+    controllers.global.updateMsg("服务模式初始化...");
     await fetchStop();
 
     try {
@@ -76,13 +83,15 @@ class ServiceController extends GetxController {
         coreStatus.value = RunningState.error;
         throw jsonResponse["msg"];
       }
+      controllers.global.updateMsg("服务模式初始化成功..");
       coreStatus.value = RunningState.running;
     } catch (e) {
       print('Exception: $e');
       coreStatus.value = RunningState.error;
+      controllers.global.updateMsg("服务模式初始化失败..");
     }
   }
-
+ //应该程序退出调用
   Future<void> fetchStop() async {
     try {
       var ut = Uri.http(url, 'stop');
@@ -136,25 +145,45 @@ class ServiceController extends GetxController {
     while (true) {
       await Future.delayed(const Duration(milliseconds: 100));
       try {
-        await client.post(Uri.http(url, 'info'), headers: headers);
+        await isCanOperationService();
         break;
       } catch (_) {}
     }
   }
 
   Future<void> install() async {
+    try {
+      final res = await runAsAdmin(Files.assetsClashService.path, ["-port", "${controllers.config.config.value.servicePort}", "stop", "uninstall", "install", "start"]);
 
-    final res = await runAsAdmin(Files.assetsClashService.path, ["-port", "${controllers.config.config.value.servicePort}", "stop", "uninstall", "install", "start"]);
+      log.debug('install', res.stdout, res.stderr);
+
+      if (res.exitCode != 0) {
+
+        throw res.stderr;
+      }
 
-    log.debug('install', res.stdout, res.stderr);
-    if (res.exitCode != 0) throw res.stderr;
-    await waitServiceStart();
+      await waitServiceStart();
+      serviceStatus.value = RunningState.running;
+      installStatus.value = true; // 安装成功
+    } catch (e) {
+      installStatus.value = false; // 安装失败
+      log.debug('安装失败: $e');
+      throw e;
+    }
   }
 
   Future<void> uninstall() async {
-    final res = await runAsAdmin(Files.assetsClashService.path, ["stop", "uninstall"]);
-    log.debug('uninstall', res.stdout, res.stderr);
-    if (res.exitCode != 0) throw res.stderr;
+    try {
+      final res = await runAsAdmin(Files.assetsClashService.path, ["stop", "uninstall"]);
+      log.debug('uninstall', res.stdout, res.stderr);
+      if (res.exitCode != 0) throw res.stderr;
+      installStatus.value = false; // 卸载成功
+      serviceStatus.value = RunningState.stoped;
+    } catch (e) {
+      installStatus.value = true; // 卸载失败
+      log.debug('卸载失败: $e');
+      throw e;
+    }
   }
 
   Future<void> stopService() async {
@@ -165,20 +194,56 @@ class ServiceController extends GetxController {
 
   Future<void> serviceModeSwitch(bool open) async {
     if (serviceStatus.value == RunningState.running) await stopService();
-    if (coreStatus.value == RunningState.running) await controllers.service.stopClashCore();
+    await controllers.service.stopClashCore();
+    await fetchStop();
     try {
       controllers.global.updateMsg(open ? "安装服务" : "卸载服务");
       open ? await install() : await uninstall();
     } catch (e) {
       print(e.toString());
     }
-    await fetchStartInit();
+    if(open)
+    {
+      await fetchStartInit();
+    }
+  }
+
+  Future<void> stopClash() async {
+    controllers.config.config.value.selected = Files.makeInitProxyConfig.path;
+    if (coreStatus.value == RunningState.running) {
+      await controllers.config.readClashCoreApi();
+      controllers.core.setApi(controllers.config.clashCoreApiAddress.value, controllers.config.clashCoreApiSecret.value);
+      await controllers.core.changeConfig(path.join(Paths.config.path, controllers.config.config.value.selected));
+    }
+  }
+
+  Future<void> reloadClashCore() async {
+    try {
+      controllers.config.config.value.selected = Files.makeProxyConfig.path;
+      if (coreStatus.value == RunningState.running) {
+        controllers.global.updateMsg("切换配置...");
+        await controllers.config.readClashCoreApi();
+        controllers.core.setApi(controllers.config.clashCoreApiAddress.value, controllers.config.clashCoreApiSecret.value);
+        await controllers.core.changeConfig(path.join(Paths.config.path, controllers.config.config.value.selected));
+        controllers.global.updateMsg("fetchReloadConfig${controllers.config.clashCoreApiAddress.value}...");
+      }
+    } catch (e) {
+      controllers.global.updateMsg("重新配置...");
+      await controllers.config.readClashCoreApi();
+      controllers.core.setApi(controllers.config.clashCoreApiAddress.value, controllers.config.clashCoreApiSecret.value);
+      await controllers.core.changeConfig(path.join(Paths.config.path, controllers.config.config.value.selected));
+    }
   }
 
   Future<bool> isCanOperationService() async {
     try {
       final res = await client.post(Uri.http(url, 'info'), headers: headers);
-      return res.statusCode == 200;
+      if(res.statusCode == 200)
+      {
+        serviceStatus.value = RunningState.running;
+      }
+
+      return installStatus.value = res.statusCode == 200;
     } catch (e) {
       print('Exception when checking service: $e');
       return false;

+ 5 - 5
lib/app/controller/tray.dart

@@ -59,7 +59,7 @@ class TrayController extends GetxController with TrayListener {
       // ),
       MenuItem.submenu(
         label: 'proxie_group_title'.tr,
-        disabled: disabled,
+        disabled: false,
         submenu: Menu(
           items: controllers.global.nodeModes.map((it) =>
               MenuItem.checkbox(
@@ -77,8 +77,8 @@ class TrayController extends GetxController with TrayListener {
       // ),
       MenuItem.checkbox(
         label: 'setting_set_as_system_proxy'.tr,
-        checked: controllers.config.config.value.setSystemProxy,
-        disabled: disabled || controllers.global.systemProxySwitchIng.value,
+        checked: controllers.global.systemProxy.value,
+        disabled: false, //disabled || controllers.global.systemProxySwitchIng.value
         onClick: handleClickSetAsSystemProxy,
       ),
       MenuItem.checkbox(
@@ -89,8 +89,8 @@ class TrayController extends GetxController with TrayListener {
       ),
       MenuItem.checkbox(
         label: 'setting_service_open'.tr,
-        checked: controllers.service.serviceMode.value,
-        disabled: disabledSerivce == false ? !await controllers.cc_service.isCanOperationService() : disabledSerivce,
+        checked: controllers.cc_service.installStatus.value,
+        disabled: disabledSerivce,
         onClick: handleClickServiceModeSwitch,
       ),
       MenuItem.submenu(

+ 96 - 5
lib/app/modules/home/controllers/home_controller.dart

@@ -51,12 +51,15 @@ class HomeController extends GetxController {
   var errAdminMsg = false.obs;
   var errAdmin = ''.obs;
   var isInit = false.obs;
-  var isServiceInstall = false.obs;
+
 
   bool get isRunning =>
-      connectStatus.value == ConnectionStatus.stopped &&
+      connectStatus.value == ConnectionStatus.connected &&
           controllers.global.allowStatusUpdate;
+
+
   late final GlobalController globalController = controllers.global;
+
   StreamSubscription<RunningState>? _statusSubscription;
   final Map<ImageType, String> imageMap = {
     ImageType.CUSTOMER: "assets/images/main/customer.png",
@@ -114,20 +117,108 @@ class HomeController extends GetxController {
       return;
     }
 
-    if (connectStatus.value == ConnectionStatus.stopped) {
+    if (connectStatus.value == ConnectionStatus.connected) {
       await connectionService.stopConnection();
     } else {
-      await connectionService.startConnection();
+      updateStatus(ConnectionStatus.connecting);
+
+      // 检查服务是否运行
+      if (!controllers.cc_service.serviceIsRuning) {
+        // 尝试获取 hello 的返回结果并处理
+        var hellow = await controllers.core.fetchHello();
+
+        // 如果获取不到 hellow,则重试启动内核
+        if (hellow == null) {
+          controllers.global.updateMsg("尝试重新启动内核");
+          bool success = await restartClashCoreWithRetry(maxRetries: 3);  // 重试 3 次
+          if (!success) {
+            controllers.global.updateMsg("内核重启失败,已达到最大重试次数");
+            return;  // 如果重启失败,直接返回,阻止继续进行
+          }
+        }
+      }
+
+      await Future.delayed(Duration(seconds: 3)); // 等待核心状态更新
+      // 继续后面的逻辑
+      var error = await networkService.fetchAuthUser();
+
+      // 根据 error 的结果继续处理
+      if (error == "") {
+        await connectionService.startConnection();
+      } else {
+        globalController.updateMsg("验证失败,{$error}");
+      }
+    }
+  }
+
+  // 重试机制,确保内核重启
+  Future<bool> restartClashCoreWithRetry({int maxRetries = 3}) async {
+    int attempts = 0;
+    bool success = false;
+
+    while (attempts < maxRetries && !success) {
+      attempts++;
+      controllers.global.updateMsg("正在尝试第 $attempts 次重启内核...");
+
+      await controllers.service.stopClashCore();
+      success = await controllers.service.initClashCoreConfig();
+
+      if (success) {
+        controllers.global.updateMsg("第 $attempts 次重启内核成功!");
+      } else {
+        controllers.global.updateMsg("第 $attempts 次重启内核失败...");
+        await Future.delayed(Duration(seconds: 2));  // 等待2秒再重试
+      }
     }
+
+    return success;
   }
 
+  void init(){
+    Future.delayed(Duration.zero, () async {
+      isLoading.value = true;
+      var userinfo = await networkService.fetchUserinfo();
+      if(userinfo != null )
+      {
+         userMode.value = userinfo;
+      }
+
+      var sysconfig = await networkService.fetchUserSysConfig();
+      if(sysconfig != null){
+        UsersysConfig.value = sysconfig;
+      }
+
+
+      var localUser =  await userService.fetchLocalUser();
+      if(localUser != null){
+        localUsers.value = localUser;
+      }
+      await controllers.global.fetchNodes();
+      nodeModes =  controllers.global.nodeModes;
+      await connectionService.coreInit();
+
+      await Future.delayed(Duration(seconds: 3)); // 等待核心状态更新
+
+      isLoading.value = false;
+    });
+  }
   @override
   void onInit() {
     super.onInit();
     connectionService = ConnectionService(controllers.global, updateStatus);
     _statusSubscription =
         controllers.service.coreStatus.stream.listen(_handleStateChange);
+    init();
   }
 
-// 其他方法保持不变...
+  bool   GetEnable()  => userMode.value.enable == 1;
+  String GetUserName() => localUsers.value.email.toString();
+  String GetExpiredAt() => "到期时间:${userMode.value.expiredAt}";
+  String GetTraffic() => "用户流量:${userMode.value.unusedTraffic}";
+  String GetNode() => controllers.global.selectedNode.value?.name ?? "未选择节点";
+  String getHttp() => "http 127.0.0.1:${controllers.config.mixedPort.value}";
+  String getSocket() => "sock 127.0.0.1:${controllers.config.mixedPort.value}";
+  String getSerivce() => "${controllers.config.servicePort.value}";
+
+  void RouteNode() =>  Get.toNamed(Routes.NODE);
 }

+ 47 - 22
lib/app/modules/home/views/home_view.dart

@@ -7,7 +7,9 @@ import 'package:naiyouwl/app/component/connection_status.dart';
 import 'package:naiyouwl/app/component/connection_widget.dart';
 import 'package:naiyouwl/app/component/sys_app_bar.dart';
 import 'package:naiyouwl/app/controller/controllers.dart';
+import 'package:naiyouwl/app/data/model/UserMode.dart';
 import 'package:url_launcher/url_launcher.dart';
+import '../../../utils/shell.dart';
 import '../controllers/home_controller.dart';
 
 class HomeView extends GetView<HomeController> {
@@ -32,12 +34,12 @@ class HomeView extends GetView<HomeController> {
                 icon: const Icon(Icons.refresh),
                 tooltip: '刷新节点',
                 onPressed: () {
-                  controller.fetchNode();
+                  controller.networkService.fetchNode();
                 },
               ),
               IconButton(
                 onPressed: () {
-                  controller.outlogin();
+                  controller.networkService.outlogin();
                 },
                 tooltip: '切换账号', 
                 icon: const Icon(Icons.exit_to_app)
@@ -57,7 +59,7 @@ class HomeView extends GetView<HomeController> {
               );
               if (result != null && result) {
                 if(Platform.isWindows){
-                  await controllers.global.onRunAdmin();
+                  await  onRunAdmin();
                 }
               }
             });
@@ -94,7 +96,13 @@ class HomeView extends GetView<HomeController> {
                     userTraffic: controller.GetTraffic(),
                     onRefresh: () async {
                       if (!controller.isLoading.value) {
-                        await controller.fetchUserinfo();
+
+                        var userinfo = await controller.networkService.fetchUserinfo();
+                        if(userinfo != null )
+                        {
+                          controller.userMode.value = userinfo;
+                        }
+
                       }
                     },
                   ),
@@ -130,11 +138,12 @@ class HomeView extends GetView<HomeController> {
                   ConnectionWidget(
                     status: controller.connectStatus.value, 
                     onTap: () {
-                      if(controller.isConnect.value){
-                        controller.stopVpn();
-                      } else {
-                        controller.fetchAuthUser();
-                      }
+                      controller.handleButtonClick();
+                      // if(controller.isConnect.value){
+                      //   controller.connectionService.stopConnection();
+                      // } else {
+                      //   controller.networkService.fetchAuthUser();
+                      // }
                     },
                   ),
                   Align(
@@ -174,19 +183,6 @@ class HomeView extends GetView<HomeController> {
                             controllers.global.updateMode(controllers.global.modes[idx])
                           },
                         ),
-                        const SizedBox(width: 20),
-                        if (Platform.isMacOS)
-                          ElevatedButton(
-                            onPressed: () async {
-                              if (controller.isServiceInstall.value) {
-                                await controller.UninstallService();
-                              } else {
-                                await controller.installService();
-                              }
-                              await controller.checkServiceInstallation();
-                            },
-                            child: Text(controller.isServiceInstall.value ? '卸载服务' : '安装服务'),
-                          ),
                       ],
                     ),
                   ),
@@ -275,3 +271,32 @@ class UserStatusWidget extends StatelessWidget {
     );
   }
 }
+
+
+/*
+ const SizedBox(width: 20),
+                        if (Platform.isMacOS)
+                          ElevatedButton(
+                            onPressed: () async {
+                              if (controllers.cc_service.installStatus.value) {
+                                if(!controller.isRunning)
+                                {
+                                  await controller.connectionService.UninstallService();
+                                } else {
+                                  controllers.global.errorMsg.value = "先停止连接,在尝试";
+                                }
+                              } else {
+
+                                if(!controller.isRunning)
+                                {
+                                  await controller.connectionService.installService();
+                                } else {
+                                  controllers.global.errorMsg.value = "先停止连接,在尝试";
+                                }
+
+                              }
+                              // await controller.connectionService.checkServiceInstallation();
+                            },
+                            child: Text(controllers.cc_service.installStatus.value ? '卸载服务' : '安装服务'),
+                          ),
+*/

+ 11 - 3
lib/app/modules/node/controllers/node_controller.dart

@@ -169,12 +169,20 @@ class NodeController extends GetxController {
     nodesToShow.value = nodes; // 使用 assignAll() 方法触发更新
   }
 
-
+  void init(){
+    Future.delayed(Duration.zero, () async {
+      isLoading.value = true;
+      nodeModes =  controllers.global.nodeModes;
+      nodesToShow.value = nodeModes;
+
+      isLoading.value = false;
+    });
+  }
   @override
   void onInit() {
     super.onInit();
-    nodeModes =  controllers.global.nodeModes;
-    nodesToShow.value = nodeModes;
+    init();
+
   }
 
   @override

+ 2 - 0
lib/app/network/api_service.dart

@@ -45,6 +45,8 @@ class ApiService {
     } else {
       throw Exception("Failed API response is NUll");
     }
+
+
   }
 
 

+ 3 - 0
lib/app/network/dio_client.dart

@@ -47,6 +47,7 @@ class DioClient {
       onResponse: (Response<dynamic> response, ResponseInterceptorHandler handler) async {
         final responseData = response.data as Map<String, dynamic>;
         //LogHelper().d("当前地址:==== ${response.requestOptions.baseUrl} ");
+        LogHelper().d("data:==== ${responseData} ");
         await SharedPreferencesUtil().setString("last_successful_url", response.requestOptions.baseUrl);
         if (responseData['ret'] == 1) {
           customInterceptor.resetRetryCount();  // 当请求成功时重置重试计数器
@@ -124,6 +125,8 @@ class CustomInterceptors extends Interceptor {
         // 有网络连接但请求失败,尝试使用备用地址
         err.requestOptions.baseUrl = _backupUrls[_retryCount];
         LogHelper().d("切换地址:==== ${err.requestOptions.baseUrl}");
+
+
         _retryCount++;
         try {
 

+ 188 - 0
lib/app/service/connection_service.dart

@@ -0,0 +1,188 @@
+import 'dart:async';
+import 'dart:io';
+import 'package:get/get.dart';
+import 'package:naiyouwl/app/controller/controllers.dart';
+import 'package:naiyouwl/app/component/connection_status.dart';
+import 'package:naiyouwl/app/clash/service/clash_service.dart';
+import 'package:naiyouwl/app/controller/service.dart';
+
+import '../controller/GlobalController.dart';
+import '../modules/home/controllers/home_controller.dart';
+import '../utils/utils.dart';
+
+class ConnectionService {
+  final GlobalController globalController;
+  final Function(ConnectionStatus) updateStatus;
+  final ClashService clashService = Get.find<ClashService>();
+  final ServiceController serviceController = Get.find<ServiceController>();
+
+  ConnectionService(this.globalController, this.updateStatus);
+
+  Future<void> startConnection() async {
+    try {
+      updateStatus(ConnectionStatus.connecting);
+      globalController.updateMsg("正在启动连接...");
+
+      if(Platform.isMacOS){
+        if (serviceController.serviceIsRuning) {
+          await globalController.makeProxy();
+          await serviceController.reloadClashCore();
+          // await serviceController.fetchSetProxy();
+        } else {
+          if (controllers.service.clashServiceIsRuning) {
+            await globalController.makeProxy();
+            await reloadClashCore();
+          }
+        }
+      } else {
+        if (controllers.service.clashServiceIsRuning) {
+          await globalController.makeProxy();
+          await reloadClashCore();
+        }
+      }
+
+      await globalController.updateNode();
+
+
+      // 等待连接建立
+      await Future.delayed(Duration(seconds: 2));
+
+      if(Platform.isMacOS){
+        if (serviceController.serviceIsRuning) {
+          //await serviceController.fetchStartInit();
+          await serviceController.fetchSetProxy();
+
+        } else {
+          if (controllers.service.clashServiceIsRuning) {
+            globalController.connectStatus.value = true;
+            await globalController.openProxy();
+          } else {
+            throw Exception("内核启动失败");
+          }
+        }
+      } else {
+        if (controllers.service.clashServiceIsRuning) {
+          updateStatus(ConnectionStatus.connected);
+          globalController.connectStatus.value = true;
+          globalController.updateMsg("连接成功");
+        } else {
+          throw Exception("内核启动失败");
+        }
+      }
+
+      updateStatus(ConnectionStatus.connected);
+      globalController.updateMsg("连接成功");
+
+    } catch (e) {
+      updateStatus(ConnectionStatus.disconnected);
+      globalController.handleApiError("连接失败: $e");
+    }
+  }
+
+  Future<void> stopConnection() async {
+    try {
+      updateStatus(ConnectionStatus.disconnected);
+      globalController.updateMsg("正在断开连接...");
+
+      if(Platform.isMacOS){
+        if (serviceController.serviceIsRuning) {
+          await serviceController.stopClash();
+          await serviceController.fetchSetProxyStop();
+
+        } else {
+          if (controllers.service.clashServiceIsRuning){
+            await controllers.service.stopClash();
+            await globalController.closeProxy();
+            globalController.updateMsg("内核已重新加载");
+          } else {
+            globalController.updateMsg("内核启动失败");
+          }
+
+        }
+      } else{
+        if (controllers.service.clashServiceIsRuning){
+          await controllers.service.stopClash();
+          await globalController.closeProxy();
+          globalController.updateMsg("内核已重新加载");
+        } else {
+          globalController.updateMsg("内核启动失败");
+        }
+
+      }
+
+
+      globalController.connectStatus.value = false;
+      updateStatus(ConnectionStatus.disconnected);
+      globalController.updateMsg("已断开连接");
+    } catch (e) {
+      globalController.handleApiError("断开连接失败: $e");
+    }
+  }
+
+  Future<void> reloadClashCore() async {
+    try {
+      globalController.updateMsg("正在重新加载内核...");
+
+      if (serviceController.serviceIsRuning) {
+        await serviceController.reloadClashCore();
+        globalController.updateMsg("内核已重新加载");
+        globalController.swift(globalController.selectedNode.value?.name ?? "");
+        return;
+      }
+      if (controllers.service.clashServiceIsRuning){
+        await controllers.service.reloadClashCore();
+        globalController.updateMsg("内核已重新加载");
+        globalController.swift(globalController.selectedNode.value?.name ?? "");
+      } else {
+        globalController.updateMsg("内核启动失败");
+      }
+
+
+    } catch (e) {
+      globalController.handleApiError("重新加载内核失败: $e");
+    }
+  }
+
+  Future<void> coreInit() async {
+    try {
+      globalController.updateMsg("正在初始化核心...");
+      if (serviceController.installStatus.value) {
+        //每次启动多要初始化
+        await controllers.cc_service.fetchStartInit();
+      } else {
+        await controllers.service.initClashCoreConfig();
+      }
+      globalController.updateMsg("核心初始化完成");
+    } catch (e) {
+      globalController.updateMsg("失败...");
+      globalController.handleApiError("核心初始化失败: $e");
+    }
+  }
+
+
+  Future<void> installService() async{
+
+
+
+    if(serviceController.serviceStatus.value == RunningState.stoped){
+      controllers.service.stopClashCore();
+      globalController.updateMsg("正在安装服务");
+      await serviceController.serviceModeSwitch(true);
+
+
+    }
+  }
+
+  
+
+  Future<void> UninstallService() async{
+    if(serviceController.serviceStatus.value == RunningState.running){
+      controllers.global.updateMsg("正在卸载服务");
+      await serviceController.serviceModeSwitch(false);
+
+    }
+  }
+
+
+
+}

+ 23 - 0
lib/app/service/local_storage_service.dart

@@ -0,0 +1,23 @@
+import 'package:dart_json_mapper/dart_json_mapper.dart';
+import 'package:get/get.dart';
+import 'package:naiyouwl/app/data/model/SysConfig.dart';
+import 'package:naiyouwl/app/data/model/LocalUser.dart';
+import 'package:naiyouwl/app/common/SharedPreferencesUtil.dart';
+
+class LocalStorageService extends GetxController {
+  Future<SysConfig?> fetchSysConfig() async {
+    String? data = await SharedPreferencesUtil().getString("sysconfig");
+    if (data != null) {
+      return JsonMapper.deserialize<SysConfig>(data);
+    }
+    return null;
+  }
+
+  Future<LocalUser?> fetchLocalUser() async {
+    String? userdata = await SharedPreferencesUtil().getString("localUser");
+    if (userdata != null) {
+      return JsonMapper.deserialize<LocalUser>(userdata);
+    }
+    return null;
+  }
+}

+ 88 - 0
lib/app/service/network_service.dart

@@ -0,0 +1,88 @@
+import 'package:dart_json_mapper/dart_json_mapper.dart';
+import 'package:get/get.dart';
+import 'package:get/get_core/src/get_main.dart';
+import 'package:naiyouwl/app/data/model/UserMode.dart';
+import 'package:naiyouwl/app/network/api_service.dart';
+import 'package:naiyouwl/app/controller/GlobalController.dart';
+
+import '../common/SharedPreferencesUtil.dart';
+import '../common/constants.dart';
+import '../data/model/NodeMode.dart';
+import '../data/model/SysConfig.dart';
+import '../routes/app_pages.dart';
+
+class NetworkService {
+  final GlobalController globalController;
+
+  NetworkService(this.globalController);
+
+
+  Future<String?> fetchAuthUser() async {
+    try {
+      final ret = await ApiService().fetchAuthUser(KAuthUser);
+
+      globalController.selectNode(ret);
+
+      return "";
+    } catch (e) {
+      return e.toString();
+    }
+
+  }
+
+  Future<void> fetchNode() async {
+    try {
+      globalController.isLoading.value = true;
+      await globalController.fetchNodes();
+
+    } catch (e) {
+      globalController.handleApiError(e);
+    } finally {
+      globalController.isLoading.value = false;
+    }
+  }
+
+
+  Future<void> outlogin() async {
+    // if(connectStatus.value == ConnectionStatus.connecting || connectStatus.value == ConnectionStatus.stopped){
+    //   controllers.global.handleApiError("当前连接状态无法退出(先停止加速)");
+    //   return ;
+    // }
+    if (globalController.connectStatus.value == false){
+      globalController.handleApiError("当前连接状态无法退出(先停止加速)");
+      return ;
+    }
+    await SharedPreferencesUtil().delete("token");
+    try {
+      //isLoading.value = true;
+      await ApiService().fetchLogout(KLogout);
+    } catch (e) {
+      globalController.handleApiError(e);
+    } finally {
+      //isLoading.value = false;
+    }
+    Get.offNamed(Routes.LOGIN);
+  }
+
+  Future<User?> fetchUserinfo() async {
+    try {
+      return await ApiService().userinfo("/api/client/v4/userinfo");
+    } catch (e) {
+      globalController.handleApiError(e);
+      return null;
+    }
+  }
+
+  Future<SysConfig?> fetchUserSysConfig() async {
+    try {
+      String? data  = await SharedPreferencesUtil().getString("sysconfig");
+      if(data  != null){
+        return  JsonMapper.deserialize<SysConfig>(data)!;
+      }
+
+    } catch (e) {
+      globalController.handleApiError(e);
+    }
+    return null;
+  }
+}   

+ 41 - 0
lib/app/service/user_service.dart

@@ -0,0 +1,41 @@
+import 'package:get/get.dart';
+import 'package:naiyouwl/app/data/model/NodeMode.dart';
+import 'package:naiyouwl/app/data/model/UserMode.dart';
+import 'package:naiyouwl/app/network/api_service.dart';
+import 'package:naiyouwl/app/controller/controllers.dart';
+
+import '../common/constants.dart';
+import '../controller/GlobalController.dart';
+import '../data/model/LocalUser.dart';
+import '../data/model/SysConfig.dart';
+import 'local_storage_service.dart';
+
+class UserService {
+  final GlobalController globalController;
+
+  UserService(this.globalController);
+
+
+
+  Future<void> fetchUserinfo() async {
+    try {
+      final user = await ApiService().userinfo("/api/client/v4/userinfo");
+      globalController.updateUserInfo(user);
+      await globalController.fetchNodes();
+      return;
+    } catch (e) {
+      globalController.handleApiError("获取用户信息失败: $e");
+      return;
+    }
+  }
+
+
+  Future<LocalUser?> fetchLocalUser() async {
+    final localStorageService = Get.find<LocalStorageService>();
+    return await localStorageService.fetchLocalUser();
+  }
+}
+
+
+ 
+ 

+ 7 - 0
lib/app/utils/utils.dart

@@ -57,3 +57,10 @@ extension MapIndex<T> on List<T> {
   }
 }
 
+enum RunningState {
+  starting,
+  running,
+  stopping,
+  stoped,
+  error,
+}

+ 5 - 0
lib/main.dart

@@ -8,6 +8,7 @@ import 'package:dart_json_mapper/dart_json_mapper.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_localizations/flutter_localizations.dart';
 import 'package:get/get.dart';
+import 'package:naiyouwl/app/clash/service/clash_service.dart';
 
 import 'package:naiyouwl/app/controller/dialog.dart';
 import 'package:naiyouwl/app/i18n/i18n.dart';
@@ -24,6 +25,7 @@ import 'package:window_manager/window_manager.dart';
 
 import 'app/const/const.dart';
 import 'app/routes/app_pages.dart';
+import 'app/service/local_storage_service.dart';
 import 'main.mapper.g.dart' show initializeJsonMapper;
 
 final proxyManager = ProxyManager();
@@ -55,9 +57,11 @@ void main() async {
   Get.put(WindowController());
   Get.put(CoreController());
   Get.put(ConfigController());
+  Get.put(ClashService());
   Get.put(ServiceController());
   Get.put(GlobalController());
   Get.put(DialogController());
+  Get.put(LocalStorageService());
 
   await initAppService();
 
@@ -123,6 +127,7 @@ class _MyAppState extends State<MyApp> {
   @override
   void initState() {
     controllers.init();
+
     controllers.global.init(context);
     listenShow = controllers.window.isVisible.stream.listen((event) async {
       if (!event) return;