node_controller.dart 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. import 'dart:io';
  2. import 'package:get/get.dart';
  3. import 'package:naiyouwl/app/controller/GlobalController.dart';
  4. import 'package:shared_preferences/shared_preferences.dart';
  5. import '../../../common/LogHelper.dart';
  6. import '../../../data/model/NodeMode.dart';
  7. import '../../../network/api_service.dart';
  8. enum NodeDisplayStrategy {
  9. All,
  10. LeastUsers,
  11. SelectedFirst,
  12. }
  13. class NodeController extends GetxController {
  14. //TODO: Implement NodeController
  15. final count = 0.obs;
  16. var isLoading = false.obs;
  17. var nodesToShow = <NodeMode>[].obs;
  18. var nodeModes = <NodeMode>[];
  19. var selectedIndex = (-1).obs;
  20. var errorMsg = ''.obs;
  21. final selectedNode = Rx<NodeMode?>(null);
  22. var pingResults = <int, String>{}.obs;
  23. //final selectedNodeId = (-1).obs;
  24. final isLoadingMap = <int, bool>{}.obs;
  25. var displayStrategy = Rx<NodeDisplayStrategy>(NodeDisplayStrategy.All);
  26. late final GlobalController globalController ;
  27. // Future<void> fetchNodes() async {
  28. // try {
  29. // isLoading.value = true;
  30. // nodeModes.clear();
  31. // nodeModes = await ApiService().getNode("/api/client/v4/nodes?vless=1");
  32. // nodesToShow.value = nodeModes;
  33. // LogHelper().d(nodeModes.toList());
  34. // loadSelectedNode();
  35. // } catch (e) {
  36. // errorMsg.value = e.toString();
  37. // } finally {
  38. // isLoading.value = false;
  39. // }
  40. // }
  41. Future<void> tcpPing(NodeMode node) async {
  42. int? nodeId = node.id;
  43. if (nodeId != null) {
  44. isLoadingMap[nodeId] = true; // 开始ping时设置为true
  45. isLoadingMap.refresh(); // 通知观察者
  46. final stopwatch = Stopwatch()..start();
  47. Socket? socket;
  48. try {
  49. socket = await Socket.connect(node.host!, node.port!, timeout: const Duration(seconds: 3));
  50. final elapsed = stopwatch.elapsedMilliseconds;
  51. pingResults[nodeId] = '${elapsed}ms'; // 使用普通的映射赋值
  52. pingResults.refresh(); // 通知观察者
  53. socket.destroy();
  54. } catch (e) {
  55. pingResults[nodeId] = 'Error'; // 使用普通的映射赋值
  56. pingResults.refresh(); // 通知观察者
  57. }
  58. isLoadingMap[nodeId] = false; // ping结束后设置为false
  59. isLoadingMap.refresh(); // 通知观察者
  60. }
  61. }
  62. void pingAllNodes() async {
  63. for (var node in nodeModes) {
  64. tcpPing(node); // 这里用了 await 使其串行 ping,若希望并行可移除 await
  65. }
  66. }
  67. Future<void> pingSingleNode(NodeMode node) async {
  68. await tcpPing(node);
  69. }
  70. void selectNode(NodeMode node) {
  71. selectedNode.value = node;
  72. _storeSelectedNode(node);
  73. //selectedIndex.value = nodeModes.indexWhere((item) => item.id == node.id);
  74. }
  75. Future<void> _storeSelectedNode(NodeMode node) async {
  76. final prefs = await SharedPreferences.getInstance();
  77. // 为简化起见,我们只存储node的ID,但您可以根据需要存储更多信息
  78. prefs.setInt('selectedNodeId', node.id!);
  79. }
  80. Future<void> loadSelectedNode() async {
  81. final prefs = await SharedPreferences.getInstance();
  82. final selectedNodeId = prefs.getInt('selectedNodeId');
  83. if (selectedNodeId != null) {
  84. //selectedIndex.value = nodeModes.indexWhere((item) => item.id == selectedNodeId);
  85. selectedNode.value = nodeModes.firstWhere((node) => node.id == selectedNodeId);
  86. }
  87. }
  88. //自动选择人数最小的线路
  89. NodeMode selectBestNode(List<NodeMode> nodes) {
  90. return nodes.where((node) => node.countryCode == 'HK') //筛选地区是HK的节点
  91. .reduce((value, element) =>
  92. value.onlineUsers! < element.onlineUsers! ? value : element); //选择人数最小的
  93. }
  94. void selectMinOnlineUsersNodeInRegion(String region) {
  95. List<NodeMode> nodesInRegion = nodeModes.where((node) => node.countryCode == region).toList();
  96. if (nodesInRegion.isNotEmpty) {
  97. NodeMode? minNode = nodesInRegion.reduce((curr, next) => curr.onlineUsers! <= next.onlineUsers! ? curr : next);
  98. if (minNode != null) {
  99. selectNode(minNode);
  100. }
  101. }
  102. }
  103. void filterNodesWithLeastUsersInHK() {
  104. displayStrategy.value = NodeDisplayStrategy.LeastUsers;
  105. updateNodesToDisplay();
  106. }
  107. void filterNodesByRegion(String region) {
  108. nodesToShow.value = nodeModes.where((node) => node.countryCode == region).toList();
  109. updateNodesToDisplay();
  110. }
  111. void showAllNodes() {
  112. displayStrategy.value = NodeDisplayStrategy.All;
  113. updateNodesToDisplay();
  114. // nodesToShow.value = List.from(nodeModes);
  115. }
  116. void showSelectedFirst() {
  117. displayStrategy.value = NodeDisplayStrategy.SelectedFirst;
  118. updateNodesToDisplay();
  119. // 如果需要,可以添加其他逻辑。
  120. }
  121. void updateNodesToDisplay() {
  122. List<NodeMode> nodes = List.from(nodeModes);
  123. switch (displayStrategy.value) {
  124. case NodeDisplayStrategy.LeastUsers:
  125. List<NodeMode> filteredNodes = nodeModes.where((node) => node.countryCode == "hk" && node.onlineUsers != null).toList();
  126. if (filteredNodes.isNotEmpty) {
  127. int? minUsers = filteredNodes.map((node) => node.onlineUsers!).reduce((curr, next) => curr < next ? curr : next);
  128. nodes = nodes.where((node) => node.onlineUsers == minUsers && node.countryCode == "hk").toList();
  129. selectNode(nodes.first);
  130. } else {
  131. // Handle the case where no nodes match the criteria. Maybe display a message or use a fallback.
  132. nodes = []; // Empty list or some fallback
  133. }
  134. break;
  135. case NodeDisplayStrategy.SelectedFirst:
  136. break;
  137. case NodeDisplayStrategy.All:
  138. // // 将选中的节点移动到前面
  139. // if (selectedNode.value != null) {
  140. // nodes.removeWhere((node) => node.id == selectedNode.value?.id);
  141. // nodes.insert(0, selectedNode.value!);
  142. // }
  143. break;
  144. default:
  145. // 不需要额外的处理,因为nodes已经包含所有节点。
  146. break;
  147. }
  148. nodesToShow.value = nodes; // 使用 assignAll() 方法触发更新
  149. }
  150. @override
  151. void onInit() {
  152. super.onInit();
  153. //fetchNodes();
  154. globalController = Get.put(GlobalController());
  155. nodeModes = globalController.nodeModes;
  156. nodesToShow.value = nodeModes;
  157. }
  158. @override
  159. void onReady() {
  160. super.onReady();
  161. }
  162. @override
  163. void onClose() {
  164. super.onClose();
  165. }
  166. void increment() => count.value++;
  167. }