delay.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import { cmdGetProxyDelay } from "./cmds";
  2. const hashKey = (name: string, group: string) => `${group ?? ""}::${name}`;
  3. class DelayManager {
  4. private cache = new Map<string, [number, number]>();
  5. private urlMap = new Map<string, string>();
  6. // 每个item的监听
  7. private listenerMap = new Map<string, (time: number) => void>();
  8. // 每个分组的监听
  9. private groupListenerMap = new Map<string, () => void>();
  10. setUrl(group: string, url: string) {
  11. this.urlMap.set(group, url);
  12. }
  13. getUrl(group: string) {
  14. return this.urlMap.get(group);
  15. }
  16. setListener(name: string, group: string, listener: (time: number) => void) {
  17. const key = hashKey(name, group);
  18. this.listenerMap.set(key, listener);
  19. }
  20. removeListener(name: string, group: string) {
  21. const key = hashKey(name, group);
  22. this.listenerMap.delete(key);
  23. }
  24. setGroupListener(group: string, listener: () => void) {
  25. this.groupListenerMap.set(group, listener);
  26. }
  27. removeGroupListener(group: string) {
  28. this.groupListenerMap.delete(group);
  29. }
  30. setDelay(name: string, group: string, delay: number) {
  31. const key = hashKey(name, group);
  32. this.cache.set(key, [Date.now(), delay]);
  33. this.listenerMap.get(key)?.(delay);
  34. this.groupListenerMap.get(group)?.();
  35. }
  36. getDelay(name: string, group: string) {
  37. if (!name) return -1;
  38. const result = this.cache.get(hashKey(name, group));
  39. if (result && Date.now() - result[0] <= 18e5) {
  40. return result[1];
  41. }
  42. return -1;
  43. }
  44. /// 暂时修复provider的节点延迟排序的问题
  45. getDelayFix(proxy: IProxyItem, group: string) {
  46. if (!proxy.provider) {
  47. const delay = this.getDelay(proxy.name, group);
  48. if (delay >= 0 || delay === -2) return delay;
  49. }
  50. if (proxy.history.length > 0) {
  51. // 0ms以error显示
  52. return proxy.history[proxy.history.length - 1].delay || 1e6;
  53. }
  54. return -1;
  55. }
  56. async checkDelay(name: string, group: string) {
  57. let delay = -1;
  58. try {
  59. const url = this.getUrl(group);
  60. const result = await cmdGetProxyDelay(name, url);
  61. delay = result.delay;
  62. } catch {
  63. delay = 1e6; // error
  64. }
  65. this.setDelay(name, group, delay);
  66. return delay;
  67. }
  68. async checkListDelay(nameList: string[], group: string, concurrency = 36) {
  69. const names = nameList.filter(Boolean);
  70. // 设置正在延迟测试中
  71. names.forEach((name) => this.setDelay(name, group, -2));
  72. let total = names.length;
  73. let current = 0;
  74. return new Promise((resolve) => {
  75. const help = async (): Promise<void> => {
  76. if (current >= concurrency) return;
  77. const task = names.shift();
  78. if (!task) return;
  79. current += 1;
  80. await this.checkDelay(task, group);
  81. current -= 1;
  82. total -= 1;
  83. if (total <= 0) resolve(null);
  84. else return help();
  85. };
  86. for (let i = 0; i < concurrency; ++i) help();
  87. });
  88. }
  89. formatDelay(delay: number) {
  90. if (delay <= 0) return "Error";
  91. if (delay > 1e5) return "Error";
  92. if (delay >= 10000) return "Timeout"; // 10s
  93. return `${delay} ms`;
  94. }
  95. formatDelayColor(delay: number) {
  96. if (delay >= 10000) return "error.main";
  97. if (delay <= 0) return "error.main";
  98. if (delay > 500) return "warning.main";
  99. return "success.main";
  100. }
  101. }
  102. export default new DelayManager();