diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index a36629be..449308c3 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -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 diff --git a/src/class_objectHashHolder.py b/src/class_objectHashHolder.py index 327656db..e4e2c6d8 100644 --- a/src/class_objectHashHolder.py +++ b/src/class_objectHashHolder.py @@ -47,6 +47,9 @@ 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 diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 322b2390..6adadd44 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -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) diff --git a/src/shared.py b/src/shared.py index 315e5671..6eda2e11 100644 --- a/src/shared.py +++ b/src/shared.py @@ -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