node_controller.dart 5.9 KB

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