alroyso 1 year ago
parent
commit
6a62dfedc5

+ 121 - 139
lib/app/controller/GlobalController.dart

@@ -1,3 +1,4 @@
+import 'dart:ffi';
 import 'dart:io';
 import 'package:flutter/services.dart';
 import 'package:flutter/widgets.dart';
@@ -36,19 +37,20 @@ class GlobalController extends GetxController {
   var selectMageNode = false.obs;
   var systemProxySwitchIng = false.obs;
   var tunProxySwitchIng = false.obs;
+  var nodeId = 0.obs;
   bool allowStatusUpdate = false;
   final _wlBaseHelpPlugin = WlBaseHelp();
   var sysInfo = ''.obs;
 
   final selectedNode = Rx<NodeMode?>(null);
-  // 策略组
-  var proxieGroups = <ProxieProxiesItem>[].obs;
-  // 代理集
-  var proxieProviders = <ProxieProviderItem>[].obs;
-  // 代理
-  var proxieProxies = <ProxieProxiesItem>[].obs;
-  // 所有节点
-  var allProxies = <String, ProxieProxiesItem>{}.obs;
+  // // 策略组
+  // 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 = [
@@ -68,28 +70,6 @@ class GlobalController extends GetxController {
     // init plugins
     await controllers.tray.initTray();
     controllers.window.initWindow();
-    //controllers.protocol.initProtocol();
-    await controllers.config.portDetection();
-    // init clash config
-
-    // init config
-    await controllers.config.initConfig();
-    await controllers.service.initConfig();
-
-     await  controllers.service.isService();
-    // init service
-    // await controllers.service.startService();
-    // if (controllers.service.serviceStatus.value != RunningState.running) return;
-    //await controllers.service.serviceModeSwitch(true);
-    // init clash core
-    await platformState();
-    //判断clash 程序是否在启动中,如果是可以先停止
-    await onIsProcessRunning(path.basename(Files.assetsCCore.path));
-
-     await controllers.service.initClashCoreConfig();
-     if (controllers.service.coreStatus.value != RunningState.running) return;
-     await controllers.core.updateVersion();
-    //initRegularlyUpdate();
   }
 
   // Platform messages are asynchronous, so we initialize in an async method.
@@ -122,25 +102,21 @@ class GlobalController extends GetxController {
 
   }
 
-  Future<bool?> onIsRunAdmin() async {
-    bool? isAdmin;
-    if (Platform.isWindows) {
-      try {
-        isAdmin = await _wlBaseHelpPlugin.isRunningAsAdmin();
-      } on PlatformException {
-        isAdmin = null;
-      }
-    } else {
-      // 对于非 Windows 平台,可以根据需要返回 null 或 false
-      isAdmin = null; // 或者保持 isAdmin = null;
+  Future<bool> onIsRunAdmin() async {
+    bool isAdmin;
+    try {
+      isAdmin = await _wlBaseHelpPlugin.isRunningAsAdmin() ?? false;
+    } on PlatformException {
+      isAdmin = false;
     }
 
     return isAdmin;
   }
 
-  Future<void> onIsProcessRunning(String passName) async {
+  Future<bool> onIsProcessRunning(String passName) async {
+    bool isRun = false;
     if(Platform.isWindows){
-      bool isRun;
+
       try {
         isRun = await _wlBaseHelpPlugin.isProcessRunning(passName) ?? false;
 
@@ -152,7 +128,7 @@ class GlobalController extends GetxController {
         isRun = false;
       }
     }
-
+    return isRun;
   }
 
   Future<void> onKillProcess(String passName) async {
@@ -247,9 +223,10 @@ class GlobalController extends GetxController {
       {
         g = "GLOBAL";
       }
+
       await controllers.core.fetchSetProxieGroup(g, name);
-      await updateDate();
       final conn = await controllers.core.fetchConnection();
+      if(conn == null) { return; }
       for (final it in conn.connections) {
         if (it.chains.contains(name)) controllers.core.fetchCloseConnections(it.id);
       }
@@ -259,20 +236,6 @@ class GlobalController extends GetxController {
 
 
   }
-  // Future<ProxieProxiesItem> findProxieByName(String name) async {
-  //   return proxieGroups.firstWhere((proxie) => proxie['name'] == name, orElse: () => null);
-  // }
-
-  Future<ProxieProxiesItem?> findProxieByName(String name) async {
-    ProxieProxiesItem? result;
-    try {
-      result = proxieGroups.firstWhere((proxie) => proxie.all!.contains(name));
-    } catch (e) {
-      // 在这里可以处理异常,或者只是简单地返回 null
-      return null;
-    }
-    return result;
-  }
 
 
 
@@ -310,91 +273,101 @@ class GlobalController extends GetxController {
     await controllers.config.setSystemProxy(open);
     if(open)
     {
-     await openProxy();
+      if(Platform.isWindows){
+        await openProxy();
+      } else {
+       await controllers.service.fetchSetProxy();
+      }
+
     } else {
-     await  closeProxy();
-    }
-    systemProxySwitchIng.value = false;
-  }
+      if(Platform.isWindows){
+        await  closeProxy();
+      } else {
+        await controllers.service.fetchSetProxyStop();
+      }
 
-  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;
-      });
     }
+    systemProxySwitchIng.value = false;
   }
 
-  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<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);
-    }
-  }
+  // 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
@@ -414,6 +387,7 @@ class GlobalController extends GetxController {
     });
   }
   void selectNode(NodeMode node) {
+    nodeId.value = node.id ?? 0;
     controllers.global.selectedNode.value = node;
     _storeSelectedNode(node);
   }
@@ -421,6 +395,7 @@ 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();
   }
@@ -543,15 +518,22 @@ class GlobalController extends GetxController {
         //.e('Failed to start $coreName: ${e.message}');
         throw Exception('Failed to start sysproxy: ${e.message}');
       }
+      proxyManager.cleanSystemProxy();
     }
-    proxyManager.cleanSystemProxy();
+
     systemProxy = false;
   }
   Future<void> stopAllCore() async {
     await systemProxySwitch(false);
-    await controllers.service.stopClashCore();
+    if(Platform.isWindows){
+      await controllers.service.stopClashCore();
+    } else if(Platform.isMacOS) {
+      await controllers.service.fetchStop();
+    }
     if(!controllers.service.serviceMode.value){{
-      await onKillProcess(path.basename(Files.assetsCCore.path));
+      if(Platform.isWindows){
+        await onKillProcess(path.basename(Files.assetsCCore.path));
+      }
       await killProcess(path.basename(Files.assetsCCore.path));
     }}
 

+ 8 - 0
lib/app/controller/config.dart

@@ -272,6 +272,14 @@ $rules
     config.refresh();
   }
 
