1
0
Fork 0
mirror of synced 2024-05-18 11:32:50 +12:00

Add stop download button (#33)

Add stop download button
Not a perfect solution, but it should work
This commit is contained in:
ChemicalXandco 2021-04-11 16:03:55 +01:00 committed by GitHub
parent 5d23eae990
commit da8ef8dab8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 80 additions and 23 deletions

View file

@ -50,9 +50,9 @@ class DownloadTab(QWidget):
self.mini_layout.addWidget(self.prog_bar)
self.kill_button = QPushButton(self.tr("Stop Download"))
# self.mini_layout.addWidget(self.kill_button)
self.kill_button.setDisabled(True)
self.kill_button.clicked.connect(self.stop_download)
self.mini_layout.addWidget(self.kill_button)
self.layout.addLayout(self.mini_layout)
@ -85,7 +85,7 @@ class DownloadTab(QWidget):
self.dl_queue = dl_queue
def stop_download(self):
self.thread.kill = True
self.thread.kill()
def install_game(self, options: InstallOptions):
@ -227,11 +227,12 @@ class DownloadTab(QWidget):
else:
self.queue_widget.update_queue(self.dl_queue)
elif text == "error":
QMessageBox.warning(self, "warn", "Download error")
elif text[:5] == "error":
QMessageBox.warning(self, "warn", "Download error: "+text[6:])
elif text == "stop":
self.reset_infos()
self.active_game = None
def reset_infos(self):
self.kill_button.setDisabled(True)

View file

@ -1,18 +1,19 @@
import os
import queue
import subprocess
import sys
import time
from logging import getLogger
from multiprocessing import Queue as MPQueue
from queue import Empty
import psutil
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QMessageBox
from rare.utils.models import KillDownloadException
from custom_legendary.core import LegendaryCore
from custom_legendary.downloader.manager import DLManager
from custom_legendary.models.downloading import UIUpdate
from custom_legendary.models.downloading import UIUpdate, WriterTask
logger = getLogger("Download")
@ -20,7 +21,6 @@ logger = getLogger("Download")
class DownloadThread(QThread):
status = pyqtSignal(str)
statistics = pyqtSignal(UIUpdate)
kill = False
def __init__(self, dlm: DLManager, core: LegendaryCore, status_queue: MPQueue, igame, repair=False,
repair_file=None):
@ -31,37 +31,92 @@ class DownloadThread(QThread):
self.igame = igame
self.repair = repair
self.repair_file = repair_file
self._kill = False
def run(self):
start_time = time.time()
dl_stopped = False
try:
self.dlm.start()
time.sleep(1)
while self.dlm.is_alive():
if self.kill:
# raise KillDownloadException()
# TODO kill download queue, workers
pass
if self._kill:
self.status.emit("stop")
logger.info("Download stopping...")
# The code below is a temporary solution.
# It should be removed once legendary supports stopping downloads more gracefully.
self.dlm.running = False
# send conditions to unlock threads if they aren't already
for cond in self.dlm.conditions:
with cond:
cond.notify()
# make sure threads are dead.
for t in self.dlm.threads:
t.join(timeout=5.0)
if t.is_alive():
logger.warning(f'Thread did not terminate! {repr(t)}')
# clean up all the queues, otherwise this process won't terminate properly
for name, q in zip(('Download jobs', 'Writer jobs', 'Download results', 'Writer results'),
(self.dlm.dl_worker_queue, self.dlm.writer_queue, self.dlm.dl_result_q, self.dlm.writer_result_q)):
logger.debug(f'Cleaning up queue "{name}"')
try:
while True:
_ = q.get_nowait()
except Empty:
q.close()
q.join_thread()
except AttributeError:
logger.warning(f'Queue {name} did not close')
if self.dlm.writer_queue:
# cancel installation
self.dlm.writer_queue.put_nowait(WriterTask('', kill=True))
# forcibly kill DL workers that are not actually dead yet
for child in self.dlm.children:
if child.exitcode is None:
child.terminate()
if self.dlm.shared_memory:
# close up shared memory
self.dlm.shared_memory.close()
self.dlm.shared_memory.unlink()
self.dlm.shared_memory = None
self.dlm.kill()
# force kill any threads that are somehow still alive
for proc in psutil.process_iter():
# check whether the process name matches
if sys.platform in ['linux', 'darwin'] and proc.name() == 'DownloadThread':
proc.kill()
elif sys.platform == 'win32' and proc.name() == 'python.exe' and proc.create_time() >= start_time:
proc.kill()
logger.info("Download stopped. It can be continued later.")
dl_stopped = True
try:
self.statistics.emit(self.status_queue.get(timeout=1))
if not dl_stopped:
self.statistics.emit(self.status_queue.get(timeout=1))
except queue.Empty:
pass
self.dlm.join()
except KillDownloadException:
self.status.emit("stop")
logger.info("Downlaod can be continued later")
self.dlm.kill()
return
except Exception as e:
logger.error(f"Installation failed after {time.time() - start_time:.02f} seconds: {e}")
self.status.emit("error")
self.status.emit("error "+str(e))
return
else:
if dl_stopped:
return
self.status.emit("dl_finished")
end_t = time.time()
@ -115,3 +170,6 @@ class DownloadThread(QThread):
else:
logger.info('Automatic installation not available on Linux.')
def kill(self):
self._kill = True

View file

@ -13,6 +13,3 @@ class InstallOptions:
self.ignore_free_space = ignore_free_space
self.force = force
class KillDownloadException(Exception):
pass

View file

@ -3,3 +3,4 @@ Pillow
PyQt5
QtAwesome
notify-py
psutil