Attempt to terminate threads when pyfa is closed
This commit is contained in:
@@ -99,12 +99,14 @@ class PFPanel(wx.Panel):
|
||||
|
||||
|
||||
class OpenFitsThread(threading.Thread):
|
||||
|
||||
def __init__(self, fits, callback):
|
||||
threading.Thread.__init__(self)
|
||||
self.name = "LoadingOpenFits"
|
||||
self.mainFrame = MainFrame.getInstance()
|
||||
self.callback = callback
|
||||
self.fits = fits
|
||||
self.running = True
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
@@ -118,10 +120,15 @@ class OpenFitsThread(threading.Thread):
|
||||
# We use 1 for all fits except the last one where we use 2 so that we
|
||||
# have correct calculations displayed at startup
|
||||
for fitID in self.fits[:-1]:
|
||||
wx.PostEvent(self.mainFrame, FitSelected(fitID=fitID, startup=1))
|
||||
if self.running:
|
||||
wx.PostEvent(self.mainFrame, FitSelected(fitID=fitID, startup=1))
|
||||
|
||||
wx.PostEvent(self.mainFrame, FitSelected(fitID=self.fits[-1], startup=2))
|
||||
wx.CallAfter(self.callback)
|
||||
if self.running:
|
||||
wx.PostEvent(self.mainFrame, FitSelected(fitID=self.fits[-1], startup=2))
|
||||
wx.CallAfter(self.callback)
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
|
||||
|
||||
# todo: include IPortUser again
|
||||
|
||||
15
pyfa.py
15
pyfa.py
@@ -151,5 +151,18 @@ if __name__ == "__main__":
|
||||
else:
|
||||
pyfa.MainLoop()
|
||||
|
||||
# TODO: Add some thread cleanup code here. Right now we bail, and that can lead to orphaned threads or threads not properly exiting.
|
||||
# When main loop is over, threads have 5 seconds to comply...
|
||||
import threading
|
||||
from utils.timer import CountdownTimer
|
||||
|
||||
timer = CountdownTimer(5)
|
||||
stoppableThreads = []
|
||||
for t in threading.enumerate():
|
||||
if t is not threading.main_thread() and hasattr(t, 'stop'):
|
||||
stoppableThreads.append(t)
|
||||
t.stop()
|
||||
for t in stoppableThreads:
|
||||
t.join(timeout=timer.remainder())
|
||||
|
||||
# Nah, just kidding, no way to terminate threads - just try to exit
|
||||
sys.exit()
|
||||
|
||||
@@ -45,11 +45,13 @@ pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class CharacterImportThread(threading.Thread):
|
||||
|
||||
def __init__(self, paths, callback):
|
||||
threading.Thread.__init__(self)
|
||||
self.name = "CharacterImport"
|
||||
self.paths = paths
|
||||
self.callback = callback
|
||||
self.running = True
|
||||
|
||||
def run(self):
|
||||
paths = self.paths
|
||||
@@ -61,6 +63,8 @@ class CharacterImportThread(threading.Thread):
|
||||
all_skill_ids.append(skill.itemID)
|
||||
|
||||
for path in paths:
|
||||
if not self.running:
|
||||
break
|
||||
try:
|
||||
charFile = open(path, mode='r').read()
|
||||
doc = minidom.parseString(charFile)
|
||||
@@ -95,6 +99,9 @@ class CharacterImportThread(threading.Thread):
|
||||
|
||||
wx.CallAfter(self.callback)
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
|
||||
|
||||
class SkillBackupThread(threading.Thread):
|
||||
def __init__(self, path, saveFmt, activeFit, callback):
|
||||
@@ -104,25 +111,32 @@ class SkillBackupThread(threading.Thread):
|
||||
self.saveFmt = saveFmt
|
||||
self.activeFit = activeFit
|
||||
self.callback = callback
|
||||
self.running = True
|
||||
|
||||
def run(self):
|
||||
path = self.path
|
||||
sCharacter = Character.getInstance()
|
||||
|
||||
if self.saveFmt == "xml" or self.saveFmt == "emp":
|
||||
backupData = sCharacter.exportXml()
|
||||
else:
|
||||
backupData = sCharacter.exportText()
|
||||
backupData = None
|
||||
if self.running:
|
||||
if self.saveFmt == "xml" or self.saveFmt == "emp":
|
||||
backupData = sCharacter.exportXml()
|
||||
else:
|
||||
backupData = sCharacter.exportText()
|
||||
|
||||
if self.saveFmt == "emp":
|
||||
with gzip.open(path, mode='wb') as backupFile:
|
||||
backupFile.write(backupData.encode())
|
||||
else:
|
||||
with open(path, mode='w', encoding='utf-8') as backupFile:
|
||||
backupFile.write(backupData)
|
||||
if self.running and backupData is not None:
|
||||
if self.saveFmt == "emp":
|
||||
with gzip.open(path, mode='wb') as backupFile:
|
||||
backupFile.write(backupData.encode())
|
||||
else:
|
||||
with open(path, mode='w', encoding='utf-8') as backupFile:
|
||||
backupFile.write(backupData)
|
||||
|
||||
wx.CallAfter(self.callback)
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
|
||||
|
||||
class Character:
|
||||
instance = None
|
||||
@@ -474,12 +488,14 @@ class Character:
|
||||
|
||||
|
||||
class UpdateAPIThread(threading.Thread):
|
||||
|
||||
def __init__(self, charID, callback):
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
self.name = "CheckUpdate"
|
||||
self.callback = callback
|
||||
self.charID = charID
|
||||
self.running = True
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
@@ -488,20 +504,31 @@ class UpdateAPIThread(threading.Thread):
|
||||
sEsi = Esi.getInstance()
|
||||
sChar = Character.getInstance()
|
||||
ssoChar = sChar.getSsoCharacter(char.ID)
|
||||
|
||||
if not self.running:
|
||||
self.callback[0](self.callback[1])
|
||||
return
|
||||
resp = sEsi.getSkills(ssoChar.ID)
|
||||
|
||||
if not self.running:
|
||||
self.callback[0](self.callback[1])
|
||||
return
|
||||
# todo: check if alpha. if so, pop up a question if they want to apply it as alpha. Use threading events to set the answer?
|
||||
char.clearSkills()
|
||||
for skillRow in resp["skills"]:
|
||||
char.addSkill(Skill(char, skillRow["skill_id"], skillRow["trained_skill_level"]))
|
||||
|
||||
if not self.running:
|
||||
self.callback[0](self.callback[1])
|
||||
return
|
||||
resp = sEsi.getSecStatus(ssoChar.ID)
|
||||
|
||||
char.secStatus = resp['security_status']
|
||||
|
||||
self.callback[0](self.callback[1])
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as ex:
|
||||
pyfalog.warn(ex)
|
||||
self.callback[0](self.callback[1], sys.exc_info())
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
|
||||
@@ -46,6 +46,7 @@ class ShipBrowserWorkerThread(threading.Thread):
|
||||
threading.Thread.__init__(self)
|
||||
pyfalog.debug("Initialize ShipBrowserWorkerThread.")
|
||||
self.name = "ShipBrowser"
|
||||
self.running = True
|
||||
|
||||
def run(self):
|
||||
self.queue = queue.Queue()
|
||||
@@ -60,6 +61,8 @@ class ShipBrowserWorkerThread(threading.Thread):
|
||||
cache = self.cache
|
||||
sMkt = Market.getInstance()
|
||||
while True:
|
||||
if not self.running:
|
||||
break
|
||||
try:
|
||||
id_, callback = queue.get()
|
||||
set_ = cache.get(id_)
|
||||
@@ -82,6 +85,9 @@ class ShipBrowserWorkerThread(threading.Thread):
|
||||
pyfalog.critical("Queue task done failed.")
|
||||
pyfalog.critical(e)
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
|
||||
|
||||
class SearchWorkerThread(threading.Thread):
|
||||
def __init__(self):
|
||||
@@ -91,6 +97,7 @@ class SearchWorkerThread(threading.Thread):
|
||||
# load the jargon while in an out-of-thread context, to spot any problems while in the main thread
|
||||
self.jargonLoader.get_jargon()
|
||||
self.jargonLoader.get_jargon().apply('test string')
|
||||
self.running = True
|
||||
|
||||
def run(self):
|
||||
self.cv = threading.Condition()
|
||||
@@ -101,6 +108,8 @@ class SearchWorkerThread(threading.Thread):
|
||||
cv = self.cv
|
||||
|
||||
while True:
|
||||
if not self.running:
|
||||
break
|
||||
cv.acquire()
|
||||
while self.searchRequest is None:
|
||||
cv.wait()
|
||||
@@ -161,6 +170,8 @@ class SearchWorkerThread(threading.Thread):
|
||||
self.cv.notify()
|
||||
self.cv.release()
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
|
||||
class Market:
|
||||
instance = None
|
||||
|
||||
@@ -235,11 +235,14 @@ class PriceWorkerThread(threading.Thread):
|
||||
self.name = "PriceWorker"
|
||||
self.queue = queue.Queue()
|
||||
self.wait = {}
|
||||
self.running = True
|
||||
pyfalog.debug("Initialize PriceWorkerThread.")
|
||||
|
||||
def run(self):
|
||||
queue = self.queue
|
||||
while True:
|
||||
if not self.running:
|
||||
break
|
||||
# Grab our data
|
||||
callback, requests, fetchTimeout, validityOverride = queue.get()
|
||||
|
||||
@@ -265,6 +268,9 @@ class PriceWorkerThread(threading.Thread):
|
||||
callbacks = self.wait.setdefault(price.typeID, [])
|
||||
callbacks.append(callback)
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
|
||||
|
||||
# Import market sources only to initialize price source modules, they register on their own
|
||||
from service.marketSources import evemarketer, evemarketdata, evepraisal # noqa: E402
|
||||
|
||||
@@ -41,6 +41,7 @@ class CheckUpdateThread(threading.Thread):
|
||||
self.callback = callback
|
||||
self.settings = UpdateSettings.getInstance()
|
||||
self.network = Network.getInstance()
|
||||
self.running = True
|
||||
|
||||
def run(self):
|
||||
network = Network.getInstance()
|
||||
@@ -49,13 +50,13 @@ class CheckUpdateThread(threading.Thread):
|
||||
try:
|
||||
response = network.get(
|
||||
url='https://www.pyfa.io/update_check?pyfa_version={}&client_hash={}'.format(config.version, config.getClientSecret()),
|
||||
type=network.UPDATE)
|
||||
type=network.UPDATE, timeout=5)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as e:
|
||||
response = network.get(
|
||||
url='https://api.github.com/repos/pyfa-org/Pyfa/releases',
|
||||
type=network.UPDATE)
|
||||
type=network.UPDATE, timeout=5)
|
||||
|
||||
jsonResponse = response.json()
|
||||
jsonResponse.sort(
|
||||
@@ -94,6 +95,9 @@ class CheckUpdateThread(threading.Thread):
|
||||
def versiontuple(v):
|
||||
return tuple(map(int, (v.split("."))))
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
|
||||
|
||||
class Update:
|
||||
instance = None
|
||||
|
||||
@@ -35,3 +35,16 @@ class Timer:
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.checkpoint('finished')
|
||||
pass
|
||||
|
||||
|
||||
class CountdownTimer:
|
||||
|
||||
def __init__(self, timeout):
|
||||
self.timeout = timeout
|
||||
self.start = time.time()
|
||||
|
||||
def elapsed(self):
|
||||
return time.time() - self.start
|
||||
|
||||
def remainder(self):
|
||||
return max(self.timeout - self.elapsed(), 0)
|
||||
|
||||
Reference in New Issue
Block a user