GlobalController.dart 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. import 'dart:io';
  2. import 'package:flutter/widgets.dart';
  3. import 'package:get/get.dart';
  4. import 'package:naiyouwl/app/bean/proxie.dart';
  5. import 'package:naiyouwl/app/common/LogHelper.dart';
  6. import 'package:naiyouwl/app/common/SharedPreferencesUtil.dart';
  7. import 'package:naiyouwl/app/controller/controllers.dart';
  8. import 'package:naiyouwl/app/data/model/NodeMode.dart';
  9. import 'package:naiyouwl/app/network/api_service.dart';
  10. import 'package:naiyouwl/app/utils/system_proxy.dart';
  11. import 'package:proxy_manager/proxy_manager.dart';
  12. import 'package:shared_preferences/shared_preferences.dart';
  13. import 'package:tray_manager/tray_manager.dart';
  14. import 'package:window_manager/window_manager.dart';
  15. import 'package:path/path.dart' as path;
  16. import 'package:wl_base_help/wl_base_help.dart';
  17. import '../clash/service/clash_service.dart';
  18. import '../common/constants.dart';
  19. import '../const/const.dart';
  20. import '../data/model/UserMode.dart';
  21. import '../network/dio_client.dart';
  22. import '../utils/shell.dart';
  23. import '../utils/utils.dart';
  24. class GlobalController extends GetxController {
  25. final proxyManager = ProxyManager();
  26. var systemProxy = false.obs;
  27. late BuildContext context;
  28. final List<String> modes = ['rule', 'global'];
  29. final List<String> routeModes = ['sys', 'tun'];
  30. var msgStatus = "未连接".obs;
  31. var routeModesSelect = "sys".obs;
  32. var modesSelect = "rule".obs;
  33. var nodeModes = <NodeMode>[].obs;
  34. var isLoading = false.obs;
  35. var errorMsg = ''.obs;
  36. var statusCode = 0.obs;
  37. var selectMageNode = false.obs;
  38. var systemProxySwitchIng = false.obs;
  39. var tunProxySwitchIng = false.obs;
  40. var nodeId = 0.obs;
  41. bool allowStatusUpdate = false;
  42. final _wlBaseHelpPlugin = WlBaseHelp();
  43. var sysInfo = ''.obs;
  44. var sysVersion = kVersion.obs;
  45. var connectStatus = false.obs;
  46. final selectedNode = Rx<NodeMode?>(null);
  47. final List<String> groupInternalTypes = ['DIRECT', 'REJECT', 'GLOBAL'];
  48. final List<String> groupTypes = [
  49. ProxieProxieType.selector,
  50. ProxieProxieType.urltest,
  51. ProxieProxieType.fallback,
  52. ProxieProxieType.loadbalance,
  53. ];
  54. Future<void> init(BuildContext context) async {
  55. this.context = context;
  56. watchExit();
  57. await controllers.config.initConfig();
  58. await controllers.cc_service.initConfig();
  59. sysInfo.value = await platformState();
  60. await SharedPreferencesUtil().delete("last_successful_url");
  61. await controllers.tray.initTray();
  62. controllers.window.initWindow();
  63. await controllers.cc_service.isCanOperationService();
  64. }
  65. void updateMsg(String msg) {
  66. msgStatus.value = msg;
  67. }
  68. Future<void> updateMode(String route) async {
  69. if(allowStatusUpdate) return;
  70. modesSelect.value = route;
  71. await controllers.core.fetchConfigUpdate({
  72. "mode": modesSelect.value
  73. });
  74. await controllers.global.swift(selectedNode.value?.name ?? "");
  75. }
  76. void updateUserInfo(User user) {
  77. update();
  78. }
  79. Future<void> updateRoute(String route) async {
  80. if(allowStatusUpdate) return;
  81. routeModesSelect.value = route;
  82. LogHelper().d("当前ROUTE模式${routeModesSelect.value}");
  83. }
  84. Future<void> fetchNodes() async {
  85. nodeModes.value = await ApiService().getNode("/api/client/v4/nodes?vless=1");
  86. }
  87. Future<void> updateNode() async {
  88. NodeMode? targetNode;
  89. if (selectedNode.value == null) {
  90. targetNode = await findNodeWithMinUsers(nodeModes);
  91. selectedNode.value = targetNode;
  92. } else {
  93. targetNode = selectedNode.value;
  94. }
  95. if (targetNode != null){
  96. selectNode(targetNode);
  97. await swift(targetNode.name ?? "");
  98. }
  99. }
  100. Future<void> showConsole() async {
  101. await _wlBaseHelpPlugin.showConsole();
  102. }
  103. Future<void> hideConsole() async {
  104. await _wlBaseHelpPlugin.hideConsole();
  105. }
  106. Future<void> swift(String name) async {
  107. try{
  108. var g = "proxy";
  109. if(modesSelect.value == "global") {
  110. g = "GLOBAL";
  111. }
  112. await controllers.core.fetchSetProxieGroup(g, name);
  113. final conn = await controllers.core.fetchConnection();
  114. if(conn == null) return;
  115. for (final it in conn.connections) {
  116. if (it.chains.contains(name)) controllers.core.fetchCloseConnections(it.id);
  117. }
  118. } catch (e) {
  119. //LogHelper().d(e.toString());
  120. }
  121. }
  122. // 创建代理配置文件
  123. Future<void> makeProxy() async {
  124. // final clashService = ClashService();
  125. //if (!await Paths.config.exists()) await Paths.config.create(recursive: true);
  126. await controllers.service.saveConfigToFile(path.join(Paths.config.path, Files.makeProxyConfig.path), nodeModes);
  127. }
  128. Future<NodeMode> findNodeWithMinUsers(List<NodeMode> nodes) async {
  129. return nodes
  130. .where((node) => node.countryCode == "hk")
  131. .reduce((a, b) => a.onlineUsers! < b.onlineUsers! ? a : b);
  132. }
  133. Future<void> TunProxySwitch(bool open) async {
  134. tunProxySwitchIng.value = true;
  135. routeModesSelect.value = open ? "tun": "sys";
  136. LogHelper().d("TunProxySwitch ----- 当前ROUTE模式${routeModesSelect.value}");
  137. tunProxySwitchIng.value = false;
  138. }
  139. Future<void> systemProxySwitch(bool open) async {
  140. systemProxySwitchIng.value = true;
  141. systemProxySwitchIng.value = false;
  142. }
  143. void watchExit() {
  144. if (Platform.isMacOS) {
  145. ProcessSignal.sigterm.watch().listen((_) {
  146. stdout.writeln('exit: sigterm');
  147. handleExit();
  148. });
  149. }
  150. ProcessSignal.sigint.watch().listen((_) {
  151. stdout.writeln('exit: sigint');
  152. handleExit();
  153. });
  154. }
  155. void selectNode(NodeMode node) {
  156. nodeId.value = node.id ?? 0;
  157. controllers.global.selectedNode.value = node;
  158. _storeSelectedNode(node);
  159. }
  160. Future<void> _storeSelectedNode(NodeMode node) async {
  161. final prefs = await SharedPreferences.getInstance();
  162. prefs.setInt('selectedNodeId', node.id ?? -1);
  163. await loadSelectedNode();
  164. }
  165. Future<void> loadSelectedNode() async {
  166. final prefs = await SharedPreferences.getInstance();
  167. final selectedNodeId = prefs.getInt('selectedNodeId');
  168. if (selectedNodeId != null) {
  169. selectedNode.value = nodeModes.firstWhere((node) => node.id == selectedNodeId);
  170. }
  171. }
  172. Future<void> openProxy() async {
  173. int? port = controllers.config.mixedPort.value;
  174. if (port == 0) {
  175. port = null;
  176. }
  177. int? socksPort = controllers.config.mixedPort.value;
  178. if (socksPort == 0) {
  179. socksPort = null;
  180. }
  181. int? mixedPort = controllers.config.mixedPort.value;
  182. if (mixedPort == 0) {
  183. mixedPort = null;
  184. }
  185. port = port ?? mixedPort ?? 0;
  186. if (port != 0) {
  187. await proxyManager.setAsSystemProxy(
  188. ProxyTypes.http,
  189. "127.0.0.1",
  190. port,
  191. );
  192. await proxyManager.setAsSystemProxy(
  193. ProxyTypes.https,
  194. "127.0.0.1",
  195. port,
  196. );
  197. await proxyManager.setAsSystemProxy(
  198. ProxyTypes.socks,
  199. "127.0.0.1",
  200. port,
  201. );
  202. }
  203. socksPort = socksPort ?? mixedPort ?? 0;
  204. if (socksPort != 0) {
  205. if (!Platform.isWindows) {
  206. await proxyManager.setAsSystemProxy(
  207. ProxyTypes.socks,
  208. "127.0.0.1",
  209. socksPort,
  210. );
  211. }
  212. }
  213. systemProxy.value = true;
  214. }
  215. Future<void> closeProxy() async {
  216. await proxyManager.cleanSystemProxy();
  217. systemProxy.value = false;
  218. }
  219. Future<void> stopAllCore() async {
  220. await systemProxySwitch(false);
  221. if(Platform.isWindows){
  222. await controllers.service.stopClashCore();
  223. } else if(Platform.isMacOS) {
  224. if (controllers.cc_service.serviceIsRuning) {
  225. await controllers.cc_service.fetchStop();
  226. } else {
  227. await controllers.service.stopClashCore();
  228. }
  229. }
  230. if(!controllers.service.serviceMode.value){
  231. if(Platform.isWindows){
  232. await onKillProcess(path.basename(Files.assetsClashService.path));
  233. }
  234. await killProcess(path.basename(Files.assetsCCore.path));
  235. await killProcess(path.basename(Files.assetsClashService.path));
  236. }
  237. if(!controllers.service.serviceMode.value){
  238. await killProcess(path.basename(Files.assetsClashService.path));
  239. }
  240. }
  241. Future<void> handleExit() async {
  242. await stopAllCore();
  243. await trayManager.destroy();
  244. await windowManager.destroy();
  245. }
  246. void handleApiError(dynamic error) {
  247. if (error is AppException) {
  248. LogHelper().d('API error with status code: ${error.statusCode}');
  249. statusCode.value = error.statusCode ?? -1;
  250. errorMsg.value = error.toString();
  251. } else {
  252. LogHelper().d('Other error: $error');
  253. errorMsg.value = error.toString();
  254. }
  255. }
  256. @override
  257. void dispose() {
  258. controllers.tray.dispose();
  259. controllers.window.dispose();
  260. super.dispose();
  261. }
  262. }