diff --git a/src/cutecoin/core/community.py b/src/cutecoin/core/community.py index c0999f362bdd181afead252809520f8563867759..762dd50232bd01eabd5c6a9bb1d889f390a03de4 100644 --- a/src/cutecoin/core/community.py +++ b/src/cutecoin/core/community.py @@ -17,6 +17,9 @@ from requests.exceptions import RequestException class Cache(): + _saved_requests = [hash(bma.blockchain.Block), + hash(bma.wot.Lookup)] + def __init__(self, community): self.latest_block = 0 self.community = community @@ -32,9 +35,8 @@ class Cache(): self.latest_block = data['latest_block'] def jsonify(self): - saved_requests = [hash(bma.blockchain.Block)] data = {k: self.data[k] for k in self.data.keys() - if k[0] in saved_requests} + if k[0] in Cache._saved_requests} entries = [] for d in data: entries.append({'key': d, @@ -44,9 +46,8 @@ class Cache(): def refresh(self): self.latest_block = self.community.current_blockid()['number'] - saved_requests = [hash(bma.blockchain.Block)] self.data = {k: self.data[k] for k in self.data.keys() - if k[0] in saved_requests} + if k[0] in Cache._saved_requests} def request(self, request, req_args={}, get_args={}): cache_key = (hash(request), diff --git a/src/cutecoin/core/person.py b/src/cutecoin/core/person.py index 57c6e7695ecc224cbcca7141eeb9678ae9c534da..11d521cd61af3c0f5df6316e09448de03e622457 100644 --- a/src/cutecoin/core/person.py +++ b/src/cutecoin/core/person.py @@ -5,6 +5,8 @@ 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 @@ -13,48 +15,129 @@ from cutecoin.tools.exceptions import PersonNotFoundError,\ MembershipNotFoundError -class Person(object): +def load_cache(json_data): + for person_data in json_data: + person = Person.from_json(person_data) + Person._instances[person.pubkey] = person + + +class cached(object): + ''' + Decorator. Caches a function's return value each time it is called. + If called later with the same arguments, the cached value is returned + (not reevaluated). + Delete it to clear it from the cache + ''' + def __init__(self, func): + self.func = func + self.cache = {} + + def __call__(self, inst, community): + try: + inst.__cache + except AttributeError: + inst.__cache = {} + + 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[community.currency] = {} + + value = self.func(inst, community) + inst.__cache[community.currency][self.func.__name__] = value + return value + + def __repr__(self): + '''Return the function's docstring.''' + return self.func.__doc__ + + 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): ''' A person with a name, a fingerprint and an email - Created by the person.factory ''' + _instances = {} - def __init__(self, name, pubkey): + def __init__(self, name, pubkey, cache): ''' Constructor ''' self.name = name self.pubkey = pubkey + self.__cache = cache @classmethod def lookup(cls, pubkey, community, cached=True): ''' Create a person from the pubkey found in a community ''' - data = community.request(bma.wot.Lookup, req_args={'search': pubkey}, - cached=cached) - timestamp = 0 + if pubkey in Person._instances: + return Person._instances[pubkey] + else: + logging.debug("{0} : {1} in ? {2}".format(len(Person._instances), + pubkey, pubkey in Person._instances)) + logging.debug("{0}".format(Person._instances.keys())) + data = community.request(bma.wot.Lookup, req_args={'search': pubkey}, + cached=cached) + timestamp = 0 - for result in data['results']: - if result["pubkey"] == pubkey: - uids = result['uids'] - for uid in uids: - if uid["meta"]["timestamp"] > timestamp: - timestamp = uid["meta"]["timestamp"] - name = uid["uid"] + for result in data['results']: + if result["pubkey"] == pubkey: + uids = result['uids'] + for uid in uids: + if uid["meta"]["timestamp"] > timestamp: + timestamp = uid["meta"]["timestamp"] + name = uid["uid"] - return cls(name, pubkey) + person = cls(name, pubkey, {}) + Person._instances[pubkey] = person + logging.debug("{0}".format(Person._instances.keys())) + return person raise PersonNotFoundError(pubkey, community.name()) @classmethod + def from_metadata(cls, name, pubkey): + if pubkey in Person._instances: + return Person._instances[pubkey] + else: + person = cls(name, pubkey, {}) + Person._instances[pubkey] = person + return person + + @classmethod + #TODO: Remove name from person, contats should not use the person class def from_json(cls, json_person): ''' Create a person from json data ''' - name = json_person['name'] pubkey = json_person['pubkey'] - return cls(name, pubkey) + if pubkey in Person._instances: + return Person._instances[pubkey] + else: + name = json_person['name'] + if 'cache' in json_person: + cache = json_person['cache'] + else: + cache = {} + person = cls(name, pubkey, cache) + Person._instances[pubkey] = person + return person def selfcert(self, community): data = community.request(bma.wot.Lookup, req_args={'search': self.pubkey}) @@ -78,6 +161,7 @@ class Person(object): signature) raise PersonNotFoundError(self.pubkey, community.name()) + @cached def membership(self, community): try: search = community.request(bma.blockchain.Membership, @@ -103,6 +187,7 @@ class Person(object): search['sigDate'], None) return membership + @cached def is_member(self, community): try: certifiers = community.request(bma.wot.CertifiersOf, {'search': self.pubkey}) @@ -110,6 +195,7 @@ class Person(object): except ValueError: return False + @cached def certifiers_of(self, community): try: certifiers = community.request(bma.wot.CertifiersOf, {'search': self.pubkey}) @@ -141,6 +227,7 @@ class Person(object): return certifiers['certifications'] + @cached def certified_by(self, community): try: certified_list = community.request(bma.wot.CertifiedBy, {'search': self.pubkey}) @@ -151,6 +238,7 @@ class Person(object): except ValueError as e: logging.debug('bma.wot.Lookup request ValueError : ' + str(e)) return list() + certified_list = list() for certified in data['results'][0]['signed']: certified['cert_time'] = dict() @@ -167,5 +255,6 @@ class Person(object): def jsonify(self): data = {'name': self.name, - 'pubkey': self.pubkey} + 'pubkey': self.pubkey, + 'cache': self.__cache} return data diff --git a/src/cutecoin/gui/contact.py b/src/cutecoin/gui/contact.py index 469b9fb88839af42fc85ed08fdc1c20c8839a92d..1f2a419cff8775507e54d7e3c1a98b45864916d7 100644 --- a/src/cutecoin/gui/contact.py +++ b/src/cutecoin/gui/contact.py @@ -39,7 +39,7 @@ class ConfigureContactDialog(QDialog, Ui_ConfigureContactDialog): self.contact.pubkey = pubkey else: try: - self.account.add_contact(Person(name, pubkey)) + self.account.add_contact(Person.from_metadata(name, pubkey)) except ContactAlreadyExists as e: QMessageBox.critical(self, "Contact already exists", str(e), diff --git a/src/cutecoin/gui/wot_tab.py b/src/cutecoin/gui/wot_tab.py index 9933e02296d0e8b6977efebab5228977625bb75c..71a96c8b553437556d8060f2d3cef97605646c5d 100644 --- a/src/cutecoin/gui/wot_tab.py +++ b/src/cutecoin/gui/wot_tab.py @@ -254,4 +254,4 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): return block.mediantime def get_person_from_metadata(self, metadata): - return Person(metadata['text'], metadata['id']) + return Person.from_metadata(metadata['text'], metadata['id'])