diff --git a/src/cutecoin/core/app.py b/src/cutecoin/core/app.py index 0f98ca87675a261d5c14d1b0f87910909e4b417c..3019f976ce5d2452474d978028a69e0c045bd4d9 100644 --- a/src/cutecoin/core/app.py +++ b/src/cutecoin/core/app.py @@ -10,7 +10,7 @@ import tarfile import shutil import json import datetime -import i18n_rc +import asyncio from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, \ QUrl, QTranslator, QCoreApplication, QLocale @@ -399,7 +399,6 @@ class Application(QObject): def stop(self): for c in self.current_account.communities: c.network.stop_crawling() - self.loop.stop() def get_last_version(self): url = QUrl("https://api.github.com/repos/ucoin-io/cutecoin/releases") diff --git a/src/cutecoin/core/net/api/bma/access.py b/src/cutecoin/core/net/api/bma/access.py index e767e082446c6c7b2abbcf3b1b9e81c7fbf43369..06f2eeb3f8c721947ff8ec07e8217937a8329399 100644 --- a/src/cutecoin/core/net/api/bma/access.py +++ b/src/cutecoin/core/net/api/bma/access.py @@ -75,6 +75,49 @@ class BmaAccess(QObject): str(tuple(frozenset(sorted(get_args.keys())))), str(tuple(frozenset(sorted(get_args.values()))))) + def _compare_json(self, first, second): + """ + Compare two json dicts + :param first: the first dictionnary + :param second: the second dictionnary + :return: True if the json dicts are the same + :rtype: bool + """ + if first is not None: + if not isinstance(first, type(second)): + return False + if isinstance(first, dict): + for key in first: + if isinstance(second, dict): + if second.has_key(key): + sec = second[key] + else: + # there are key in the first, that is not presented in the second + return False + # recursive call + return self._compare_json(first[key], sec) + else: + # second is not dict + return False + # if object is list, loop over it and check. + elif isinstance(first, list): + for (index, item) in enumerate(first): + # try to get the same index from second + sec = None + if second is not None: + try: + sec = second[index] + except (IndexError, KeyError): + # goes to difference + return False + # recursive call + return self._compare_json(first[index], sec) + # not list, not dict. check for equality + elif first != second: + return False + else: + return True + def _get_from_cache(self, request, req_args, get_args): """ Get data from the cache @@ -118,7 +161,7 @@ class BmaAccess(QObject): self._data[cache_key]['value'] = {} self._data[cache_key]['metadata']['block'] = self._network.latest_block - if self._data[cache_key]['value'] != data: + if not self._compare_json(self._data[cache_key]['value'], data): self._data[cache_key]['value'] = data return True return False @@ -152,10 +195,36 @@ class BmaAccess(QObject): reply = self.simple_request(request, req_args, get_args) logging.debug("New pending request {0}, caller {1}".format(cache_key, caller)) self._pending_requests[cache_key] = [caller] - reply.finished.connect(lambda: - self.handle_reply(request, req_args, get_args, tries)) + reply.finished.connect(lambda: self.handle_reply(request, req_args, get_args, tries)) return ret_data + @pyqtSlot(int, dict, dict, int) + def handle_reply(self, request, req_args, get_args, tries): + reply = self.sender() + logging.debug("Handling QtNetworkReply for {0}".format(str(request))) + cache_key = BmaAccess._gen_cache_key(request, req_args, get_args) + + if reply.error() == QNetworkReply.NoError: + strdata = bytes(reply.readAll()).decode('utf-8') + json_data = json.loads(strdata) + # If data changed, we emit a change signal to all callers + if self._update_cache(request, req_args, get_args, json_data): + logging.debug(self._pending_requests.keys()) + for caller in self._pending_requests[cache_key]: + logging.debug("Emit change for {0} : {1} ".format(caller, request)) + caller.inner_data_changed.emit(str(request)) + self._pending_requests.pop(cache_key) + else: + logging.debug("Error in reply : {0}".format(reply.error())) + if tries < 3: + tries += 1 + try: + pending_request = self._pending_requests.pop(cache_key) + for caller in pending_request: + self.get(caller, request, req_args, get_args, tries=tries) + except KeyError: + logging.debug("{0} is not present anymore in pending requests".format(cache_key)) + def future_request(self, request, req_args={}, get_args={}): ''' Start a request to the network and returns a future. @@ -216,28 +285,6 @@ class BmaAccess(QObject): else: raise NoPeerAvailable(self.currency, len(nodes)) - @pyqtSlot(int, dict, dict, QObject) - def handle_reply(self, request, req_args, get_args, tries): - reply = self.sender() - logging.debug("Handling QtNetworkReply for {0}".format(str(request))) - cache_key = BmaAccess._gen_cache_key(request, req_args, get_args) - - if reply.error() == QNetworkReply.NoError: - strdata = bytes(reply.readAll()).decode('utf-8') - json_data = json.loads(strdata) - if self._update_cache(request, req_args, get_args, json_data): - logging.debug(self._pending_requests.keys()) - for caller in self._pending_requests[cache_key]: - logging.debug("Emit change for {0} : {1} ".format(caller, request)) - caller.inner_data_changed.emit(str(request)) - self._pending_requests.pop(cache_key) - else: - logging.debug("Error in reply : {0}".format(reply.error())) - if tries < 3: - self._pending_requests.pop(cache_key) - for caller in self._pending_requests[cache_key]: - self.get(caller, request, req_args, get_args) - def broadcast(self, request, req_args={}, post_args={}): ''' Broadcast data to a network. diff --git a/src/cutecoin/gui/community_tab.py b/src/cutecoin/gui/community_tab.py index 1d48a2a3651e485b5e7412737a1ec1566ac61a31..63599e9b9f7c34c71114ca3dca6d558c66263340 100644 --- a/src/cutecoin/gui/community_tab.py +++ b/src/cutecoin/gui/community_tab.py @@ -230,17 +230,10 @@ Revoking your UID can only success if it is not already validated by the network self.account.revoke(password, self.community) toast.display(self.tr("UID Revoking"), self.tr("Success revoking your UID")) - except ValueError as e: - QMessageBox.critical(self, self.tr("Revoke UID 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) @asyncio.coroutine def _execute_search_text(self, text): @@ -250,6 +243,16 @@ Revoking your UID can only success if it is not already validated by the network identity = yield from self.app.identities_registry.future_lookup(identity_data['pubkey'], self.community) identities.append(identity) + self_identity = self.account.identity(self.community) + try: + self_identity.inner_data_changed.disconnect(self.handle_account_identity_change) + self.community.inner_data_changed.disconnect(self.handle_community_change) + except TypeError as e: + if "disconnect() failed" in str(e): + pass + else: + raise + self.edit_textsearch.clear() self.refresh(identities)