diff --git a/src/cutecoin/core/person.py b/src/cutecoin/core/person.py index 2885a2f1cd456bc0786552b3f5b736698d90bbbc..2b40cb4e931fceae08c9752a69a2d7a3eb87b43d 100644 --- a/src/cutecoin/core/person.py +++ b/src/cutecoin/core/person.py @@ -6,13 +6,13 @@ Created on 11 févr. 2014 import logging import functools -import collections from ucoinpy.api import bma from ucoinpy import PROTOCOL_VERSION from ucoinpy.documents.certification import SelfCertification from ucoinpy.documents.membership import Membership from cutecoin.tools.exceptions import PersonNotFoundError,\ MembershipNotFoundError +from PyQt5.QtCore import QMutex def load_cache(json_data): @@ -39,36 +39,30 @@ class cached(object): self.func = func def __call__(self, inst, community): - if community.currency in inst._cache: - if self.func.__name__ in inst._cache[community.currency]: - return inst._cache[community.currency][self.func.__name__] - else: + inst._cache_mutex.lock() + try: + inst._cache[community.currency] + except KeyError: inst._cache[community.currency] = {} - value = self.func(inst, community) - inst._cache[community.currency][self.func.__name__] = value + try: + value = inst._cache[community.currency][self.func.__name__] + except KeyError: + value = self.func(inst, community) + inst._cache[community.currency][self.func.__name__] = value + inst._cache_mutex.unlock() return value def __repr__(self): '''Return the function's docstring.''' - return self.func.__doc__ + return self.func.__repr__ def __get__(self, inst, objtype): if inst is None: return self.func return functools.partial(self, inst) - def reload(self, inst, community): - try: - del inst._cache[community.currency][self.func.__name__] - self.__call__(inst, community) - except KeyError: - pass - - def load(self, inst, data): - inst.cache = data - class Person(object): ''' @@ -83,6 +77,7 @@ class Person(object): self.name = name self.pubkey = pubkey self._cache = cache + self._cache_mutex = QMutex() @classmethod def lookup(cls, pubkey, community, cached=True): @@ -249,6 +244,33 @@ class Person(object): return certified_list['certifications'] + def reload(self, func, community): + self._cache_mutex.lock() + if community.currency not in self._cache: + self._cache[community.currency] = {} + + change = False + try: + before = self._cache[community.currency][func.__name__] + except KeyError: + change = True + + value = func(self, community) + + if not change: + if type(value) is dict: + hash_before = (hash(tuple(frozenset(sorted(before.keys())))), + hash(tuple(frozenset(sorted(before.items()))))) + hash_after = (hash(tuple(frozenset(sorted(value.keys())))), + hash(tuple(frozenset(sorted(value.items()))))) + change = hash_before != hash_after + elif type(value) is bool: + change = before != value + + self._cache[community.currency][func.__name__] = value + self._cache_mutex.unlock() + return change + def jsonify(self): data = {'name': self.name, 'pubkey': self.pubkey, diff --git a/src/cutecoin/core/watchers/persons.py b/src/cutecoin/core/watchers/persons.py new file mode 100644 index 0000000000000000000000000000000000000000..84e2dc8f7a12733918857358068e053b22375083 --- /dev/null +++ b/src/cutecoin/core/watchers/persons.py @@ -0,0 +1,37 @@ +''' +Created on 27 févr. 2015 + +@author: inso +''' + +from PyQt5.QtCore import QObject, pyqtSlot, pyqtSignal +from ..person import Person +import logging + + +class PersonsWatcher(QObject): + ''' + This will crawl the network to always + have up to date informations about the nodes + ''' + + person_changed = pyqtSignal(str) + end_watching = pyqtSignal() + + def __init__(self, community): + super().__init__() + self.community = community + + @pyqtSlot() + def watch(self): + logging.debug("Watching persons") + for p in Person._instances.values(): + for func in [Person.membership, + Person.is_member, + Person.certifiers_of, + Person.certified_by]: + if p.reload(func, self.community): + logging.debug("Change detected on {0} about {1}".format(p.pubkey, + func.__name__)) + self.person_changed.emit(p.pubkey) + self.end_watching.emit() diff --git a/src/cutecoin/gui/community_tab.py b/src/cutecoin/gui/community_tab.py index ade37b2388e290639e13f6c3872be4143871d7bd..69075a40d06bb8663de01e674853b5c9b8cf4be6 100644 --- a/src/cutecoin/gui/community_tab.py +++ b/src/cutecoin/gui/community_tab.py @@ -183,3 +183,6 @@ The process to join back the community later will have to be done again.""" "{0}".format(e), QMessageBox.Ok) + def refresh_person(self, pubkey): + index = self.table_community_members.model().sourceModel().person_index(pubkey) + self.table_community_members.model().sourceModel().dataChanged.emit(index[0], index[1]) diff --git a/src/cutecoin/gui/currency_tab.py b/src/cutecoin/gui/currency_tab.py index 2c7dfe57cd2ef784da85e1cc5a3e6da7582fc340..f6efa8ac90a4284fbf299a60c28d2fcbf5a96f94 100644 --- a/src/cutecoin/gui/currency_tab.py +++ b/src/cutecoin/gui/currency_tab.py @@ -22,6 +22,7 @@ from ..core.wallet import Wallet from ..core.person import Person from ..core.transfer import Transfer from ..core.watchers.blockchain import BlockchainWatcher +from ..core.watchers.persons import PersonsWatcher class CurrencyTabWidget(QWidget, Ui_CurrencyTabWidget): @@ -60,6 +61,14 @@ class CurrencyTabWidget(QWidget, Ui_CurrencyTabWidget): self.watcher_thread.start() + self.persons_watcher = PersonsWatcher(self.community) + self.persons_watcher.person_changed.connect(self.tab_community.refresh_person) + self.persons_watcher_thread = QThread() + self.persons_watcher.moveToThread(self.persons_watcher_thread) + self.persons_watcher_thread.started.connect(self.persons_watcher.watch) + self.persons_watcher.end_watching.connect(self.persons_watcher_thread.finished) + self.persons_watcher_thread.start() + person = Person.lookup(self.app.current_account.pubkey, self.community) try: join_block = person.membership(self.community)['blockNumber'] @@ -160,11 +169,7 @@ class CurrencyTabWidget(QWidget, Ui_CurrencyTabWidget): QModelIndex(), []) - if self.tab_community.table_community_members.model(): - self.tab_community.table_community_members.model().dataChanged.emit( - QModelIndex(), - QModelIndex(), - []) + self.persons_watcher_thread.start() text = "Connected : Block {0}".format(block_number) self.status_label.setText(text) diff --git a/src/cutecoin/models/members.py b/src/cutecoin/models/members.py index 3861620572eb120fe2339551b05069fe7ef4d499..72ce548225455de1adfbdca3728e42f11913f07f 100644 --- a/src/cutecoin/models/members.py +++ b/src/cutecoin/models/members.py @@ -7,7 +7,7 @@ Created on 5 févr. 2014 from ucoinpy.api import bma from ..core.person import Person from PyQt5.QtCore import QAbstractTableModel, QSortFilterProxyModel, Qt, \ - QDateTime + QDateTime, QModelIndex from PyQt5.QtGui import QColor import logging @@ -104,5 +104,14 @@ class MembersTableModel(QAbstractTableModel): col = index.column() return self.member_data(self.pubkeys[row])[col] + def person_index(self, pubkey): + try: + row = self.pubkeys.index(pubkey) + index_start = self.index(row, 0) + index_end = self.index(row, len(self.columns_ids)) + return (index_start, index_end) + except ValueError: + return (QModelIndex(), QModelIndex()) + def flags(self, index): return Qt.ItemIsSelectable | Qt.ItemIsEnabled