+  Future<void> setSerivePort(int port) async {
+    config.value.servicePort = port;
+    await save();
+    config.refresh();
+  }
+
+
+
   Future<bool> updateSub(ConfigSub sub) async {
     if ((sub.url ?? '').isEmpty) return false;
     final res = await dio.get(sub.url!);

+ 249 - 82
lib/app/controller/core.dart

@@ -1,3 +1,5 @@
+import 'dart:convert';
+
 import 'package:dio/dio.dart';
 import 'package:get/get.dart';
 import 'package:naiyouwl/app/bean/clash_core.dart';
@@ -6,15 +8,21 @@ import 'package:naiyouwl/app/bean/proxie.dart';
 import 'package:naiyouwl/app/bean/rule.dart';
 import 'package:naiyouwl/app/common/LogHelper.dart';
 import 'package:naiyouwl/app/controller/controllers.dart';
+import 'package:naiyouwl/app/controller/service.dart';
 
 import 'package:naiyouwl/app/utils/system_proxy.dart';
 import 'package:web_socket_channel/io.dart';
 
-
+import 'package:http/http.dart' as http;
 class CoreController extends GetxController {
-  late final dio  = Dio(BaseOptions(
-       baseUrl: 'http://127.0.0.1:9799',
-  ));
+  // late final dio  = Dio(BaseOptions(
+  //      baseUrl: 'http://127.0.0.1:9799',
+  // ));
+
+  var ip = "127.0.0.1";
+  var url = "";
+  var client = http.Client();
+  var headers = Map<String,String>();
   late final LogHelper _logger = LogHelper();
   var version = ClashCoreVersion(premium: true, version: '').obs;
   var address = ''.obs;
@@ -62,41 +70,119 @@ class CoreController extends GetxController {
     address.value = apiAddress;
     secret.value = apiSecret;
     // dio.close(force: true);
-    dio.options.baseUrl = 'http://${address.value}';
-    print("dio baseUrl api ${dio.options.baseUrl}");
-    dio.options.headers['Authorization'] = 'Bearer ${secret.value}';
+    url = "${address.value}";
+    headers["Authorization"] = 'Bearer ${secret.value}';
+    //client.head(Uri.http(url,'info'))
+    // dio.options.baseUrl = 'http://${address.value}';
+    // print("dio baseUrl api ${dio.options.baseUrl}");
+    // dio.options.headers['Authorization'] = 'Bearer ${secret.value}';
   }
 
   Future<dynamic> fetchHello() async {
-    return await dio.get('/');
+    try {
+      final res = await  client.get(Uri.http(url,'info'),headers: headers);
+      if(res.statusCode == 200) {
+        var jsonResponse =
+        jsonDecode(res.body) as Map<String, dynamic>;
+        return jsonResponse;
+      }
+    } on http.ClientException catch (e) {
+      // 处理客户端异常,例如没有网络连接
+      print('Client fetchHello Exception: ${e.message}');
+      return null;
+    } on Exception catch (e) {
+      // 处理其他类型的异常
+      print('Exception: $e');
+      return null;
+    }
   }
 
   Future<void> updateVersion() async {
-    final res = await dio.get('/version');
-    version.value = ClashCoreVersion.fromJson(res.data);
+    try {
+      final res = await  client.get(Uri.http(url,'version'),headers: headers);
+      if(res.statusCode == 200) {
+        var jsonResponse =
+        jsonDecode(res.body) as Map<String, dynamic>;
+        version.value = ClashCoreVersion.fromJson(jsonResponse);
+      }
+
+    } on http.ClientException catch (e) {
+      // 处理客户端异常,例如没有网络连接
+      print('Client updateVersion Exception: ${e.message}');
+      return null;
+    } on Exception catch (e) {
+      // 处理其他类型的异常
+      print('Exception: $e');
+      return null;
+    }
   }
 
   Future<void> updateConfig() async {
-    final res = await dio.get('/configs');
-    config.value = ClashCoreConfig.fromJson(res.data);
-    LogHelper().d("update-config ${config.value}");
+
+    try {
+      var ut = Uri.parse('http://$url/configs');
+      final res = await  client.get(ut,headers: headers);
+      print("updateConfig ---- ${res.statusCode}");
+      if(res.statusCode == 200) {
+        var jsonResponse =
+        jsonDecode(res.body) as Map<String, dynamic>;
+        config.value = ClashCoreConfig.fromJson(jsonResponse);
+      }
+
+    } on http.ClientException catch (e) {
+      // 处理客户端异常,例如没有网络连接
+      print('Client updateConfig Exception: ${e.message}');
+
+    } on Exception catch (e) {
+      // 处理其他类型的异常
+      print('Exception updateConfig: $e');
+
+    }
   }
 
   Future<void> fetchConfigUpdate(Map<String, dynamic> config) async {
-    await dio.patch('/configs', data: config);
-    await updateConfig();
+    try {
+      var ut = Uri.parse('http://$url/configs');
+      final res = await  client.patch(ut,headers: headers);
+      print("fetchConfigUpdate ---- ${res.statusCode}");
+      // var jsonResponse =
+      // jsonDecode(res.body) as Map<String, dynamic>;
+      // print(jsonResponse);
+      await updateConfig();
+    } on http.ClientException catch (e) {
+      // 处理客户端异常,例如没有网络连接
+      print('Client fetchConfigUpdate Exception: ${e.message}');
+
+    } on Exception catch (e) {
+      // 处理其他类型的异常
+      print('Exception fetchConfigUpdate: $e');
+
+    }
   }
 
   Future<void> changeConfig(String configPath) async{
     for (var i = 0 ; i< 5; i++) {
+
       try {
-       final data =  await dio.put('/configs', data: {"path": configPath});
-       if(data.statusCode == 204){
-        break;
-       }
-      }
-      catch (e) {
-       continue;
+        final body = json.encode({
+          "path": configPath
+        });
+        var ut = Uri.parse('http://$url/configs');
+        final res = await  client.put(ut,body:body,headers: headers);
+        print("changeConfig ---- ${res.statusCode}");
+        if(res.statusCode == 204)
+        {
+          await updateConfig();
+          break;
+        }
+      } on http.ClientException catch (e) {
+        // 处理客户端异常,例如没有网络连接
+        print('Client changeConfig Exception: ${e.message}');
+        continue;
+      } on Exception catch (e) {
+        // 处理其他类型的异常
+        print('Exception changeConfig : $e');
+        continue;
       }
     }
   }
@@ -106,94 +192,175 @@ class CoreController extends GetxController {
   // 	Payload string `json:"payload"`
   // }
   // https://github.com/Dreamacro/clash/blob/c231fd14666d6ea05d6a75eaba6db69f9eee5ae9/hub/route/configs.go#L95
-  Future<void> fetchReloadConfig(Map<String, String> config) async {
-    print("fetchReloadConfig $config");
-    await dio.put('/configs', data: config);
-  }
+  // Future<void> fetchReloadConfig(Map<String, String> config) async {
+  //   print("fetchReloadConfig $config");
+  //   await dio.put('/configs', data: config);
+  // }
 
   Future<void> fetchCloseConnections(String id) async {
-    await dio.delete('/connections/${Uri.encodeComponent(id)}');
+    //await dio.delete('/connections/${Uri.encodeComponent(id)}');
+    try {
+      var ut = Uri.parse('http://$url/connections/${Uri.encodeComponent(id)}');
+
+      final res = await  client.delete(ut,headers: headers);
+      print("fetchCloseConnections ---- ${res.statusCode}");
+      if(res.statusCode == 204){
+        var jsonResponse =
+        jsonDecode(res.body) as Map<String, dynamic>;
+        print(jsonResponse);
+        await updateConfig();
+      }
+
+    } on http.ClientException catch (e) {
+      // 处理客户端异常,例如没有网络连接
+      print('Client fetchCloseConnections Exception: ${e.message}');
+
+    } on Exception catch (e) {
+      // 处理其他类型的异常
+      print('Exception: $e');
+
+    }
   }
 
   IOWebSocketChannel fetchConnectionsWs() {
     return IOWebSocketChannel.connect(
       Uri.parse('ws://${address.value}/connections'),
-      headers: {"Authorization": dio.options.headers["Authorization"]},
+      headers: headers,
     );
   }
 
   Future updateRuleProvider() async {
-    final res = await dio.get('/providers/rules');
-    ruleProvider.value = RuleProvider.fromJson(res.data);
-    ruleProvider.refresh();
+    // final res = await dio.get('/providers/rules');
+    // ruleProvider.value = RuleProvider.fromJson(res.data);
+    // ruleProvider.refresh();
+
+    try {
+
+      var ut = Uri.parse('http://$url/rpoviders/rules');
+      final res = await  client.get(ut,headers: headers);
+      if(res.statusCode == 200){
+        var jsonResponse =
+        jsonDecode(res.body) as Map<String, dynamic>;
+        ruleProvider.value = RuleProvider.fromJson(jsonResponse);
+        ruleProvider.refresh();
+      }
+
+    } on http.ClientException catch (e) {
+      // 处理客户端异常,例如没有网络连接
+      print('Client updateRuleProvider Exception: ${e.message}');
+
+    } on Exception catch (e) {
+      // 处理其他类型的异常
+      print('Exception: $e');
+
+    }
   }
 
   Future updateRule() async {
-    final res = await dio.get('/rules');
-    rule.value = Rule.fromJson(res.data);
-    rule.refresh();
-  }
+    // final res = await dio.get('/rules');
+    // rule.value = Rule.fromJson(res.data);
+    // rule.refresh();
 
-  Future<void> fetchRuleProviderUpdate(String name) async {
-    await dio.put('/providers/rules/${Uri.encodeComponent(name)}');
-  }
+    try {
 
-  Future<Proxie> fetchProxie() async {
-    final res = await dio.get('/proxies');
-    return Proxie.fromJson(res.data);
-  }
+      var ut = Uri.parse('http://$url/rules');
+      final res = await  client.get(ut,headers: headers);
+      if(res.statusCode == 200){
+        var jsonResponse =
+        jsonDecode(res.body) as Map<String, dynamic>;
+        rule.value = Rule.fromJson(jsonResponse);
+        rule.refresh();
+      }
 
-  Future<ProxieProvider> fetchProxieProvider() async {
-    final res = await dio.get('/providers/proxies');
-    return ProxieProvider.fromJson(res.data);
-  }
+    } on http.ClientException catch (e) {
+      // 处理客户端异常,例如没有网络连接
+      print('Client updateRule Exception: ${e.message}');
 
-  Future<void> fetchProxieProviderHealthCheck(String provider) async {
-    await dio.get('/providers/proxies/${Uri.encodeComponent(provider)}/healthcheck');
+    } on Exception catch (e) {
+      // 处理其他类型的异常
+      print('Exception: $e');
+
+    }
   }
 
+  // Future<void> fetchRuleProviderUpdate(String name) async {
+  //   await dio.put('/providers/rules/${Uri.encodeComponent(name)}');
+  // }
+
+  // Future<Proxie> fetchProxie() async {
+  //   final res = await dio.get('/proxies');
+  //   return Proxie.fromJson(res.data);
+  // }
+
+  // Future<ProxieProvider> fetchProxieProvider() async {
+  //   final res = await dio.get('/providers/proxies');
+  //   return ProxieProvider.fromJson(res.data);
+  // }
+
+  // Future<void> fetchProxieProviderHealthCheck(String provider) async {
+  //   await dio.get('/providers/proxies/${Uri.encodeComponent(provider)}/healthcheck');
+  // }
+
   Future<void> fetchSetProxieGroup(String group, String value) async {
-    await dio.put('/proxies/${Uri.encodeComponent(group)}', data: {'name': value});
-  }
+   // await dio.put('/proxies/${Uri.encodeComponent(group)}', data: {'name': value});
+    try {
+      final body = json.encode({
+        'name': value
+      });
+      var ut = Uri.parse('http://$url/proxies/$group');
+      final ret = await  client.put(ut,body:body,headers: headers);
+      print("fetchSetProxieGroup ${ret.statusCode}");
 
-  Future<void> fetchProxieProviderUpdate(String name) async {
-    await dio.put('/providers/proxies/${Uri.encodeComponent(name)}');
-  }
+    } on http.ClientException catch (e) {
+      // 处理客户端异常,例如没有网络连接
+      print('Client fetchSetProxieGroup Exception: ${e.message}');
 
-  Future<int> fetchProxieDelay(String name) async {
-    final query = {'timeout': 5000, 'url': 'http://www.gstatic.com/generate_204'};
-    final res = await dio.get('/proxies/${Uri.encodeComponent(name)}/delay', queryParameters: query);
-    return res.data['delay'] ?? 0;
-  }
+    } on Exception catch (e) {
+      // 处理其他类型的异常
+      print('fetchSetProxieGroup Exception: $e');
 
-  Future<Connect> fetchConnection() async {
-    final res = await dio.get('/connections');
-    if(res.data !=null){
-     // LogHelper().d("没有连接");
-      //return Connect();
     }
-    return Connect.fromJson(res.data);
   }
-}
+  //
+  // Future<void> fetchProxieProviderUpdate(String name) async {
+  //   await dio.put('/providers/proxies/${Uri.encodeComponent(name)}');
+  // }
 
+  // Future<int> fetchProxieDelay(String name) async {
+  //   final query = {'timeout': 5000, 'url': 'http://www.gstatic.com/generate_204'};
+  //   final res = await dio.get('/proxies/${Uri.encodeComponent(name)}/delay', queryParameters: query);
+  //   return res.data['delay'] ?? 0;
+  // }
+  //
+  Future<Connect?> fetchConnection() async {
+    // final res = await dio.get('/connections');
+    // if(res.data !=null){
+    //  // LogHelper().d("没有连接");
+    //   //return Connect();
+    // }
+    try {
 
-class FriendlyErrorInterceptor extends Interceptor {
-  @override
-  Future onError(DioError err, ErrorInterceptorHandler handler) async {
-    String message = 'core未知错误';
-
-    if (err.type == DioErrorType.connectTimeout ||
-        err.type == DioErrorType.sendTimeout ||
-        err.type == DioErrorType.receiveTimeout) {
-      message = '连接core超时,请检查您的网络';
-    } else if (err.type == DioErrorType.cancel) {
-      message = 'core 请求已被取消';
-    } else if (err.type == DioErrorType.response) {
-      message = 'core 服务端响应错误: ${err.response?.statusCode} ${err.response?.statusMessage}';
-    } else if (err.type == DioErrorType.other) {
-      message = 'core 其他错误: ${err.message}';
+      var ut = Uri.parse('http://$url/connections');
+      final res = await  client.get(ut,headers: headers);
+      if(res.statusCode == 200){
+        var jsonResponse =
+        jsonDecode(res.body) as Map<String, dynamic>;
+        return Connect.fromJson(jsonResponse);
+
+      }
+
+    } on http.ClientException catch (e) {
+      // 处理客户端异常,例如没有网络连接
+      print('Client fetchConnection Exception: ${e.message}');
+      return null;
+    } on Exception catch (e) {
+      // 处理其他类型的异常
+      print('fetchConnection Exception: $e');
+      return null;
     }
-   // LogHelper().d(message);
-    return DioError(error: message, requestOptions: err.requestOptions);
+
   }
 }
+
+
+

+ 191 - 70
lib/app/controller/service.dart

@@ -20,13 +20,16 @@ import 'package:flutter/foundation.dart';
 import 'package:bot_toast/bot_toast.dart';
 
 import 'package:web_socket_channel/io.dart';
-
+import 'package:http/http.dart' as http;
 
 
 final headers = {"User-Agent": "ccore-for-flutter/0.0.1"};
 
 class ServiceController extends GetxController {
-  late final _dio = Dio(BaseOptions(baseUrl: 'http://127.0.0.1:9899', headers: headers));
+  //late final _dio = Dio(BaseOptions(baseUrl: 'http://127.0.0.1:9899', headers: headers));
+  var ip = "127.0.0.1";
+  var url = "";
+  var client = http.Client();
   var serviceMode = false.obs;
   var coreStatus = RunningState.stoped.obs;
   var serviceStatus = RunningState.stoped.obs;
@@ -41,19 +44,21 @@ class ServiceController extends GetxController {
   bool get isCanOperationCore =>
       serviceStatus.value == RunningState.running && ![RunningState.starting, RunningState.stopping].contains(coreStatus.value);
   bool get coreIsRuning => coreStatus.value == RunningState.running;
+  bool get serviceIsRuning => serviceStatus.value == RunningState.running;
   ServiceController(
 
   );
 
   Future<void> initConfig() async{
-    _dio.options.baseUrl = 'http://127.0.0.1:${controllers.config.config.value.servicePort}';
+    url = "$ip:${controllers.config.config.value.servicePort}";
+    controllers.config.setSerivcePort(controllers.config.config.value.servicePort);
   }
 
   Future<void> startTunService() async {
 
     try {
       while (true) {
-        final data = await fetchInfo();
+        final data = await fetchInfo() ?? ClashServiceInfo.fromJson({'code': -1 , 'mode' : '' ,  'status': '-1','version' : '-1'});
         if( data.mode != 'service-mode')
         {
           if (serviceStatus.value == RunningState.running) {
@@ -75,41 +80,32 @@ class ServiceController extends GetxController {
   }
 
   Future<void> isService() async {
-    //controllers.global.updateMsg("判断是不是 service-mode");
-    //serviceStatus.value = RunningState.starting;
-    if (Platform.isLinux) {
-      await fixBinaryExecutePermissions(Files.assetsClashService);
-      await fixBinaryExecutePermissions(Files.assetsClashCore);
-    }
+
     try {
-      final data = await fetchInfo();
+      final data = await fetchInfo() ?? ClashServiceInfo.fromJson({'code': -1 , 'mode' : '' ,  'status': '-1','version' : '-1'});
       if(data.mode == 'service-mode'){
         serviceMode.value = true;
         controllers.global.updateMsg("服务模式");
-        //await serviceModeSwitch(false);
+      } else {
+        serviceMode.value = false;
+        controllers.global.updateMsg("用户模式");
       }
 
     } catch (_) {
 
     }
-    //serviceStatus.value = RunningState.running;
   }
 
   Future<void> startService() async {
-    //controllers.global.updateMsg("开启服务");
+
     serviceStatus.value = RunningState.starting;
-    if (Platform.isLinux) {
-      await fixBinaryExecutePermissions(Files.assetsClashService);
-      await fixBinaryExecutePermissions(Files.assetsClashCore);
-    }
-    // bool isAvailable = await isPortAvailable(controllers.config.servicePort.value);
-    // if (!isAvailable) {
-    //   controllers.global.updateMsg("端口${controllers.config.servicePort.value}被占用,启动服务失败。");
-    //   serviceStatus.value = RunningState.error;
-    //   return; // 端口被占用,返回失败
-    // }
     try {
       final data = await fetchInfo();
+      if(data == null){
+        await startUserModeService();
+        controllers.global.updateMsg("开启用户服务");
+        return;
+      }
       serviceMode.value = data.mode == 'service-mode';
       controllers.global.updateMsg("服务模式");
     } catch (e) {
@@ -129,38 +125,58 @@ class ServiceController extends GetxController {
   }
 
   Future<void> startUserModeService() async {
+    serviceStatus.value = RunningState.stopping;
     serviceMode.value = false;
+    final timeout = const Duration(seconds: 30); // 设置超时时间为30秒
+    final checkInterval = const Duration(milliseconds: 200);
+    var startTime = DateTime.now();
     try {
+      final isRun = await controllers.global.onIsProcessRunning(Files.assetsClashService.path);
+      if(isRun == true){
+        await isService();
+        serviceStatus.value = RunningState.running;
+        return;
+      }
+
       int? exitCode;
       clashServiceProcess = await Process.start(Files.assetsClashService.path, ['-port','${controllers.config.config.value.servicePort}','user-mode'], mode: ProcessStartMode.inheritStdio);
       clashServiceProcess!.exitCode.then((code) => exitCode = code);
-
-      while (true) {
-        await Future.delayed(const Duration(milliseconds: 200));
-        if (exitCode == 101) {
-          BotToast.showText(text: 'clash-service exit with code: $exitCode,After 10 seconds, try to restart');
-          log.error('After 10 seconds, try to restart');
-          await Future.delayed(const Duration(seconds: 10));
-          await startUserModeService();
-          break;
-        } else if (exitCode != null) {
-          serviceStatus.value = RunningState.error;
-          break;
-        }
+      while (DateTime.now().difference(startTime) < timeout) {
         try {
-          await _dio.post('/info');
+          controllers.global.updateMsg("等待内核启动..");
+          final ret = await fetchInfo();
+          if(ret != null){
+            if(ret.code == 0){
+              break;
+            }
+          }
           break;
-        } catch (_) {}
+        } catch (_) {
+          // 如果fetchHello失败,等待200毫秒后重试
+          await Future.delayed(checkInterval);
+        }
+      }
+
+      // 检查是否超时
+      if (DateTime.now().difference(startTime) >= timeout) {
+        // 如果超时,更新状态并抛出异常
+        coreStatus.value = RunningState.error;
+        controllers.global.updateMsg("内核启动超时,重新点击加速后尝试。");
+        return; // 提前退出函数
       }
+
+      await fetchStartInit();
+      serviceStatus.value = RunningState.running;
     } catch (e) {
       serviceStatus.value = RunningState.error;
-      BotToast.showText(text: e.toString());
+      //BotToast.showText(text: e.toString());
+      print(e.toString());
     }
   }
 
   Future<void> stopService() async {
     serviceStatus.value = RunningState.stopping;
-    if (coreStatus.value == RunningState.running) await stopClashCore();
+    if (coreStatus.value == RunningState.running) await fetchStop();
     if (!serviceMode.value) {
       if (clashServiceProcess != null) {
         clashServiceProcess!.kill();
@@ -177,7 +193,7 @@ class ServiceController extends GetxController {
       while (true) {
         await Future.delayed(const Duration(milliseconds: 100));
         try {
-          await _dio.post('/info');
+          await  client.post(Uri.http(url,'info'),headers: headers);
           break;
         } catch (_) {}
       }
@@ -188,41 +204,155 @@ class ServiceController extends GetxController {
       while (true) {
         await Future.delayed(const Duration(milliseconds: 100));
         try {
-          await _dio.post('/info');
+          await  client.post(Uri.http(url,'info'),headers: headers);
         } catch (e) {
           break;
         }
       }
     }
 
-    Future<ClashServiceInfo> fetchInfo() async {
-      final res = await _dio.post('/info');
-      return ClashServiceInfo.fromJson(res.data);
+    Future<ClashServiceInfo?> fetchInfo() async {
+      try {
+        final res = await  client.post(Uri.http(url,'info'),headers: headers);
+        var jsonResponse =
+            jsonDecode(res.body) as Map<String, dynamic>;
+        return ClashServiceInfo.fromJson(jsonResponse);
+      } on http.ClientException catch (e) {
+        // 处理客户端异常,例如没有网络连接
+        print('Client Exception: ${e.message}');
+        return null;
+      } on Exception catch (e) {
+        // 处理其他类型的异常
+        print('Exception: $e');
+        return null;
+      }
+      return null;
     }
 
     IOWebSocketChannel fetchLogWs() {
       return IOWebSocketChannel.connect(Uri.parse('ws://127.0.0.1:${controllers.config.config.value.servicePort}/logs'), headers: headers);
     }
 
-    Future<void> fetchStart(String name) async {
-      await fetchStop();
-      final res = await _dio.post<String>('/start', data: {
-        "args": ['-d', Paths.config.path, '-f', path.join(Paths.config.path, name)]
+  Future<void> fetchStartInit() async {
+    controllers.config.config.value.selected = 'init_proxy.yaml';
+    controllers.global.updateMsg("启动内核---${controllers.config.config.value.selected}");
+    if( controllers.config.config.value.selected == 'init_proxy.yaml'){
+      controllers.global.updateMsg("启动内核初始化");
+    } else {
+      controllers.global.updateMsg("启动内核");
+    }
+    await fetchStop();
+
+    try{
+      var ut = Uri.http(url,'start');
+      final body = json.encode({
+        "args": [
+          '-d',
+          Paths.config.path,
+          '-f',
+          path.join(Paths.config.path, controllers.config.config.value.selected)
+        ]
       });
-      if (json.decode(res.data!)["code"] != 0) throw json.decode(res.data!)["msg"];
+      final res = await client.post(ut,body: body,headers: headers);
+      var jsonResponse =
+      jsonDecode(res.body) as Map<String, dynamic>;
+      if (jsonResponse["code"] != 0) {
+        coreStatus.value = RunningState.error;
+        throw jsonResponse["msg"];
+      }
+      coreStatus.value = RunningState.running;
+    } on http.ClientException catch (e) {
+      // 处理客户端异常,例如没有网络连接
+      print('Client Exception: ${e.message}');
+    } on Exception catch (e) {
+      // 处理其他类型的异常
+      print('Exception: $e');
     }
 
+  }
+
+    Future<void> fetchStart() async {
+      controllers.config.config.value.selected = 'proxy.yaml';
+      controllers.global.updateMsg("启动内核---${controllers.config.config.value.selected}");
+      if( controllers.config.config.value.selected == 'init_proxy.yaml'){
+        controllers.global.updateMsg("启动内核初始化");
+      } else {
+        controllers.global.updateMsg("启动内核");
+      }
+      await fetchStop();
+
+      try{
+        var ut = Uri.http(url,'start');
+        final res = await client.post(ut,body: {"args": ['-d', Paths.config.path, '-f', path.join(Paths.config.path, controllers.config.config.value.selected)]},headers: headers);
+        var jsonResponse =
+        jsonDecode(res.body) as Map<String, dynamic>;
+        if (jsonResponse["code"] != 0) throw jsonResponse["msg"];
+      } on http.ClientException catch (e) {
+        // 处理客户端异常,例如没有网络连接
+        print('Client Exception: ${e.message}');
+      } on Exception catch (e) {
+        // 处理其他类型的异常
+        print('Exception: $e');
+      }
+
+    }
+
+    Future<void> fetchSetProxy() async {
+      try {
+        var ut = Uri.http(url,'on');
+        final body = json.encode({
+          "http_port" : controllers.config.mixedPort.value,
+          "https_port" : controllers.config.mixedPort.value,
+          "socks_port" :controllers.config.mixedPort.value,
+          "bypass": "127.0.0.1, 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12, 100.64.0.0/10, 17.0.0.0/8, localhost, *.local, *.crashlytics.com, seed-sequoia.siri.apple.com, sequoia.apple.com,xd.apple.com",
+          "dns_ip": "",
+          "dns_type":"",
+          "address":"127.0.0.1"
+        });
+        await client.post(ut,body: body,headers:  headers);
+      } on http.ClientException catch (e) {
+        // 处理客户端异常,例如没有网络连接
+        print('Client Exception: ${e.message}');
+      } on Exception catch (e) {
+        // 处理其他类型的异常
+        print('Exception: $e');
+      }
+    }
+
+  Future<void> fetchSetProxyStop() async {
+
+    try {
+      var ut = Uri.http(url,'off');
+      final body = json.encode({
+        "bypass": "",
+        "dns_ip":""
+      });
+      await client.post(ut,body:body,headers:  headers);
+    } on http.ClientException catch (e) {
+      // 处理客户端异常,例如没有网络连接
+      print('Client Exception: ${e.message}');
+    } on Exception catch (e) {
+      // 处理其他类型的异常
+      print('Exception: $e');
+    }
+  }
     Future<void> fetchStop() async {
       try {
-        await _dio.post('/stop');
-      } catch (e) {
-        return;
+        var ut = Uri.http(url,'stop');
+        await client.post(ut,headers:headers);
+      } on http.ClientException catch (e) {
+        // 处理客户端异常,例如没有网络连接
+        print('Client Exception: ${e.message}');
+      } on Exception catch (e) {
+        // 处理其他类型的异常
+        print('Exception: $e');
       }
     }
 
     Future<void> install() async {
-      final res = await runAsAdmin(Files.assetsClashService.path, ["-port","${controllers.config.config.value.servicePort}","stop", "uninstall", "install", "start"]);
       await initConfig();
+      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;
       await waitServiceStart();
@@ -246,12 +376,11 @@ class ServiceController extends GetxController {
       }
       if(open){
         await startService();
-        await startClashCore();
+        //await startClashCore();
       }else{
         serviceMode.value = false;
-        await startClashCore();
       }
-      //await startClashCore();
+
     }
   Future<bool> isPortAvailable(int port) async {
     try {
@@ -271,16 +400,7 @@ class ServiceController extends GetxController {
       final checkInterval = const Duration(milliseconds: 200);
       var startTime = DateTime.now();
       await controllers.config.readClashCoreApi();
-      // bool isAvailable = await isPortAvailable(controllers.config.mixedPort.value);
-      // if (!isAvailable) {
-      //   controllers.global.updateMsg("端口 被占用,启动内核失败,等待几秒后重新测试。");
-      //   return false; // 端口被占用,返回失败
-      // }
-      // isAvailable = await isPortAvailable(controllers.config.ApiAddressPort.value);
-      // if (!isAvailable) {
-      //   controllers.global.updateMsg("端口 被占用,启动内核失败,等待几秒后重新测试。");
-      //   return false; // 端口被占用,返回失败
-      // }
+
 
       try {
         controllers.global.updateMsg("启动内核---${controllers.config.config.value.selected}");
@@ -292,7 +412,7 @@ class ServiceController extends GetxController {
         coreStatus.value = RunningState.starting;
 
         if(serviceMode.value == true){
-          await fetchStart(controllers.config.config.value.selected);
+          await fetchStart();
         }
         else
         {
@@ -332,7 +452,6 @@ class ServiceController extends GetxController {
         await controllers.core.updateConfig();
         coreStatus.value = RunningState.running;
         controllers.global.updateMsg("内核状态:${coreStatus.value == RunningState.running} ");
-        controllers.global.updateDate();
         return true;
       } catch (e) {
         log.error("core -- $e");
@@ -390,6 +509,8 @@ class ServiceController extends GetxController {
       await controllers.core.changeConfig(path.join(Paths.config.path, controllers.config.config.value.selected));
     }
   }
+
+
     Future<void> reloadClashCore() async {
       try
         {

+ 31 - 18
lib/app/controller/tray.dart

@@ -3,6 +3,7 @@ import 'dart:io';
 import 'package:get/get.dart';
 import 'package:naiyouwl/app/bean/proxie.dart';
 import 'package:naiyouwl/app/controller/controllers.dart';
+import 'package:naiyouwl/app/data/model/NodeMode.dart';
 import 'package:naiyouwl/app/utils/utils.dart';
 import 'package:tray_manager/tray_manager.dart';
 import 'package:url_launcher/url_launcher.dart';
@@ -15,6 +16,7 @@ class TrayController extends GetxController with TrayListener {
   var show = false.obs;
   var isSHow = false;
   var isShowConsole = false.obs;
+
   Future<void> initTray() async {
     await trayManager.setIcon('assets/images/logo/logo.ico');
     // await trayManager.setTitle('Clash For Flutter');
@@ -40,25 +42,33 @@ class TrayController extends GetxController with TrayListener {
     trayMenu = Menu(items: [
       MenuItem.checkbox(label: 'tray_show'.tr, checked: visible, onClick: handleClickShow),
       MenuItem.separator(),
+      // MenuItem.submenu(
+      //   label: 'proxie_group_title'.tr,
+      //   disabled: disabled,
+      //   submenu: Menu(
+      //     items: controllers.global.nodeModes.map((it) =>
+      //         MenuItem.checkbox(
+      //           label: it.name,
+      //           checked: it.id == nodeId.value,
+      //           onClicked: () {
+      //             handleClickProxieItem(it)
+      //           },
+      //         )
+      //     ).toList(),
+      //   ),
+      // ),
       MenuItem.submenu(
         label: 'proxie_group_title'.tr,
         disabled: disabled,
         submenu: Menu(
-            items: controllers.global.proxieGroups
-                .map((it) => MenuItem.submenu(
-                      label: it.name,
-                      submenu: Menu(
-                        items: (it.all ?? [])
-                            .map((t) => MenuItem.checkbox(
-                                  label: t,
-                                  checked: t == it.now,
-                                  disabled: it.type != 'Selector',
-                                  onClick: (m) => handleClickProxieItem(it, m),
-                                ))
-                            .toList(),
-                      ),
-                    ))
-                .toList()),
+          items: controllers.global.nodeModes.map((it) =>
+              MenuItem.checkbox(
+                label: it.name,
+                checked: it.id == controllers.global.nodeId.value,
+                onClick: (m) => handleClickProxieItem(it, m),
+              )
+          ).toList(),
+        ),
       ),
       // MenuItem(
       //   label: 'tray_restart_clash_core'.tr,
@@ -136,10 +146,13 @@ class TrayController extends GetxController with TrayListener {
       await controllers.window.showWindow();
     }
   }
-
-  Future<void> handleClickProxieItem(ProxieProxiesItem proxie, MenuItem menuItem) async {
-    await controllers.global.handleSetProxieGroup(proxie, menuItem.label!);
+  Future<void> handleClickProxieItem(NodeMode proxie, MenuItem menuItem) async {
+    controllers.global.selectNode(proxie);
+    await controllers.global.swift(proxie.name ?? "");
   }
+  // Future<void> handleClickProxieItem(ProxieProxiesItem proxie, MenuItem menuItem) async {
+  //   await controllers.global.handleSetProxieGroup(proxie, menuItem.label!);
+  // }
 
   Future<void> handleClickSetAsSystemProxy(MenuItem menuItem) async {
     await controllers.global.systemProxySwitch(menuItem.checked != true);

+ 105 - 23
lib/app/modules/home/controllers/home_controller.dart

@@ -4,6 +4,7 @@ import 'dart:io';
 import 'package:dart_json_mapper/dart_json_mapper.dart';
 import 'package:get/get.dart';
 import 'package:naiyouwl/app/common/constants.dart';
+import 'package:naiyouwl/app/const/const.dart';
 import 'package:naiyouwl/app/controller/GlobalController.dart';
 import 'package:naiyouwl/app/controller/controllers.dart';
 import 'package:naiyouwl/app/utils/shell.dart';
@@ -18,7 +19,7 @@ import '../../../data/model/SysConfig.dart';
 import '../../../data/model/UserMode.dart';
 import '../../../network/api_service.dart';
 import '../../../routes/app_pages.dart';
-
+import 'package:path/path.dart' as path;
 enum ImageType {
   CUSTOMER,
   PROMOTION,
@@ -40,6 +41,9 @@ class HomeController extends GetxController {
   var nodeModes = <NodeMode>[];
   var isConnect = false.obs;
   var errAdminMsg = false.obs;
+  var errAdmin = ''.obs;
+  var isInit = false.obs;
+  var isServiceInstall  = false.obs;
   bool get isRunning => connectStatus.value == ConnectionStatus.stopped && controllers.global.allowStatusUpdate;
   late final GlobalController globalController = controllers.global;
   StreamSubscription<RunningState>? _statusSubscription;
@@ -97,7 +101,15 @@ class HomeController extends GetxController {
       controllers.global.allowStatusUpdate = false;
       await controllers.config.setBreakConnections(true);
       // // 停止服务
-      await controllers.service.stopClash();
+      if(Platform.isWindows)
+      {
+        await controllers.service.stopClash();
+      }
+      else
+      {
+        await controllers.service.fetchStartInit();
+      }
+
       await controllers.global.systemProxySwitch(false);
       updateStatus(ConnectionStatus.disconnected);
       return;
@@ -131,15 +143,15 @@ class HomeController extends GetxController {
         }
 
         final coreStatus = controllers.service.coreStatus.value;
+        final serverStatus = controllers.service.serviceStatus.value;
         if (coreStatus == RunningState.running){
           await controllers.service.reloadClashCore();
         }
         else{
-          final ret = await controllers.service.startClashCore();
-          if(ret == false){
-            //controllers.global.updateMsg("启动内核失败...");
-            return;
+          if(serverStatus == RunningState.running){
+            await controllers.service.reloadClashCore();
           }
+
         }
 
       } else {
@@ -148,17 +160,17 @@ class HomeController extends GetxController {
         controllers.config.clashCoreTunEnable.value = false;
         controllers.global.startSysMode();
         final coreStatus = controllers.service.coreStatus.value;
-        if (coreStatus == RunningState.running){
-          controllers.global.updateMsg("正在重启内核...");
-          await controllers.service.reloadClashCore();
+        final serverStatus = controllers.service.serviceStatus.value;
+        if(Platform.isWindows){
+          if (coreStatus == RunningState.running){
+            controllers.global.updateMsg("正在重启内核...");
+            await controllers.service.reloadClashCore();
+          }
         }
         else{
           controllers.global.updateMsg("正在启动内核...");
-
-          final ret = await controllers.service.startClashCore();
-          if(ret == false){
-            //controllers.global.updateMsg("启动内核失败...");
-            return;
+          if(serverStatus == RunningState.running){
+            await controllers.service.reloadClashCore();
           }
         }
 
@@ -168,7 +180,7 @@ class HomeController extends GetxController {
 
       Future.delayed(const Duration(seconds: 5), () async {
         updateStatus(ConnectionStatus.stopped);
-        await controllers.global.updateDate();
+
         await controllers.global.updateNode();
         //
         await controllers.tray.updateTray();
@@ -211,10 +223,19 @@ class HomeController extends GetxController {
   }
   Future<void> fetchAuthUser() async {
     try {
-
-      if (!controllers.service.coreIsRuning){
-        controllers.global.updateMsg("内核没有启动...");
-        return;
+      if(Platform.isWindows)
+      {
+        if (!controllers.service.coreIsRuning){
+          controllers.global.updateMsg("内核没有启动...");
+          return;
+        }
+      }
+      if(Platform.isMacOS){
+        if(!controllers.service.serviceIsRuning)
+        {
+          controllers.global.updateMsg("服务内核没有启动...");
+          return;
+        }
       }
 
       if(controllers.global.routeModesSelect.value == "tun")
@@ -225,16 +246,29 @@ class HomeController extends GetxController {
           if(!await isRunningAsAdmin()){
             controllers.global.updateMsg("网卡模式需要管理模式运行...");
             errAdminMsg.value = true;
+            errAdmin.value = "网卡模式需要用户管理员模式去运行,点击确定管理员模式重启如果无法重启,手动重启。";
             return;
           }
         } else {
+
           if(controllers.service.serviceMode.value == false){
             controllers.global.updateMsg("需要开启服务,才能使用,记得卸载服务才能卸载软件...");
+
             return;
           }
         }
       }
 
+      if(Platform.isMacOS){
+        if(!controllers.service.serviceMode.value)
+         {
+           if(!await controllers.global.onIsRunAdmin()){
+             errAdminMsg.value = true;
+             errAdmin.value = "当前用户没有管理员权限。系统代理,可能无法使用,可以安装服务来解决这个问题,或者开启用户的管理员许可";
+             return;
+           }
+         }
+      }
 
       if (controllers.global.allowStatusUpdate && connectStatus.value == ConnectionStatus.stopped || connectStatus.value == ConnectionStatus.connecting) {
         controllers.global.updateMsg("当前连接状态未停止,不要多次启动...");
@@ -249,6 +283,7 @@ class HomeController extends GetxController {
       if(controllers.global.selectMageNode.value == false){
         controllers.global.selectedNode.value = ret;
         controllers.global.selectNode(ret);
+
         controllers.global.updateMsg("获取自动节点完成...");
       }
       await handleButtonClick();
@@ -366,16 +401,62 @@ class HomeController extends GetxController {
   }
 
 
+  Future<void> coreInit() async{
+    controllers.global.updateMsg("正在初始化内核");
+    isInit.value = true;
+    //controllers.protocol.initProtocol();
+    await controllers.config.portDetection();
+    // init clash config
+    // init config
+    await controllers.config.initConfig();
+    await controllers.service.initConfig();
+    await controllers.global.platformState();
+    //判断clash 程序是否在启动中,如果是可以先停止
+    if (Platform.isWindows){
+      await controllers.global.onIsProcessRunning(path.basename(Files.assetsCCore.path));
+    }
+
+    if(Platform.isWindows){
+      await controllers.service.initClashCoreConfig();
+      if (controllers.service.coreStatus.value != RunningState.running) return;
+      await controllers.core.updateVersion();
+      final hello = await controllers.core.fetchHello();
+      print(hello);
+    } else {
+      await controllers.service.startUserModeService();
+      if (controllers.service.serviceStatus.value != RunningState.running) return;
+
+      if(Platform.isMacOS){
+        if(!await controllers.global.onIsRunAdmin()){
+          isServiceInstall.value = true;
+        }
+      }
+
+    }
+
+
+
+    controllers.global.updateMsg("初始化内核完成");
+    isInit.value = false;
+  }
+
+  void init(){
+    Future.delayed(Duration.zero, () async {
+     await fetchSysConfig();
+     await fetchLocalUser();
+     await fetchUserinfo();
+      //controllers.global.initService();
+     await coreInit();
+    });
+  }
+
   final count = 0.obs;
   @override
   void onInit() {
     super.onInit();
     _statusSubscription = controllers.service.coreStatus.stream.listen(_handleStateChange);
 
-    fetchSysConfig();
-    fetchLocalUser();
-    fetchUserinfo();
-    //controllers.global.initService();
+    init();
   }
 
   @override
@@ -397,6 +478,7 @@ class HomeController extends GetxController {
   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);
 }

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

@@ -1,3 +1,4 @@
+import 'dart:ffi';
 import 'dart:io';
 
 import 'package:flutter/foundation.dart';
@@ -56,12 +57,15 @@ class HomeView extends GetView<HomeController> {
               Future.delayed(Duration.zero, () async {
                 bool? result = await controllers.dialog.showNormalDialog(
                   title: "提示",
-                  content: '网卡模式需要用户管理员模式去运行,点击确定管理员模式重启如果无法重启,手动重启。',
+                  content: controller.errAdmin.value,
                   cancelText: "取消",
                   enterText: "确定",
                 );
                 if (result != null && result) {
-                   await controllers.global.onRunAdmin();
+                  if(Platform.isWindows){
+                    await controllers.global.onRunAdmin();
+                  }
+
                 } else {
                   // User pressed "取消" or dismissed the dialog
                 }
@@ -154,10 +158,6 @@ class HomeView extends GetView<HomeController> {
                ConnectionWidget(
                   status: controller.connectStatus.value, onTap: () {
 
-                    if(controllers.service.coreIsRuning == false){
-                      return;
-                    }
-
                     if(controller.isConnect.value){
                       controller.stopVpn();
                     } else
@@ -229,20 +229,29 @@ class HomeView extends GetView<HomeController> {
 
                   ),
                 ) : Container(),
+              controller.isServiceInstall.value == true ? Padding(
+                  padding: const EdgeInsets.fromLTRB(60, 10, 50, 0),
+                  child: Row(
+                    mainAxisAlignment: MainAxisAlignment.center,
+                    children: [
+                      ElevatedButton(onPressed: () async {
+                        await controllers.service.serviceModeSwitch(true);
+                        controller.isServiceInstall.value = false;
+                      }, child: const Text("安装服务")),
+                    ],
+
+                  ),
+                ) : Container(),
                 // const SizedBox(height: 20,),
                 // Align(
                 //   alignment: Alignment.center,
                 //   child:,
                 // )
                 Text("版本号:$kVersion"),
-                // ElevatedButton(onPressed: () async {
-                //   await controllers.global.showConsole();
-                // }, child: Text("显示控制台")),
-                // ElevatedButton(onPressed: () async {
-                //   await  controllers.global.hideConsole();
-                // }, child: Text("隐藏控制台")),
+
                 const SizedBox(height: 10,),
-                Text("当前:${controllers.global.sysInfo.value}"),
+                Text("服务端口${ controller.getSerivce() }"),
+                controllers.global.sysInfo.value.isEmpty ? Container() : Text("当前:${controllers.global.sysInfo.value}"),
               ],
             );
           })

+ 1 - 0
lib/app/modules/node/controllers/node_controller.dart

@@ -71,6 +71,7 @@ class NodeController extends GetxController {
     controllers.global.selectedNode.value = node;
     _storeSelectedNode(node);
     controllers.global.swift(node.name!);
+    controllers.global.nodeId.value = node.id ?? 0;
     Get.back();
     //selectedIndex.value = nodeModes.indexWhere((item) => item.id == node.id);
   }

+ 1 - 1
lib/app/network/dio_client.dart

@@ -98,7 +98,7 @@ class TokenInterceptor extends Interceptor {
 
 class CustomInterceptors extends Interceptor {
   int _retryCount = 0;
-  final List<String> _backupUrls = ['http://107.148.49.147:8383','https://api.androidrj02.top','https://api.androidrj88.com','https://user.jyjksmd.top','https://api.androidrj03.top'];
+  final List<String> _backupUrls = ['http://107.148.49.147:8383','https://api.androidrj02.top','https://api.androidrj88.com','https://vip.markson.hk','https://api.androidrj03.top'];
   final Dio _dio;  // 添加 Dio 作为参数
   CustomInterceptors(this._dio);
   Future<bool> isConnected() async {