66import os
77import tempfile
88import subprocess
9-
9+ import uuid
1010
1111class PingThread (QThread ):
1212 pingSignal = pyqtSignal (str ,float )
@@ -74,10 +74,22 @@ def sources(self,sources:dict):
7474
7575 @property
7676 def currentSource (self ):
77+ """
78+ 当前使用的源
79+ """
7780 return self .__currentSource
7881
7982 @currentSource .setter
8083 def currentSource (self ,currentSource :str ):
84+ """
85+ 设置当前使用的源
86+
87+ Args:
88+ currentSource (str): 源名称
89+
90+ Raises:
91+ ValueError: 如果currentSource不在sources中
92+ """
8193 if currentSource not in self .sources :
8294 raise ValueError
8395 self .__currentSource = currentSource
@@ -87,6 +99,9 @@ def currentSourceUrl(self):
8799 return self .sources [self .currentSource ]
88100
89101 def checkSourceSpeed (self ):
102+ """
103+ 检查所有源的速度,并发射quickSource(name:str,time:float)信号
104+ """
90105 self .threads .clear ()
91106 self .speedData = {}
92107 for source in self .sources :
@@ -127,12 +142,21 @@ class GitHub(QObject):
127142 downloadReleaseAsyncFinishSignal = pyqtSignal (str )
128143 errorSignal = pyqtSignal (str )
129144 def __init__ (self ,sourcemanager :SourceManager ,owner :str ,repo :str ,version :str ,versionReStr :str ,parent = None ):
145+ """
146+ :param sourcemanager: 一个SourceManager实例,提供了多个github api的url
147+ :param owner: github的owner
148+ :param repo: github的仓库名
149+ :param version: 当前的版本号
150+ :param versionReStr: 一个正则表达式串,用于从github的release中,提取版本号
151+ :param parent: 一个QObject实例,父对象
152+ """
130153 super ().__init__ (parent )
131154 self .__sourcemanager = sourcemanager
132155 self .__owner = owner
133156 self .__repo = repo
134157 self .__version = version
135158 self .__versionReStr = versionReStr
159+ self .__replyDict = {}
136160
137161 @property
138162 def sourceManager (self ):
@@ -175,20 +199,36 @@ def versionReStr(self,versionReStr:str):
175199 self .__versionReStr = versionReStr
176200 @property
177201 def latestReleaseUrl (self ) -> str :
202+ """
203+ 获取最新的release的url
204+ """
178205 return f'{ self .sourceManager .currentSourceUrl } /{ self .__owner } /{ self .__repo } /releases/latest'
179206 @property
180207 def releasesUrl (self ) -> str :
208+ """
209+ 获取所有release的url
210+ """
181211 return f'{ self .sourceManager .currentSourceUrl } /{ self .__owner } /{ self .__repo } /releases'
182212 @property
183213 def header (self ) -> dict :
184214 return {
185215 'Accept' :'application/vnd.github.v3+json' ,
186216 'User-Agent' :'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'
187217 }
188- def isNeedUpdate (self ,isAsync :bool = True ) -> bool | None :
218+ def isNeedUpdate (self ,isAsync :bool = True ) -> bool | str | None :
219+ """
220+ 判断是否需要更新
221+
222+ :param isAsync: 是否异步
223+ :return: bool :如果不是异步,返回True表示需要更新,False表示不需要更新,None表示网络错误 \n
224+ str: 如果是异步,返回一个当前请求的唯一标识,并发射isNeedUpdateAsyncSignal信号
225+ """
226+
189227 nam = QNetworkAccessManager (self )
190228 request = QNetworkRequest (QUrl (self .latestReleaseUrl ))
191229 reply = nam .get (request )
230+ reply .setObjectName (str (uuid .uuid1 ()))
231+ self .__replyDict [reply .objectName ()] = reply
192232 if not isAsync :
193233 loop = QEventLoop ()
194234 reply .finished .connect (loop .quit )
@@ -197,11 +237,12 @@ def isNeedUpdate(self,isAsync:bool = True) -> bool | None:
197237 self .error (reply .errorString ())
198238 return None
199239 data = reply .readAll ().data ().decode ('utf-8' )
240+ self .__replyDict .pop (reply .objectName ())
200241 reply .deleteLater ()
201242 return self .__isNeedUpdate (data )
202243 else :
203244 nam .finished .connect (self .__isNeedUpdateAsync )
204- return None
245+ return reply . objectName ()
205246
206247 def __isNeedUpdate (self ,data )-> bool :
207248 release = Release (json .loads (data ))
@@ -215,16 +256,29 @@ def __isNeedUpdate(self,data)->bool:
215256 return True
216257
217258 def __isNeedUpdateAsync (self ,reply :QNetworkReply ):
218- if reply .error () != QNetworkReply .NoError :
259+ if reply .error () == QNetworkReply .NetworkError .OperationCanceledError :
260+ pass
261+ elif reply .error () != QNetworkReply .NoError :
219262 self .error (reply .errorString ())
220- return
221- self .isNeedUpdateAsyncSignal .emit (self .__isNeedUpdate (reply .readAll ().data ().decode ('utf-8' )))
263+ else :
264+ self .isNeedUpdateAsyncSignal .emit (self .__isNeedUpdate (reply .readAll ().data ().decode ('utf-8' )))
265+ self .__replyDict .pop (reply .objectName ())
222266 reply .deleteLater ()
223267
224- def latestRelease (self ,isAsync :bool = True ) -> Release | None :
268+ def latestRelease (self ,isAsync :bool = True ) -> Release | str | None :
269+ """
270+ 获取最新的release
271+
272+ :param isAsync: 是否异步
273+ :return: bool :如果不是异步,返回一个Release实例
274+ str: 如果是异步,返回一个当前请求的唯一标识,并发射latestReleaseAsyncSignal信号
275+ """
276+
225277 nam = QNetworkAccessManager (self )
226278 request = QNetworkRequest (QUrl (self .latestReleaseUrl ))
227279 reply = nam .get (request )
280+ reply .setObjectName (str (uuid .uuid1 ()))
281+ self .__replyDict [reply .objectName ()] = reply
228282 if not isAsync :
229283 loop = QEventLoop ()
230284 reply .finished .connect (loop .quit )
@@ -233,23 +287,36 @@ def latestRelease(self,isAsync:bool = True) -> Release | None:
233287 self .error (reply .errorString ())
234288 return None
235289 data = reply .readAll ().data ().decode ('utf-8' )
290+ self .__replyDict .pop (reply .objectName ())
236291 reply .deleteLater ()
237292 return Release (json .loads (data ))
238293 else :
239294 nam .finished .connect (self .__lastReleaseAsync )
240- return None
295+ return reply . objectName ()
241296
242297 def __lastReleaseAsync (self ,reply :QNetworkReply ):
243- if reply .error () != QNetworkReply .NoError :
298+ if reply .error () == QNetworkReply .NetworkError .OperationCanceledError :
299+ pass
300+ elif reply .error () != QNetworkReply .NoError :
244301 self .error (reply .errorString ())
245- return
246- self .latestReleaseAsyncSignal .emit (Release (json .loads (reply .readAll ().data ().decode ('utf-8' ))))
247-
302+ else :
303+ self .latestReleaseAsyncSignal .emit (Release (json .loads (reply .readAll ().data ().decode ('utf-8' ))))
304+ self .__replyDict .pop (reply .objectName ())
305+ reply .deleteLater ()
248306
249- def releases (self ,isAsync :bool = True ) -> list | None :
307+ def releases (self ,isAsync :bool = True ) -> list | str | None :
308+ """
309+ 获取所有release
310+
311+ :param isAsync: 是否异步
312+ :return: list :如果不是异步,返回一个Release实例的列表
313+ str: 如果是异步,返回一个当前请求的唯一标识,并发射releasesAsyncSignal信号
314+ """
250315 nam = QNetworkAccessManager (self )
251316 request = QNetworkRequest (QUrl (self .releasesUrl ))
252317 reply = nam .get (request )
318+ reply .setObjectName (str (uuid .uuid1 ()))
319+ self .__replyDict [reply .objectName ()] = reply
253320 if not isAsync :
254321 loop = QEventLoop ()
255322 reply .finished .connect (loop .quit )
@@ -258,51 +325,79 @@ def releases(self,isAsync:bool = True) -> list | None:
258325 self .error (reply .errorString ())
259326 return None
260327 data = reply .readAll ().data ().decode ('utf-8' )
328+ self .__replyDict .pop (reply .objectName ())
261329 reply .deleteLater ()
262330 return self .__releases (data )
263331 else :
264332 nam .finished .connect (self .__releasesAsync )
265- return None
333+ return reply . objectName ()
266334
267335
268336 def __releases (self ,data ) -> list | None :
269337 return [Release (x ) for x in json .loads (data )]
270338
271339 def __releasesAsync (self ,reply :QNetworkReply ):
272- if reply .error () != QNetworkReply .NoError :
340+ if reply .error () == QNetworkReply .NetworkError .OperationCanceledError :
341+ pass
342+ elif reply .error () != QNetworkReply .NoError :
273343 self .error (reply .errorString ())
274- return
275- releases = self .__releases (reply .readAll ().data ().decode ('utf-8' ))
344+ else :
345+ releases = self .__releases (reply .readAll ().data ().decode ('utf-8' ))
346+ self .releasesAsyncSignal .emit (releases )
347+ self .__replyDict .pop (reply .objectName (),None )
276348 reply .deleteLater ()
277- self .releasesAsyncSignal .emit (releases )
278349
279- def downloadRelease (self ,release :Release ):
280- nam = QNetworkAccessManager (self )
350+
351+ def downloadRelease (self ,release :Release ) -> str :
352+ """
353+ 下载release
354+
355+ :param release: 需要下载的release
356+ :return: 一个当前请求的唯一标识
357+ """
281358 self .downloadReleaseAsyncStartSignal .emit (release )
359+ nam = QNetworkAccessManager (self )
282360 request = QNetworkRequest (QUrl (release .assets_browser_download_url ))
283361 request .setAttribute (QNetworkRequest .Attribute .FollowRedirectsAttribute ,True )
284362 reply = nam .get (request )
363+ reply .setObjectName (str (uuid .uuid1 ()))
364+ self .__replyDict [reply .objectName ()] = reply
285365 reply .downloadProgress .connect (self .downloadProgress )
286366 reply .finished .connect ( lambda : self .saveFile (release ))
367+ return reply .objectName ()
287368
288369 def downloadProgress (self ,bytesReceived :int ,bytesTotal :int ):
370+ """
371+ 用于触发downloadReleaseAsyncProgressSignal信号
372+
373+ :param bytesReceived: 已经下载的字节数
374+ :param bytesTotal: 需要下载的总字节数
375+ """
289376 self .downloadReleaseAsyncProgressSignal .emit (bytesReceived ,bytesTotal )
290377 def saveFile (self ,release :Release ):
378+ """
379+ 从reply中读取数据并根据release.assets_name保存到临时文件夹
380+
381+ :param release: 需要保存的release
382+ :return: None
383+ """
291384 reply :QNetworkReply = self .sender ()
292- if reply .error () != QNetworkReply .NoError :
385+ if reply .error () == QNetworkReply .NetworkError .OperationCanceledError :
386+ pass
387+ elif reply .error () != QNetworkReply .NoError :
293388 self .error (reply .errorString ())
294- return
295- # 临时文件夹
296- tempDir = tempfile .gettempdir ()
297- path = os .path .join (tempDir ,release .assets_name )
298- # 判断是否存在
299- if os .path .exists (path ):
300- os .remove (path )
301- with open (path ,'wb' ) as f :
302- f .write (reply .readAll ())
389+ else :
390+ # 临时文件夹
391+ tempDir = tempfile .gettempdir ()
392+ path = os .path .join (tempDir ,release .assets_name )
393+ # 判断是否存在
394+ if os .path .exists (path ):
395+ os .remove (path )
396+ with open (path ,'wb' ) as f :
397+ f .write (reply .readAll ())
398+ self .downloadReleaseAsyncFinishSignal .emit (path )
399+ self .__replyDict .pop (reply .objectName ())
303400 reply .deleteLater ()
304- self .downloadReleaseAsyncFinishSignal .emit (path )
305-
306401 def compareVersion (self ,v2 ) -> str :
307402 v = re .findall (self .__versionReStr ,self .__version )
308403 if len (v ) == 0 :
@@ -324,8 +419,21 @@ def compareVersion(self,v2) -> str:
324419 def error (self ,errorStr :str ):
325420 self .errorSignal .emit (errorStr )
326421
327-
422+ def closeAllRequest (self ):
423+ """关闭所有的请求"""
424+ keys = list (self .__replyDict .keys ())
425+ for key in keys :
426+ self .__replyDict [key ].abort ()
427+ self .__replyDict .clear ()
428+ def closeRequest (self ,id :str ):
429+ """关闭单个请求
328430
431+ Args:
432+ id (str): 请求的唯一标识
433+ """
434+ if id in self .__replyDict :
435+ self .__replyDict [id ].abort ()
436+ self .__replyDict .pop (id )
329437if __name__ == '__main__' :
330438 app = QCoreApplication ([])
331439 data = {
0 commit comments