Skip to content
Snippets Groups Projects
Commit 5c6df81b authored by inso's avatar inso
Browse files

Using quamash, asyncio and coroutines

Now, waiting for signals is way easier.
parent e9275a9e
Branches
Tags
No related merge requests found
from .community import Community
from .wallet import Wallet
from .account import Account
\ No newline at end of file
......@@ -12,6 +12,7 @@ import logging
import time
import math
import json
import asyncio
from PyQt5.QtCore import QObject, pyqtSignal, QCoreApplication, QT_TRANSLATE_NOOP
from PyQt5.QtNetwork import QNetworkReply
......@@ -121,7 +122,9 @@ class Account(QObject):
loading_progressed = pyqtSignal(int, int)
inner_data_changed = pyqtSignal(str)
wallets_changed = pyqtSignal()
document_broadcasted = pyqtSignal(str)
membership_broadcasted = pyqtSignal()
certification_broadcasted = pyqtSignal()
broadcast_error = pyqtSignal(int, str)
def __init__(self, salt, pubkey, name, communities, wallets, contacts, identities_registry):
'''
......@@ -312,6 +315,7 @@ class Account(QObject):
self.wallets = self.wallets[:size]
self.wallets_changed.emit()
@asyncio.coroutine
def certify(self, password, community, pubkey):
"""
Certify an other identity
......@@ -320,26 +324,76 @@ class Account(QObject):
:param cutecoin.core.community.Community community: The community target of the certification
:param str pubkey: The certified identity pubkey
"""
certified = self._identities_registry.lookup(pubkey, community)
blockid = community.current_blockid()
blockid = ""
selfcert = None
def build_certification_data(reply):
if reply.error() == QNetworkReply.NoError:
strdata = bytes(reply.readAll()).decode('utf-8')
json_data = json.loads(strdata)
nonlocal blockid
blockid = community.blockid(json_data)
future_certdata.set_result(True)
def build_certification_selfcert(reply):
if reply.error() == QNetworkReply.NoError:
strdata = bytes(reply.readAll()).decode('utf-8')
json_data = json.loads(strdata)
nonlocal selfcert
selfcert = self._identities_registry.lookup(pubkey, community).selfcert(community, json_data)
future_selfcert.set_result(True)
future_certdata = asyncio.Future()
reply = community.bma_access.request(qtbma.blockchain.Current)
reply.finished.connect(lambda: build_certification_data(reply))
yield from future_certdata
future_selfcert = asyncio.Future()
reply = community.bma_access.request( qtbma.wot.Lookup, req_args={'search': pubkey})
reply.finished.connect(lambda: build_certification_selfcert(reply))
yield from future_selfcert
certification = Certification(PROTOCOL_VERSION, community.currency,
self.pubkey, certified.pubkey,
self.pubkey, pubkey,
blockid['number'], blockid['hash'], None)
selfcert = certified.selfcert(community)
logging.debug("SelfCertification : {0}".format(selfcert.raw()))
key = SigningKey(self.salt, password)
certification.sign(selfcert, [key])
signed_cert = certification.signed_raw(selfcert)
logging.debug("Certification : {0}".format(signed_cert))
data = {'pubkey': certified.pubkey,
data = {'pubkey': pubkey,
'self_': selfcert.signed_raw(),
'other': "{0}\n".format(certification.inline())}
logging.debug("Posted data : {0}".format(data))
community.broadcast(qtbma.wot.Add, {}, data)
replies = community.bma_access.broadcast(qtbma.wot.Add, {}, data)
for r in replies:
r.finished.connect(lambda reply=r: self.__handle_certification_reply(replies, reply))
def __handle_certification_reply(self, replies, reply):
"""
Handle the reply, if the request was accepted, disconnect
all other replies
:param QNetworkReply reply: The reply of this handler
:param list of QNetworkReply replies: All request replies
:return:
"""
strdata = bytes(reply.readAll()).decode('utf-8')
logging.debug("Received reply : {0} : {1}".format(reply.error(), strdata))
if reply.error() == QNetworkReply.NoError:
self.certification_broadcasted.emit()
for r in replies:
try:
r.disconnect()
except TypeError as e:
if "disconnect()" in str(e):
logging.debug("Could not disconnect a reply")
else:
for r in replies:
if not r.isFinished() or r.error() == QNetworkReply.NoError:
return
self.broadcast_error.emit(r.error(), strdata)
def revoke(self, password, community):
"""
......@@ -351,7 +405,6 @@ class Account(QObject):
revoked = self._identities_registry.lookup(self.pubkey, community)
revocation = Revocation(PROTOCOL_VERSION, community.currency, None)
selfcert = revoked.selfcert(community)
key = SigningKey(self.salt, password)
......@@ -414,32 +467,50 @@ class Account(QObject):
'self_': selfcert.signed_raw(),
'other': []})
@asyncio.coroutine
def send_membership(self, password, community, mstype):
'''
Send a membership document to a target community
Send a membership document to a target community.
Signal "document_broadcasted" is emitted at the end.
:param str password: The account SigningKey password
:param community: The community target of the membership document
:param str mstype: The type of membership demand. "IN" to join, "OUT" to leave
'''
reply = community.bma_access.request(qtbma.blockchain.Current)
reply.finished.connect(lambda: self.__build_membership_data(password, community, mstype, reply))
blockid = ""
selfcert = None
logging.debug("Send membership")
def __build_membership_data(self, password, community, mstype, reply):
def build_membership_data(reply):
if reply.error() == QNetworkReply.NoError:
strdata = bytes(reply.readAll()).decode('utf-8')
json_data = json.loads(strdata)
nonlocal blockid
blockid = community.blockid(json_data)
reply = community.bma_access.request( qtbma.wot.Lookup, req_args={'search': self.pubkey})
reply.finished.connect(lambda: self.__broadcast_membership(community, blockid, mstype, password, reply))
future_msdata.set_result(True)
else:
raise ConnectionError(self.tr("Failed to get data build membership document"))
def __broadcast_membership(self, community, blockid, mstype, password, reply):
def build_selfcert(reply):
if reply.error() == QNetworkReply.NoError:
strdata = bytes(reply.readAll()).decode('utf-8')
json_data = json.loads(strdata)
nonlocal selfcert
selfcert = self.identity(community).selfcert(community, json_data)
future_selfcert.set_result(True)
else:
raise ConnectionError(self.tr("Failed to get data build membership document"))
future_msdata = asyncio.Future()
reply = community.bma_access.request(qtbma.blockchain.Current)
reply.finished.connect(lambda: build_membership_data(reply))
logging.debug("msdata")
yield from future_msdata
future_selfcert = asyncio.Future()
reply = community.bma_access.request( qtbma.wot.Lookup, req_args={'search': self.pubkey})
reply.finished.connect(lambda: build_selfcert(reply))
logging.debug("selfcert")
yield from future_selfcert
membership = Membership(PROTOCOL_VERSION, community.currency,
selfcert.pubkey, blockid['number'],
blockid['hash'], mstype, selfcert.uid,
......@@ -450,11 +521,9 @@ class Account(QObject):
replies = community.bma_access.broadcast(qtbma.blockchain.Membership, {},
{'membership': membership.signed_raw()})
for r in replies:
r.finished.connect(lambda reply=r: self.__handle_broadcast_replies(replies, reply))
else:
raise ConnectionError(self.tr("Failed to get data build membership document"))
r.finished.connect(lambda reply=r: self.__handle_membership_replies(replies, reply))
def __handle_broadcast_replies(self, replies, reply):
def __handle_membership_replies(self, replies, reply):
"""
Handle the reply, if the request was accepted, disconnect
all other replies
......@@ -463,14 +532,21 @@ class Account(QObject):
:param list of QNetworkReply replies: All request replies
:return:
"""
strdata = bytes(reply.readAll()).decode('utf-8')
logging.debug("Received reply : {0} : {1}".format(reply.error(), strdata))
if reply.error() == QNetworkReply.NoError:
self.document_broadcasted.emit("Membership")
self.membership_broadcasted.emit()
for r in replies:
try:
r.disconnect()
except TypeError as e:
if "disconnect()" in str(e):
logging.debug("Could not disconnect a reply")
else:
for r in replies:
if not r.isFinished() or r.error() == QNetworkReply.NoError:
return
self.broadcast_error.emit(r.error(), strdata)
def jsonify(self):
'''
......@@ -493,7 +569,3 @@ class Account(QObject):
'wallets': data_wallets,
'contacts': self.contacts}
return data
def get_person(self):
return Person.from_metadata({'text': self.name,
'id': self.pubkey})
......@@ -43,6 +43,7 @@ class Application(QObject):
super().__init__()
self.accounts = {}
self.current_account = None
self.qapp = qapp
self.available_version = (True,
__version__,
"")
......@@ -215,7 +216,7 @@ class Application(QObject):
for wallet in account.wallets:
wallet_path = os.path.join(config.parameters['home'],
account.name, '__cache__', wallet.pubkey)
account.name, '__cache__', wallet.pubkey + "_wal")
if os.path.exists(wallet_path):
with open(wallet_path, 'r') as json_data:
data = json.load(json_data)
......
......@@ -53,6 +53,7 @@ class IdentitiesRegistry:
:return: A new person if the pubkey was unknown or\
the known instance if pubkey was already known.
:rtype: cutecoin.core.registry.Identity
"""
if pubkey in self._instances:
identity = self._instances[pubkey]
......
......@@ -4,8 +4,8 @@ Created on 24 dec. 2014
@author: inso
'''
from PyQt5.QtWidgets import QDialog, QMessageBox, QDialogButtonBox, QApplication
from PyQt5.QtCore import Qt
from ..tools.exceptions import NoPeerAvailable
from PyQt5.QtCore import Qt, pyqtSlot
import quamash
from ..gen_resources.certification_uic import Ui_CertificationDialog
from . import toast
......@@ -16,12 +16,13 @@ class CertificationDialog(QDialog, Ui_CertificationDialog):
classdocs
'''
def __init__(self, certifier, password_asker):
def __init__(self, certifier, app, password_asker):
'''
Constructor
'''
super().__init__()
self.setupUi(self)
self.app = app
self.account = certifier
self.password_asker = password_asker
self.community = self.account.communities[0]
......@@ -43,30 +44,19 @@ class CertificationDialog(QDialog, Ui_CertificationDialog):
if password == "":
return
try:
QApplication.setOverrideCursor(Qt.WaitCursor)
self.account.certify(password, self.community, pubkey)
self.account.certification_broadcasted.connect(lambda: self.certification_sent(self.community,
pubkey))
self.account.broadcast_error.connect(self.handle_error)
with quamash.QEventLoop(self.app.qapp) as loop:
loop.run_until_complete(self.account.certify(password, self.community, pubkey))
def certification_sent(self, pubkey, currency):
toast.display(self.tr("Certification"),
self.tr("Success certifying {0} from {1}").format(pubkey,
self.community.currency))
except ValueError as e:
QMessageBox.critical(self, self.tr("Certification"),
self.tr("Something wrong happened : {0}").format(e),
QMessageBox.Ok)
return
except NoPeerAvailable as e:
QMessageBox.critical(self, self.tr("Certification"),
self.tr("Couldn't connect to network : {0}").format(e),
QMessageBox.Ok)
return
except Exception as e:
QMessageBox.critical(self, self.tr("Error"),
"{0}".format(e),
QMessageBox.Ok)
return
finally:
self.tr("Success certifying {0} from {1}").format(pubkey, currency))
self.account.certification_broadcasted.disconnect()
QApplication.restoreOverrideCursor()
super().accept()
def change_current_community(self, index):
......@@ -78,6 +68,13 @@ class CertificationDialog(QDialog, Ui_CertificationDialog):
self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
self.button_box.button(QDialogButtonBox.Ok).setText(self.tr("Not a member"))
@pyqtSlot(int, str)
def handle_error(self, error_code, text):
toast.display(self.tr("Error"), self.tr("{0} : {1}".format(error_code, text)))
self.account.certification_broadcasted.disconnect()
self.account.broadcast_error.disconnect(self.handle_error)
QApplication.restoreOverrideCursor()
def recipient_mode_changed(self, pubkey_toggled):
self.edit_pubkey.setEnabled(pubkey_toggled)
self.combo_contact.setEnabled(not pubkey_toggled)
......@@ -17,6 +17,7 @@ from .wot_tab import WotTabWidget
from .transfer import TransferMoneyDialog
from .certification import CertificationDialog
from . import toast
import quamash
from ..tools.exceptions import LookupFailureError, NoPeerAvailable
from ..core.registry import IdentitiesRegistry
from ucoinpy.api import bma
......@@ -68,8 +69,7 @@ class CommunityTabWidget(QWidget, Ui_CommunityTabWidget):
self.account.identity(self.community).inner_data_changed.connect(self.handle_account_identity_change)
self.search_direct_connections()
self.account.document_broadcasted.connect(self.display_broadcast_toast)
self.account.membership_broadcasted.connect(self.display_membership_toast)
self.refresh_quality_buttons()
def identity_context_menu(self, point):
......@@ -152,10 +152,10 @@ class CommunityTabWidget(QWidget, Ui_CommunityTabWidget):
currency_tab = self.window().currencies_tabwidget.currentWidget()
currency_tab.tab_history.table_history.model().sourceModel().refresh_transfers()
def certify_identity(self, person):
dialog = CertificationDialog(self.account, self.password_asker)
def certify_identity(self, identity):
dialog = CertificationDialog(self.account, self.app, self.password_asker)
dialog.combo_community.setCurrentText(self.community.name)
dialog.edit_pubkey.setText(person.pubkey)
dialog.edit_pubkey.setText(identity.pubkey)
dialog.radio_pubkey.setChecked(True)
dialog.exec_()
......@@ -169,28 +169,16 @@ class CommunityTabWidget(QWidget, Ui_CommunityTabWidget):
index_wot_tab = self.tabs_information.indexOf(self.wot_tab)
self.tabs_information.setCurrentIndex(index_wot_tab)
@pyqtSlot(str)
def display_broadcast_toast(self, document):
toast.display(document, self.tr("Success sending {0} demand".format(document)))
@pyqtSlot()
def display_membership_toast(self):
toast.display(self.tr("Membership"), self.tr("Success sending Membership demand"))
def send_membership_demand(self):
password = self.password_asker.exec_()
if self.password_asker.result() == QDialog.Rejected:
return
try:
self.account.send_membership(password, self.community, 'IN')
except ValueError as e:
QMessageBox.critical(self, self.tr("Join demand error"),
str(e))
except LookupFailureError as e:
QMessageBox.critical(self, self.tr("Key not sent to community"),
self.tr(""""Your key wasn't sent in the community.
You can't request a membership."""))
except NoPeerAvailable as e:
QMessageBox.critical(self, self.tr("Network error"),
self.tr("Couldn't connect to network : {0}").format(e),
QMessageBox.Ok)
with quamash.QEventLoop(self.app.qapp) as loop:
loop.run_until_complete(self.account.send_membership(password, self.community, 'IN'))
# except Exception as e:
# QMessageBox.critical(self, "Error",
# "{0}".format(e),
......@@ -207,19 +195,8 @@ The process to join back the community later will have to be done again.""")
if self.password_asker.result() == QDialog.Rejected:
return
try:
self.account.send_membership(password, self.community, 'OUT')
except ValueError as e:
QMessageBox.critical(self, self.tr("Leaving demand error"),
str(e))
except NoPeerAvailable as e:
QMessageBox.critical(self, self.tr("Network error"),
self.tr("Couldn't connect to network : {0}").format(e),
QMessageBox.Ok)
# except Exception as e:
# QMessageBox.critical(self, self.tr("Error"),
# "{0}".format(e),
# QMessageBox.Ok)
with quamash.QEventLoop(self.app.qapp) as loop:
loop.run_until_complete(self.account.send_membership(password, self.community, 'OUT'))
def publish_uid(self):
reply = QMessageBox.warning(self, self.tr("Warning"),
......
......@@ -7,7 +7,9 @@ import signal
import sys
import os
import logging
import asyncio
from quamash import QEventLoop
from PyQt5.QtWidgets import QApplication
from cutecoin.gui.mainwindow import MainWindow
from cutecoin.core.app import Application
......@@ -18,6 +20,8 @@ if __name__ == '__main__':
cutecoin = QApplication(sys.argv)
app = Application(sys.argv, cutecoin)
loop = QEventLoop(app)
asyncio.set_event_loop(loop)
window = MainWindow(app)
window.showMaximized()
sys.exit(cutecoin.exec_())
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment