Cancel Senging Message Feature
This commit is contained in:
parent
e423343e9a
commit
554b4f8cce
|
@ -390,6 +390,12 @@ class MyForm(QtGui.QMainWindow):
|
|||
_translate(
|
||||
"MainWindow", "Copy destination address to clipboard"),
|
||||
self.on_action_SentClipboard)
|
||||
self.actionCancelPoW = self.ui.sentContextMenuToolbar.addAction(
|
||||
_translate(
|
||||
"MainWindow", "Cancel sending"), self.on_action_CancelPoW)
|
||||
self.actionContinuePoW = self.ui.sentContextMenuToolbar.addAction(
|
||||
_translate(
|
||||
"MainWindow", "Continue sending"), self.on_action_ContinuePoW)
|
||||
self.actionForceSend = self.ui.sentContextMenuToolbar.addAction(
|
||||
_translate(
|
||||
"MainWindow", "Force send"), self.on_action_ForceSend)
|
||||
|
@ -849,6 +855,9 @@ class MyForm(QtGui.QMainWindow):
|
|||
elif status == 'toodifficult':
|
||||
statusText = _translate("MainWindow", "Problem: The work demanded by the recipient is more difficult than you are willing to do. %1").arg(
|
||||
unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(lastactiontime)),'utf-8'))
|
||||
elif status == 'PoW_Cancelled':
|
||||
statusText = _translate("MainWindow", "Problem: The sending was cancelled. %1").arg(
|
||||
unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(lastactiontime)),'utf-8'))
|
||||
elif status == 'badkey':
|
||||
statusText = _translate("MainWindow", "Problem: The recipient\'s encryption key is no good. Could not encrypt message. %1").arg(
|
||||
unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(lastactiontime)),'utf-8'))
|
||||
|
@ -2718,6 +2727,31 @@ class MyForm(QtGui.QMainWindow):
|
|||
clipboard = QtGui.QApplication.clipboard()
|
||||
clipboard.setText(str(addressAtCurrentRow))
|
||||
|
||||
def on_action_CancelPoW(self):
|
||||
#The user wants to cancel the sending
|
||||
if shared.PoWQueue.empty() == True: #The PoW calculation finished
|
||||
QMessageBox.about(self, _translate("MainWindow", "PoW Finished"), _translate(
|
||||
"MainWindow", "The message has already been sent!"))
|
||||
else: #The PoW calculation is still in progress
|
||||
if shared.PoWQueue.get() == 'PoW_Single_Thread': #It is the single threaded version
|
||||
QMessageBox.about(self, _translate("MainWindow", "PoW Cancelled"), _translate(
|
||||
"MainWindow", "The sending was cancelled!"))
|
||||
else: #The multi threaded version is different, because of the possible overhead of the termination of the threads.
|
||||
QMessageBox.about(self, _translate("MainWindow", "PoW Cancellation"), _translate(
|
||||
"MainWindow", "The cancellation of sending can take up to a few seconds because of the multi-threaded environment. If the message is not be sent during this period it will be cancelled!"))
|
||||
time.sleep(0.2) # We need to give some time to the PoW process to terminate and change the status of the message
|
||||
self.loadSent()
|
||||
|
||||
def on_action_ContinuePoW(self):
|
||||
#Continue sending of a message if it was cancelled by the user
|
||||
currentRow = self.ui.tableWidgetSent.selectedIndexes()[0].row()
|
||||
ackdataToContinue = str(self.ui.tableWidgetSent.item(
|
||||
currentRow, 3).data(Qt.UserRole).toPyObject())
|
||||
sqlExecute('''UPDATE sent SET status='msgqueued' WHERE status='PoW_Cancelled' AND ackdata=?''', ackdataToContinue)
|
||||
self.statusBar().showMessage(_translate(
|
||||
"MainWindow", "The sending will be continued."))
|
||||
shared.workerQueue.put(('sendmessage', ''))
|
||||
|
||||
# Group of functions for the Address Book dialog box
|
||||
def on_action_AddressBookNew(self):
|
||||
self.click_pushButtonAddAddressBook()
|
||||
|
@ -3060,6 +3094,12 @@ class MyForm(QtGui.QMainWindow):
|
|||
status, = row
|
||||
if status == 'toodifficult':
|
||||
self.popMenuSent.addAction(self.actionForceSend)
|
||||
if status == 'PoW_Cancelled':
|
||||
self.popMenuSent.addSeparator()
|
||||
self.popMenuSent.addAction(self.actionContinuePoW)
|
||||
if (status == 'doingmsgpow') and (shared.PoWQueue.empty() == False): #The PoW of a message is calculating
|
||||
self.popMenuSent.addSeparator()
|
||||
self.popMenuSent.addAction(self.actionCancelPoW)
|
||||
self.popMenuSent.exec_(self.ui.tableWidgetSent.mapToGlobal(point))
|
||||
|
||||
def inboxSearchLineEditPressed(self):
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#import shared
|
||||
import shared
|
||||
#import time
|
||||
#from multiprocessing import Pool, cpu_count
|
||||
import hashlib
|
||||
|
@ -30,16 +30,19 @@ def _pool_worker(nonce, initialHash, target, pool_size):
|
|||
trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8])
|
||||
return [trialValue, nonce]
|
||||
|
||||
def _doSafePoW(target, initialHash):
|
||||
def _doSafePoW(target, initialHash, cancellable):
|
||||
nonce = 0
|
||||
trialValue = float('inf')
|
||||
while trialValue > target:
|
||||
if (shared.PoWQueue.empty() == True) and cancellable: #If the PoW is cancellable it can be interrupted
|
||||
return [-1,-1] #Special value for differentiation
|
||||
nonce += 1
|
||||
trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8])
|
||||
|
||||
if cancellable: shared.PoWQueue.get() #If the PoW is cancellable we need to communicate its end to the UI
|
||||
return [trialValue, nonce]
|
||||
|
||||
def _doFastPoW(target, initialHash):
|
||||
import shared
|
||||
def _doFastPoW(target, initialHash, cancellable):
|
||||
import time
|
||||
from multiprocessing import Pool, cpu_count
|
||||
try:
|
||||
|
@ -62,16 +65,33 @@ def _doFastPoW(target, initialHash):
|
|||
while True:
|
||||
time.sleep(10) # Don't let this thread return here; it will return nothing and cause an exception in bitmessagemain.py
|
||||
return
|
||||
if (shared.PoWQueue.empty() == True) and cancellable: #If the PoW is cancellable it can be interrupted
|
||||
pool.terminate()
|
||||
pool.join() #Wait for the workers to exit...
|
||||
return [-1, -1] #Special value for differentiation
|
||||
for i in range(pool_size):
|
||||
if result[i].ready():
|
||||
result = result[i].get()
|
||||
pool.terminate()
|
||||
pool.join() #Wait for the workers to exit...
|
||||
return result[0], result[1]
|
||||
if cancellable: shared.PoWQueue.get() #If the PoW is cancellable we need to communicate its end to the UI
|
||||
return result[0], result[1]
|
||||
time.sleep(0.2)
|
||||
|
||||
def run(target, initialHash):
|
||||
def run(target, initialHash, cancellable):
|
||||
import time
|
||||
#Only message PoW calculations are cancellable, Key requests are not.
|
||||
if cancellable:
|
||||
#If the PoW is cancellable we need to communicate its beginning to the UI
|
||||
if frozen == "macosx_app" or not frozen:
|
||||
shared.PoWQueue.put('PoW_Single_Thread')
|
||||
else:
|
||||
shared.PoWQueue.put('PoW_Multi_Thread')
|
||||
while shared.PoWQueue.empty() == True: #Necessary to wait because of the interprocess/interthread communication
|
||||
time.sleep(0.1)
|
||||
|
||||
if frozen == "macosx_app" or not frozen:
|
||||
return _doFastPoW(target, initialHash)
|
||||
return _doFastPoW(target, initialHash, cancellable)
|
||||
else:
|
||||
return _doSafePoW(target, initialHash)
|
||||
return _doSafePoW(target, initialHash, cancellable)
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import ConfigParser
|
|||
import os
|
||||
import pickle
|
||||
import Queue
|
||||
from multiprocessing import Queue as MQueue #A Multiproccessing Queue is necessary for the PoW cancellation.
|
||||
import random
|
||||
import socket
|
||||
import sys
|
||||
|
@ -39,6 +40,7 @@ broadcastSendersForWhichImWatching = {}
|
|||
workerQueue = Queue.Queue()
|
||||
UISignalQueue = Queue.Queue()
|
||||
addressGeneratorQueue = Queue.Queue()
|
||||
PoWQueue = MQueue() #Multithreaded queue for interprocess communication. It is used for the PoW calculation
|
||||
knownNodesLock = threading.Lock()
|
||||
knownNodes = {}
|
||||
sendDataQueues = [] #each sendData thread puts its queue in this list.
|
||||
|
|
Reference in New Issue
Block a user