forked from cmliu/SubsCheck-Win-GUI
-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathProxy.cs
More file actions
157 lines (142 loc) · 5.43 KB
/
Proxy.cs
File metadata and controls
157 lines (142 loc) · 5.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace subs_check.win.gui
{
internal class Proxy
{
// 常见代理端口
private static readonly List<string> CommonProxies = new List<string>
{
"http://127.0.0.1:7890",
"http://127.0.0.1:7891",
"http://127.0.0.1:1080",
"http://127.0.0.1:8080",
"http://127.0.0.1:10808",
"http://127.0.0.1:10809",
"http://127.0.0.1:3067",
"http://127.0.0.1:2080",
"http://127.0.0.1:1194",
"http://127.0.0.1:1082",
"http://127.0.0.1:12334",
"http://127.0.0.1:12335"
};
public class SysProxyResult
{
public bool IsAvailable { get; set; }
public string Address { get; set; }
}
/// <summary>
/// 检测系统代理是否可用,并设置环境变量
/// </summary>
public static Task<SysProxyResult> GetSysProxyAsync(string configProxy)
{
return FindAvailableSysProxyAsync(configProxy, CommonProxies)
.ContinueWith(t =>
{
string proxy = t.Result;
if (!string.IsNullOrEmpty(proxy))
{
Environment.SetEnvironmentVariable("HTTP_PROXY", proxy);
Environment.SetEnvironmentVariable("HTTPS_PROXY", proxy);
Console.WriteLine("系统代理可用: " + proxy);
return new SysProxyResult
{
IsAvailable = true,
Address = proxy
};
}
Console.WriteLine("未找到可用代理,将不设置代理");
return new SysProxyResult
{
IsAvailable = false,
Address = string.Empty
};
});
}
/// <summary>
/// 检测代理是否可用(要求 Google 204 和 GitHub Raw 都成功)
/// </summary>
private static async Task<bool> IsSysProxyAvailableAsync(string proxy, CancellationToken token = default)
{
try
{
var proxyUri = new Uri(proxy);
var handler = new HttpClientHandler
{
Proxy = new WebProxy(proxyUri),
UseProxy = true
};
using (var client = new HttpClient(handler))
{
client.Timeout = TimeSpan.FromSeconds(10);
client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win32; x86) AppleWebKit/537.36 (KHTML, like Gecko) cmliu/SubsCheck-Win-GUI");
var testTasks = new[]
{
client.GetAsync("https://www.google.com/generate_204", token),
client.GetAsync("https://raw.githubusercontent.com/github/gitignore/main/Go.gitignore", token)
};
var responses = await Task.WhenAll(testTasks);
return responses[0].StatusCode == HttpStatusCode.NoContent && responses[1].StatusCode == HttpStatusCode.OK;
}
}
catch (OperationCanceledException)
{
return false; // Expected cancellation
}
catch
{
return false;
}
}
/// <summary>
/// 优先检测配置文件中的代理,不可用则并发检测常见端口
/// </summary>
private static async Task<string> FindAvailableSysProxyAsync(string configProxy, List<string> candidates)
{
// Step 1: 优先检测配置文件中的代理
if (!string.IsNullOrEmpty(configProxy) && await IsSysProxyAvailableAsync(configProxy))
{
return configProxy;
}
// Step 2: 并发检测候选代理
var cts = new CancellationTokenSource();
var runningTasks = new List<Task<string>>();
foreach (var p in candidates)
{
runningTasks.Add(Task.Run(async () =>
{
if (await IsSysProxyAvailableAsync(p, cts.Token))
{
return p;
}
return null;
}, cts.Token));
}
while (runningTasks.Any())
{
var completedTask = await Task.WhenAny(runningTasks);
runningTasks.Remove(completedTask);
try
{
string result = await completedTask;
if (!string.IsNullOrEmpty(result))
{
cts.Cancel(); // 找到一个就取消其他任务
return result; // 立即返回结果
}
}
catch (OperationCanceledException)
{
// This task was canceled because another one finished first. Ignore.
}
// Other exceptions can be logged if needed.
}
return string.Empty;
}
}
}