delay.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import { getProxyDelay } from "./api";
  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: ApiType.ProxyItem, group: string) {
  46. if (!proxy.provider) return this.getDelay(proxy.name, group);
  47. if (proxy.history.length > 0) {
  48. // 0ms以error显示
  49. return proxy.history[proxy.history.length - 1].delay || 1e6;
  50. }
  51. return -1;
  52. }
  53. async checkDelay(name: string, group: string) {
  54. let delay = -1;
  55. try {
  56. const url = this.getUrl(group);
  57. const result = await getProxyDelay(name, url);
  58. delay = result.delay;
  59. } catch {
  60. delay = 1e6; // error
  61. }
  62. this.setDelay(name, group, delay);
  63. return delay;
  64. }
  65. async checkListDelay(
  66. nameList: readonly string[],
  67. groupName: string,
  68. concurrency: number
  69. ) {
  70. const names = [...nameList];
  71. let total = names.length;
  72. let current = 0;
  73. // 设置正在延迟测试中
  74. names.forEach((name) => this.setDelay(name, groupName, -2));
  75. return new Promise((resolve) => {
  76. const help = async (): Promise<void> => {
  77. if (current >= concurrency) return;
  78. const task = names.shift();
  79. if (!task) return;
  80. current += 1;
  81. await this.checkDelay(task, groupName);
  82. current -= 1;
  83. total -= 1;
  84. if (total <= 0) resolve(null);
  85. else return help();
  86. };
  87. for (let i = 0; i < concurrency; ++i) help();
  88. });
  89. }
  90. }
  91. export default new DelayManager();