node_controller.dart 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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.selectedNode.value = node;
  55. _storeSelectedNode(node);
  56. Get.back();
  57. //selectedIndex.value = nodeModes.indexWhere((item) => item.id == node.id);
  58. }
  59. Future<void> _storeSelectedNode(NodeMode node) async {
  60. final prefs = await SharedPreferences.getInstance();
  61. // 为简化起见,我们只存储node的ID,但您可以根据需要存储更多信息
  62. prefs.setInt('selectedNodeId', node.id);
  63. await controllers.global.loadSelectedNode();
  64. }
  65. // Future<void> loadSelectedNode() async {
  66. // final prefs = await SharedPreferences.getInstance();
  67. // final selectedNodeId = prefs.getInt('selectedNodeId');
  68. // if (selectedNodeId != null) {
  69. // //selectedIndex.value = nodeModes.indexWhere((item) => item.id == selectedNodeId);
  70. // selectedNode.value = nodeModes.firstWhere((node) => node.id == selectedNodeId);
  71. // }
  72. // }
  73. //自动选择人数最小的线路
  74. NodeMode selectBestNode(List<NodeMode> nodes) {
  75. return nodes.where((node) => node.countryCode == 'HK') //筛选地区是HK的节点
  76. .reduce((value, element) =>
  77. value.onlineUsers< element.onlineUsers? value : element); //选择人数最小的
  78. }
  79. void selectMinOnlineUsersNodeInRegion(String region) {
  80. List<NodeMode> nodesInRegion = nodeModes.where((node) => node.countryCode == region).toList();
  81. if (nodesInRegion.isNotEmpty) {
  82. NodeMode? minNode = nodesInRegion.reduce((curr, next) => curr.onlineUsers! <= next.onlineUsers! ? curr : next);
  83. selectNode(minNode);
  84. }
  85. }
  86. void filterNodesWithLeastUsersInHK() {
  87. displayStrategy.value = NodeDisplayStrategy.LeastUsers;
  88. updateNodesToDisplay();
  89. }
  90. void filterNodesByRegion(String region) {
  91. nodesToShow.value = nodeModes.where((node) => node.countryCode == region).toList();
  92. updateNodesToDisplay();
  93. }
  94. void showAllNodes() {
  95. displayStrategy.value = NodeDisplayStrategy.All;
  96. updateNodesToDisplay();
  97. // nodesToShow.value = List.from(nodeModes);
  98. }
  99. void showSelectedFirst() {
  100. displayStrategy.value = NodeDisplayStrategy.SelectedFirst;
  101. updateNodesToDisplay();
  102. // 如果需要,可以添加其他逻辑。
  103. }
  104. void updateNodesToDisplay() {
  105. List<NodeMode> nodes = List.from(nodeModes);
  106. switch (displayStrategy.value) {
  107. case NodeDisplayStrategy.LeastUsers:
  108. List<NodeMode> filteredNodes = nodeModes.where((node) => node.countryCode == "hk" && node.onlineUsers != null).toList();
  109. if (filteredNodes.isNotEmpty) {
  110. int? minUsers = filteredNodes.map((node) => node.onlineUsers!).reduce((curr, next) => curr < next ? curr : next);
  111. nodes = nodes.where((node) => node.onlineUsers == minUsers && node.countryCode == "hk").toList();
  112. selectNode(nodes.first);
  113. } else {
  114. // Handle the case where no nodes match the criteria. Maybe display a message or use a fallback.
  115. nodes = []; // Empty list or some fallback
  116. }
  117. break;
  118. case NodeDisplayStrategy.SelectedFirst:
  119. break;
  120. case NodeDisplayStrategy.All:
  121. // // 将选中的节点移动到前面
  122. // if (selectedNode.value != null) {
  123. // nodes.removeWhere((node) => node.id == selectedNode.value?.id);
  124. // nodes.insert(0, selectedNode.value!);
  125. // }
  126. break;
  127. default:
  128. // 不需要额外的处理,因为nodes已经包含所有节点。
  129. break;
  130. }
  131. nodesToShow.value = nodes; // 使用 assignAll() 方法触发更新
  132. }
  133. @override
  134. void onInit() {
  135. super.onInit();
  136. nodeModes = controllers.global.nodeModes;
  137. nodesToShow.value = nodeModes;
  138. }
  139. @override
  140. void onReady() {
  141. super.onReady();
  142. }
  143. @override
  144. void onClose() {
  145. super.onClose();
  146. }
  147. void increment() => count.value++;
  148. }