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