GUI shutdown improvements

- it shows that it needs to wait for PoW to finish
- it waits a bit for new objects to be distributed
- it displays a better progress indicator in the status bar

Previously, people who don't understand how PyBitmessage works sometimes
shut it down immediately after they wrote a message. This would have
caused the message to be stuck in the queue locally and not sent. Now,
it will indicate that the PoW still needs to work, and it will wait a
bit longer so that the message can spread. It's not a completely correct
approach, because it does not know whether the message was really
retrieved after the "inv" notification was sent.
This commit is contained in:
mailchuck 2016-04-20 15:33:01 +02:00 committed by Peter Surda
parent 167da731d0
commit 3dbb4d5ce9
4 changed files with 74 additions and 6 deletions

View File

@ -67,6 +67,8 @@ from utils import *
from collections import OrderedDict
from account import *
from dialogs import AddAddressDialog
from class_objectHashHolder import objectHashHolder
from class_singleWorker import singleWorker
def _translate(context, text):
return QtGui.QApplication.translate(context, text)
@ -2644,7 +2646,64 @@ class MyForm(settingsmixin.SMainWindow):
if reply is QtGui.QMessageBox.No:
return
'''
self.statusBar().showMessage(_translate(
"MainWindow", "Shutting down PyBitmessage... %1%%").arg(str(0)))
# check if PoW queue empty
maxWorkerQueue = 0
curWorkerQueue = 1
while curWorkerQueue > 0:
# worker queue size
curWorkerQueue = shared.workerQueue.qsize()
# if worker is busy add 1
for thread in threading.enumerate():
try:
if isinstance(thread, singleWorker):
curWorkerQueue += thread.busy
except:
pass
if curWorkerQueue > maxWorkerQueue:
maxWorkerQueue = curWorkerQueue
if curWorkerQueue > 0:
self.statusBar().showMessage(_translate("MainWindow", "Waiting for PoW to finish... %1%").arg(str(50 * (maxWorkerQueue - curWorkerQueue) / maxWorkerQueue)))
time.sleep(0.5)
QtCore.QCoreApplication.processEvents()
self.statusBar().showMessage(_translate("MainWindow", "Shutting down Pybitmessage... %1%").arg(str(50)))
QtCore.QCoreApplication.processEvents()
if maxWorkerQueue > 0:
time.sleep(0.5) # a bit of time so that the hashHolder is populated
QtCore.QCoreApplication.processEvents()
# check if objectHashHolder empty
self.statusBar().showMessage(_translate("MainWindow", "Waiting for objects to be sent... %1%").arg(str(50)))
maxWaitingObjects = 0
curWaitingObjects = 1
while curWaitingObjects > 0:
curWaitingObjects = 0
for thread in threading.enumerate():
try:
if isinstance(thread, objectHashHolder):
curWaitingObjects += thread.hashCount()
except:
pass
if curWaitingObjects > maxWaitingObjects:
maxWaitingObjects = curWaitingObjects
if curWaitingObjects > 0:
self.statusBar().showMessage(_translate("MainWindow", "Waiting for objects to be sent... %1%").arg(str(50 + 20 * (maxWaitingObjects - curWaitingObjects) / maxWaitingObjects)))
time.sleep(0.5)
QtCore.QCoreApplication.processEvents()
QtCore.QCoreApplication.processEvents()
if maxWorkerQueue > 0 or maxWaitingObjects > 0:
time.sleep(10) # a bit of time so that the other nodes retrieve the objects
QtCore.QCoreApplication.processEvents()
# save state and geometry self and all widgets
self.statusBar().showMessage(_translate("MainWindow", "Saving settings... %1%").arg(str(70)))
QtCore.QCoreApplication.processEvents()
self.saveSettings()
for attr, obj in self.ui.__dict__.iteritems():
if hasattr(obj, "__class__") and isinstance(obj, settingsmixin.SettingsMixin):
@ -2652,19 +2711,20 @@ class MyForm(settingsmixin.SMainWindow):
if callable (saveMethod):
obj.saveSettings()
self.statusBar().showMessage(_translate("MainWindow", "Shutting down core... %1%").arg(str(80)))
QtCore.QCoreApplication.processEvents()
shared.doCleanShutdown()
self.statusBar().showMessage(_translate("MainWindow", "Stopping notifications... %1%").arg(str(90)))
QtCore.QCoreApplication.processEvents()
self.tray.hide()
# unregister the messaging system
if self.mmapp is not None:
self.mmapp.unregister()
# settings = QSettings("Bitmessage", "PyBitmessage")
# settings.setValue("geometry", self.saveGeometry())
# settings.setValue("state", self.saveState())
self.statusBar().showMessage(_translate(
"MainWindow", "All done. Closing user interface..."))
self.statusBar().showMessage(_translate("MainWindow", "Shutdown imminent... %1%").arg(str(100)))
QtCore.QCoreApplication.processEvents()
shared.thisapp.cleanup()
logger.info("Shutdown complete")
os._exit(0)
# window close event

View File

@ -48,5 +48,8 @@ class objectHashHolder(threading.Thread):
def holdPeer(self,peerDetails):
self.collectionOfPeerLists[random.randrange(0, self.size)].append(peerDetails)
def hashCount(self):
return sum([len(x) for x in self.collectionOfHashLists])
def close(self):
self.shutdown = True

View File

@ -87,7 +87,9 @@ class singleWorker(threading.Thread, StoppableThread):
self.sendBroadcast()
while shared.shutdown == 0:
self.busy = 0
command, data = shared.workerQueue.get()
self.busy = 1
if command == 'sendmessage':
try:
self.sendMsg()
@ -114,6 +116,7 @@ class singleWorker(threading.Thread, StoppableThread):
except:
pass
elif command == 'stopThread':
self.busy = 0
return
else:
logger.error('Probable programming error: The command sent to the workerThread is weird. It is: %s\n' % command)

View File

@ -522,6 +522,8 @@ def doCleanShutdown():
logger.info('Clean shutdown complete.')
thisapp.cleanup()
os._exit(0)
else:
logger.info('Core shutdown complete.')
# If you want to command all of the sendDataThreads to do something, like shutdown or send some data, this
# function puts your data into the queues for each of the sendDataThreads. The sendDataThreads are