1
+ import re
2
+ import wx
3
+ import subprocess
4
+ from concurrent .futures import ThreadPoolExecutor
5
+
6
+ from utils .config import Config
7
+ from utils .common .map import cdn_map
8
+
9
+ class ChangeCDNDialog (wx .Dialog ):
10
+ def __init__ (self , parent ):
11
+ wx .Dialog .__init__ (self , parent , - 1 , "更改 CDN" )
12
+
13
+ self .init_UI ()
14
+
15
+ self .Bind_EVT ()
16
+
17
+ self .init_utils ()
18
+
19
+ self .CenterOnParent ()
20
+
21
+ def init_UI (self ):
22
+ def _get_scale_size (_size : tuple ):
23
+ match Config .Sys .platform :
24
+ case "windows" :
25
+ return self .FromDIP (_size )
26
+
27
+ case "linux" | "darwin" :
28
+ return wx .DefaultSize
29
+
30
+ cdn_lab = wx .StaticText (self , - 1 , "CDN 列表" )
31
+
32
+ self .cdn_list = wx .ListCtrl (self , - 1 , size = self .FromDIP ((650 , 250 )), style = wx .LC_REPORT | wx .LC_SINGLE_SEL )
33
+ self .cdn_list .EnableCheckBoxes (True )
34
+
35
+ custom_lab = wx .StaticText (self , - 1 , "自定义" )
36
+ self .custom_box = wx .TextCtrl (self , - 1 , size = _get_scale_size ((240 , 24 )))
37
+ self .add_btn = wx .Button (self , - 1 , "添加" , size = _get_scale_size ((80 , 28 )))
38
+ self .delete_btn = wx .Button (self , - 1 , "删除" , size = _get_scale_size ((80 , 28 )))
39
+
40
+ self .ping_btn = wx .Button (self , - 1 , "Ping 测试" , size = _get_scale_size ((100 , 28 )))
41
+
42
+ action_hbox = wx .BoxSizer (wx .HORIZONTAL )
43
+ action_hbox .Add (custom_lab , 0 , wx .ALL & (~ wx .TOP ) & (~ wx .BOTTOM ) | wx .ALIGN_CENTER , 10 )
44
+ action_hbox .Add (self .custom_box , 0 , wx .ALL & (~ wx .TOP ) & (~ wx .BOTTOM ) & (~ wx .LEFT ) | wx .ALIGN_CENTER , 10 )
45
+ action_hbox .Add (self .add_btn , 0 , wx .ALL & (~ wx .TOP ) & (~ wx .BOTTOM ) & (~ wx .LEFT ), 10 )
46
+ action_hbox .Add (self .delete_btn , 0 , wx .ALL & (~ wx .TOP ) & (~ wx .BOTTOM ) & (~ wx .LEFT ), 10 )
47
+ action_hbox .AddStretchSpacer ()
48
+ action_hbox .Add (self .ping_btn , 0 , wx .ALL & (~ wx .TOP ) & (~ wx .BOTTOM ), 10 )
49
+
50
+ bottom_line = wx .StaticLine (self , - 1 )
51
+
52
+ self .ok_btn = wx .Button (self , wx .ID_OK , "确定" , size = _get_scale_size ((80 , 30 )))
53
+ self .cancel_btn = wx .Button (self , wx .ID_CANCEL , "取消" , size = _get_scale_size ((80 , 30 )))
54
+
55
+ bottom_hbox = wx .BoxSizer (wx .HORIZONTAL )
56
+ bottom_hbox .AddStretchSpacer (1 )
57
+ bottom_hbox .Add (self .ok_btn , 0 , wx .ALL & (~ wx .TOP ), 10 )
58
+ bottom_hbox .Add (self .cancel_btn , 0 , wx .ALL & (~ wx .TOP ) & (~ wx .LEFT ), 10 )
59
+
60
+ vbox = wx .BoxSizer (wx .VERTICAL )
61
+ vbox .Add (cdn_lab , 0 , wx .ALL & (~ wx .BOTTOM ), 10 )
62
+ vbox .Add (self .cdn_list , 0 , wx .ALL | wx .EXPAND , 10 )
63
+ vbox .Add (action_hbox , 0 , wx .EXPAND )
64
+ vbox .Add (bottom_line , 0 , wx .ALL | wx .EXPAND , 10 )
65
+ vbox .Add (bottom_hbox , 0 , wx .EXPAND )
66
+
67
+ self .SetSizerAndFit (vbox )
68
+
69
+ def Bind_EVT (self ):
70
+ self .cdn_list .Bind (wx .EVT_LIST_ITEM_CHECKED , self .onCheckEVT )
71
+ self .cdn_list .Bind (wx .EVT_LIST_ITEM_ACTIVATED , self .onItemActivateEVT )
72
+
73
+ self .ping_btn .Bind (wx .EVT_BUTTON , self .onPingTestEVT )
74
+ self .add_btn .Bind (wx .EVT_BUTTON , self .onAddCDNEVT )
75
+ self .delete_btn .Bind (wx .EVT_BUTTON , self .onDeleteCDNEVT )
76
+ self .ok_btn .Bind (wx .EVT_BUTTON , self .onConfirm )
77
+
78
+ def init_utils (self ):
79
+ def init_listctrl ():
80
+ self .cdn_list .AppendColumn ("序号" , width = self .FromDIP (75 ))
81
+ self .cdn_list .AppendColumn ("CDN" , width = self .FromDIP (280 ))
82
+ self .cdn_list .AppendColumn ("提供商" , width = self .FromDIP (140 ))
83
+ self .cdn_list .AppendColumn ("延迟" , width = self .FromDIP (100 ))
84
+
85
+ def init_cdn_list ():
86
+ for key , value in cdn_map .items ():
87
+ index = self .cdn_list .Append ([str (key + 1 ), value ["cdn" ], value ["provider" ], "未知" ])
88
+
89
+ if value ["cdn" ] == Config .Advanced .custom_cdn :
90
+ self .cdn_list .CheckItem (index )
91
+
92
+ self .update_index ()
93
+
94
+ self ._last_index = - 1
95
+
96
+ init_listctrl ()
97
+ init_cdn_list ()
98
+
99
+ def get_cdn (self ):
100
+ return self .cdn_list .GetItemText (self ._last_index , 1 )
101
+
102
+ def onConfirm (self , event ):
103
+ if self ._last_index == - 1 or not self .cdn_list .IsItemChecked (self ._last_index ):
104
+ wx .MessageDialog (self , "更改失败\n \n 请选择需要更改的 CDN" , "警告" , wx .ICON_WARNING ).ShowModal ()
105
+ return
106
+
107
+ event .Skip ()
108
+
109
+ def onPingTestEVT (self , event ):
110
+ def worker (index : int , cdn : str ):
111
+ def update (value ):
112
+ self .cdn_list .SetItem (index , 3 , value )
113
+
114
+ def get_ping_cmd () -> str :
115
+ match Config .Sys .platform :
116
+ case "windows" :
117
+ return f"ping { cdn } "
118
+
119
+ case "linux" | "darwin" :
120
+ return f"ping { cdn } -c 4"
121
+
122
+ def get_latency ():
123
+ match Config .Sys .platform :
124
+ case "windows" :
125
+ return re .findall (r"Average = ([0-9]*)" , process .stdout )
126
+
127
+ case "linux" | "darwin" :
128
+ _temp = re .findall (r"time=([0-9]*)" , process .stdout )
129
+
130
+ if _temp :
131
+ return [int (sum (list (map (int , _temp ))) / len (_temp ))]
132
+ else :
133
+ return None
134
+
135
+ wx .CallAfter (update , "正在检测..." )
136
+
137
+ process = subprocess .run (get_ping_cmd (), stdout = subprocess .PIPE , stderr = subprocess .STDOUT , shell = True , text = True , encoding = "utf-8" )
138
+ latency = get_latency ()
139
+
140
+ if latency :
141
+ result = f"{ latency [0 ]} ms"
142
+ else :
143
+ result = "请求超时"
144
+
145
+ wx .CallAfter (update , result )
146
+
147
+ thread_pool = ThreadPoolExecutor (max_workers = 5 )
148
+
149
+ for i in range (self .cdn_list .GetItemCount ()):
150
+ item : wx .ListItem = self .cdn_list .GetItem (i , 1 )
151
+
152
+ thread_pool .submit (worker , i , item .GetText ())
153
+
154
+ def onCheckEVT (self , event : wx .ListEvent ):
155
+ index = event .GetIndex ()
156
+
157
+ if self ._last_index != - 1 and self ._last_index != index :
158
+ self .cdn_list .CheckItem (self ._last_index , False )
159
+
160
+ self .cdn_list .Select (index )
161
+
162
+ self ._last_index = index
163
+
164
+ def onItemActivateEVT (self , event : wx .ListEvent ):
165
+ index = event .GetIndex ()
166
+
167
+ self .cdn_list .CheckItem (index )
168
+
169
+ def onAddCDNEVT (self , event ):
170
+ if not self .custom_box .GetValue ():
171
+ wx .MessageDialog (self , "添加失败\n \n 请输入要添加的 CDN" , "警告" , wx .ICON_WARNING ).ShowModal ()
172
+ self .custom_box .SetFocus ()
173
+ return
174
+
175
+ for i in range (self .cdn_list .GetItemCount ()):
176
+ item : wx .ListItem = self .cdn_list .GetItem (i , 1 )
177
+
178
+ if item .GetText () == self .custom_box .GetValue ():
179
+ wx .MessageDialog (self , "添加失败\n \n 已存在相同的 CDN,无法重复添加" , "警告" , wx .ICON_WARNING ).ShowModal ()
180
+ self .custom_box .SetFocus ()
181
+ return
182
+
183
+ self .cdn_list .SetFocus ()
184
+
185
+ index = self .cdn_list .Append (["-" , self .custom_box .GetValue (), "自定义" , "未知" ])
186
+
187
+ Config .Advanced .custom_cdn_list .append (self .custom_box .GetValue ())
188
+
189
+ self .cdn_list .Focus (index )
190
+ self .cdn_list .Select (index )
191
+
192
+ self .update_index ()
193
+
194
+ def onDeleteCDNEVT (self , event ):
195
+ if self ._last_index == - 1 or not self .cdn_list .IsItemChecked (self ._last_index ):
196
+ wx .MessageDialog (self , "删除失败\n \n 请选择要删除的 CDN" , "警告" , wx .ICON_WARNING ).ShowModal ()
197
+ self .cdn_list .SetFocus ()
198
+ return
199
+
200
+ cdn = self .cdn_list .GetItemText (self ._last_index , 1 )
201
+
202
+ if self .cdn_list .GetItemText (self ._last_index , 2 ) != "自定义" :
203
+ wx .MessageDialog (self , "删除失败\n \n 仅支持删除自定义的 CDN" , "警告" , wx .ICON_WARNING ).ShowModal ()
204
+ self .cdn_list .SetFocus ()
205
+ return
206
+
207
+ self .cdn_list .DeleteItem (self ._last_index )
208
+
209
+ Config .Advanced .custom_cdn_list .remove (cdn )
210
+
211
+ self ._last_index = - 1
212
+
213
+ self .update_index ()
214
+
215
+ def update_index (self ):
216
+ for i in range (self .cdn_list .GetItemCount ()):
217
+ self .cdn_list .SetItem (i , 0 , str (i + 1 ))
0 commit comments