diff --git a/src/sakia/data/connectors/bma.py b/src/sakia/data/connectors/bma.py index ed48ec3aa4ca586b3b8aaf7208b397fcb6581c88..8030fc6706c2968ca48ad38355066a52532ea407 100644 --- a/src/sakia/data/connectors/bma.py +++ b/src/sakia/data/connectors/bma.py @@ -65,7 +65,7 @@ class BmaConnector: asyncio.TimeoutError, ValueError, jsonschema.ValidationError) as e: self._logger.debug(str(e)) tries += 1 - raise NoPeerAvailable("", len(endpoint)) + raise NoPeerAvailable("", len(endpoints)) async def broadcast(self, currency, request, req_args={}, post_args={}): """ diff --git a/src/sakia/data/connectors/node.py b/src/sakia/data/connectors/node.py index c030f85716a60d216f9d9b3c2677701580fef981..006cbc897a2fb720845f5ab0315582b93bb88cc3 100644 --- a/src/sakia/data/connectors/node.py +++ b/src/sakia/data/connectors/node.py @@ -174,12 +174,13 @@ class NodeConnector(QObject): except (ClientError, gaierror, TimeoutError, DisconnectedError) as e: self._logger.debug("{0} : {1}".format(str(e), self.node.pubkey[:5])) self.node.state = Node.OFFLINE + self.changed.emit() except jsonschema.ValidationError as e: self._logger.debug(str(e)) self._logger.debug("Validation error : {0}".format(self.node.pubkey[:5])) self.node.state = Node.CORRUPTED - finally: self.changed.emit() + finally: self._connected['block'] = False self._ws_tasks['block'] = None @@ -191,16 +192,18 @@ class NodeConnector(QObject): for endpoint in [e for e in self.node.endpoints if isinstance(e, BMAEndpoint)]: try: block_data = await self.safe_request(endpoint, bma.blockchain.Current, self._session) + if not block_data: + continue await self.refresh_block(block_data) return # Do not try any more endpoint except errors.DuniterError as e: if e.ucode == errors.BLOCK_NOT_FOUND: self.node.previous_buid = BlockUID.empty() + self.changed.emit() else: self.node.state = Node.OFFLINE + self.changed.emit() self._logger.debug("Error in block reply of {0} : {1}}".format(self.node.pubkey[:5], str(e))) - finally: - self.changed.emit() else: self._logger.debug("Could not connect to any BMA endpoint : {0}".format(self.node.pubkey[:5])) self.node.state = Node.OFFLINE @@ -219,6 +222,8 @@ class NodeConnector(QObject): try: previous_block = await self.safe_request(endpoint, bma.blockchain.Block, req_args={'number': self.node.current_buid.number}) + if not previous_block: + continue self.node.previous_buid = BlockUID(previous_block['number'], previous_block['hash']) return # Do not try any more endpoint except errors.DuniterError as e: @@ -229,11 +234,12 @@ class NodeConnector(QObject): self.node.state = Node.OFFLINE self._logger.debug("Error in previous block reply of {0} : {1}".format(self.node.pubkey[:5], str(e))) finally: - self.node.current_buid = BlockUID(block_data['number'], block_data['hash']) - self.node.current_ts = block_data['medianTime'] - self._logger.debug("Changed block {0} -> {1}".format(self.node.current_buid.number, - block_data['number'])) - self.changed.emit() + if self.node.current_buid != BlockUID(block_data['number'], block_data['hash']): + self.node.current_buid = BlockUID(block_data['number'], block_data['hash']) + self.node.current_ts = block_data['medianTime'] + self._logger.debug("Changed block {0} -> {1}".format(self.node.current_buid.number, + block_data['number'])) + self.changed.emit() else: self._logger.debug("Could not connect to any BMA endpoint : {0}".format(self.node.pubkey[:5])) self.node.state = Node.OFFLINE @@ -247,14 +253,16 @@ class NodeConnector(QObject): for endpoint in [e for e in self.node.endpoints if isinstance(e, BMAEndpoint)]: try: summary_data = await self.safe_request(endpoint, bma.node.Summary) + if not summary_data: + continue self.node.software = summary_data["duniter"]["software"] self.node.version = summary_data["duniter"]["version"] self.node.state = Node.ONLINE + self.changed.emit() return # Break endpoints loop except errors.DuniterError as e: self.node.state = Node.OFFLINE self._logger.debug("Error in summary of {0} : {1}".format(self.node.pubkey[:5], str(e))) - finally: self.changed.emit() else: self._logger.debug("Could not connect to any BMA endpoint : {0}".format(self.node.pubkey[:5])) @@ -271,6 +279,8 @@ class NodeConnector(QObject): data = await self.safe_request(endpoint, bma.wot.Lookup, req_args={'search':self.node.pubkey}, get_args={}) + if not data: + continue self.node.state = Node.ONLINE timestamp = BlockUID.empty() uid = "" @@ -327,14 +337,15 @@ class NodeConnector(QObject): except (ClientError, gaierror, TimeoutError, DisconnectedError) as e: self._logger.debug("{0} : {1}".format(str(e), self.node.pubkey[:5])) self.node.state = Node.OFFLINE + self.changed.emit() except jsonschema.ValidationError as e: self._logger.debug(str(e)) self._logger.debug("Validation error : {0}".format(self.node.pubkey[:5])) self.node.state = Node.CORRUPTED + self.changed.emit() finally: self._connected['peer'] = False self._ws_tasks['peer'] = None - self.changed.emit() else: self._logger.debug("Could not connect to any BMA endpoint : {0}".format(self.node.pubkey[:5])) self.node.state = Node.OFFLINE @@ -348,6 +359,8 @@ class NodeConnector(QObject): try: peers_data = await self.safe_request(endpoint, bma.network.peering.Peers, get_args={'leaves': 'true'}) + if not peers_data: + continue self.node.state = Node.ONLINE if peers_data['root'] != self.node.merkle_peers_root: leaves = [leaf for leaf in peers_data['leaves'] @@ -357,6 +370,8 @@ class NodeConnector(QObject): leaf_data = await self.safe_request(endpoint, bma.network.peering.Peers, get_args={'leaf': leaf_hash}) + if not leaf_data: + break self.refresh_peer_data(leaf_data['leaf']['value']) except (AttributeError, ValueError, errors.DuniterError) as e: self._logger.debug("{pubkey} : Incorrect peer data in {leaf}" @@ -365,13 +380,13 @@ class NodeConnector(QObject): self.node.state = Node.OFFLINE finally: self.changed.emit() - self.node.merkle_peers_root = peers_data['root'] - self.node.merkle_peers_leaves = tuple(peers_data['leaves']) + else: + self.node.merkle_peers_root = peers_data['root'] + self.node.merkle_peers_leaves = tuple(peers_data['leaves']) return # Break endpoints loop except errors.DuniterError as e: self._logger.debug("Error in peers reply : {0}".format(str(e))) self.node.state = Node.OFFLINE - finally: self.changed.emit() else: self._logger.debug("Could not connect to any BMA endpoint : {0}".format(self.node.pubkey[:5])) diff --git a/src/sakia/data/processors/blockchain.py b/src/sakia/data/processors/blockchain.py index b2e4dcfe1feca585a6277e8420305d7eb10f758c..ab5bc52fb853874647d22c39f82465991be139d0 100644 --- a/src/sakia/data/processors/blockchain.py +++ b/src/sakia/data/processors/blockchain.py @@ -123,7 +123,7 @@ class BlockchainProcessor: bma.blockchain.Excluded, bma.blockchain.Newcomers): future_requests.append(self._bma_connector.get(currency, req)) - results = await asyncio.gather(future_requests) + results = await asyncio.gather(*future_requests) for res in results: with_identities += res["result"]["blocks"] @@ -140,7 +140,7 @@ class BlockchainProcessor: future_requests = [] for req in (bma.blockchain.UD, bma.blockchain.TX): future_requests.append(self._bma_connector.get(currency, req)) - results = await asyncio.gather(future_requests) + results = await asyncio.gather(*future_requests) for res in results: with_money += res["result"]["blocks"] diff --git a/src/sakia/data/processors/identities.py b/src/sakia/data/processors/identities.py index f85ed66f477ccbeb09ebdcc3252e3dd47cc7098a..96efad15ed8df1bf73754b5d2cecaa4c36308e40 100644 --- a/src/sakia/data/processors/identities.py +++ b/src/sakia/data/processors/identities.py @@ -71,21 +71,20 @@ class IdentitiesProcessor: tries = 0 while tries < 3: try: - data = await self._bma_connector.get(bma.wot.Lookup, - req_args={'search': text}) + data = await self._bma_connector.get(currency, bma.wot.Lookup, req_args={'search': text}) for result in data['results']: pubkey = result['pubkey'] for uid_data in result['uids']: if not uid_data['revoked']: - identity = Identity(currency, pubkey, uid_data['uid'], uid_data['sigDate']) - identity.signature = data['self'] - identity.blockstamp = data['meta']['timestamp'] + identity = Identity(currency, pubkey, uid_data['uid'], + uid_data['meta']['timestamp'], uid_data['self']) if identity not in identities: identities.append(identity) + break except (errors.DuniterError, asyncio.TimeoutError, ClientError) as e: tries += 1 - except NoPeerAvailable: - return identities + except NoPeerAvailable as e: + self._logger.debug(str(e)) return identities def get_written(self, currency, pubkey): diff --git a/src/sakia/data/processors/nodes.py b/src/sakia/data/processors/nodes.py index e084b32105efdce1482fbf16a8a9d8716627645b..fb065d992ced5efa4906453172689bb6411ab8b0 100644 --- a/src/sakia/data/processors/nodes.py +++ b/src/sakia/data/processors/nodes.py @@ -9,6 +9,14 @@ import logging class NodesProcessor: _repo = attr.ib() # :type sakia.data.repositories.NodesRepo + def current_buid(self, currency): + """ + Get current buid + :param str currency: + """ + synced_node = self._repo.get_one(currency=currency, state=Node.ONLINE) + return synced_node.current_buid + def synced_nodes(self, currency): """ Get nodes which are in the ONLINE state. diff --git a/src/sakia/data/repositories/identities.py b/src/sakia/data/repositories/identities.py index 60b12db4de9e55979fb392b9945e28655acfd36c..10c229e6bf8f69989a7048b8254db826be879440 100644 --- a/src/sakia/data/repositories/identities.py +++ b/src/sakia/data/repositories/identities.py @@ -124,16 +124,16 @@ class IdentitiesRepo: return [Identity(*data) for data in datas] return [] - def find_all(self, text): + def find_all(self, currency, text): """ Get all existing identity in the database corresponding to the search :param dict search: the criterions of the lookup :rtype: sakia.data.entities.Identity """ with self._conn: - request = "SELECT * FROM identities WHERE UID LIKE ? or PUBKEY LIKE ?" + request = "SELECT * FROM identities WHERE currency=? AND (UID LIKE ? or PUBKEY LIKE ?)" - c = self._conn.execute(request, tuple("%{0}%".format(text),)) + c = self._conn.execute(request, (currency, "%{0}%".format(text), "%{0}%".format(text))) datas = c.fetchall() if datas: return [Identity(*data) for data in datas] diff --git a/src/sakia/gui/navigation/identities/controller.py b/src/sakia/gui/navigation/identities/controller.py index 18347d5c1596cafed7dd9d74096dfd70533580e1..370fa23e20a354eb8a3c5cc9f0a7882d7698c68c 100644 --- a/src/sakia/gui/navigation/identities/controller.py +++ b/src/sakia/gui/navigation/identities/controller.py @@ -55,20 +55,19 @@ class IdentitiesController(ComponentController): @classmethod def create(cls, parent, app, **kwargs): - account = kwargs['account'] - community = kwargs['community'] + connection = kwargs['connection'] + blockchain_service = kwargs['blockchain_service'] + identities_service = kwargs['identities_service'] view = IdentitiesView(parent.view) - model = IdentitiesModel(None, app, account, community) - txhistory = cls(parent, view, model) - model.setParent(txhistory) - return txhistory + model = IdentitiesModel(None, app, connection, blockchain_service, identities_service) + identities = cls(parent, view, model) + model.setParent(identities) + return identities - @once_at_a_time - @asyncify - async def identity_context_menu(self, point): + def identity_context_menu(self, point): index = self.view.table_identities.indexAt(point) - valid, identity = await self.model.table_data(index) + valid, identity = self.model.table_data(index) if valid: menu = ContextMenu.from_data(self.view, self.app, self.account, self.community, self.password_asker, (identity,)) @@ -86,16 +85,8 @@ class IdentitiesController(ComponentController): :return: """ try: - response = await self.community.bma_access.future_request(bma.wot.Lookup, {'search': text}) - identities = [] - for identity_data in response['results']: - for uid_data in identity_data['uids']: - identity = Identity.from_handled_data(uid_data['uid'], - identity_data['pubkey'], - BlockUID.from_str(uid_data['meta']['timestamp']), - BlockchainState.BUFFERED) - identities.append(identity) - await self.model.refresh_identities(identities) + identities = await self.model.lookup_identities(text) + self.model.refresh_identities(identities) except errors.DuniterError as e: if e.ucode == errors.BLOCK_NOT_FOUND: logging.debug(str(e)) @@ -121,4 +112,4 @@ class IdentitiesController(ComponentController): certified_by = [p for p in account_connections if p.pubkey not in [i.pubkey for i in certifiers_of]] identities = certifiers_of + certified_by - await self.model.refresh_identities(identities) + self.model.refresh_identities(identities) diff --git a/src/sakia/gui/navigation/identities/model.py b/src/sakia/gui/navigation/identities/model.py index c2737855d3427d4718b4319cb3ca9cd1eb2eb637..218985c6aac2f568c136012e8e570b25efeb6a65 100644 --- a/src/sakia/gui/navigation/identities/model.py +++ b/src/sakia/gui/navigation/identities/model.py @@ -8,19 +8,21 @@ class IdentitiesModel(ComponentModel): The model of the identities component """ - def __init__(self, parent, app, account, community): + def __init__(self, parent, app, connection, blockchain_service, identities_service): """ Constructor of a model of Identities component :param sakia.gui.identities.controller.IdentitiesController parent: the controller - :param sakia.core.Application app: the app - :param sakia.core.Account account: the account - :param sakia.core.Community community: the communitys + :param sakia.app.Application app: the app + :param sakia.data.entities.Connection connection: the connection + :param sakia.services.BlockchainService blockchain_service: the blockchain service + :param sakia.services.IdentitiesService identities_service: the identities service """ super().__init__(parent) self.app = app - self.account = account - self.community = community + self.connection = connection + self.blockchain_service = blockchain_service + self.identities_service = identities_service self.table_model = None @@ -28,13 +30,13 @@ class IdentitiesModel(ComponentModel): """ Instanciate the table model of the view """ - identities_model = IdentitiesTableModel(self, self.community) + identities_model = IdentitiesTableModel(self, self.blockchain_service, self.identities_service) proxy = IdentitiesFilterProxyModel() proxy.setSourceModel(identities_model) self.table_model = proxy return self.table_model - async def table_data(self, index): + def table_data(self, index): """ Get table data at given point :param PyQt5.QtCore.QModelIndex index: @@ -46,13 +48,23 @@ class IdentitiesModel(ComponentModel): pubkey_index = self.table_model.sourceModel().index(source_index.row(), pubkey_col) pubkey = self.table_model.sourceModel().data(pubkey_index, Qt.DisplayRole) - identity = await self.app.identities_registry.future_find(pubkey, self.community) + identity_col = self.table_model.sourceModel().columns_ids.index('pubkey') + identity_index = self.table_model.sourceModel().index(source_index.row(), + pubkey_col) + identity = self.table_model.sourceModel().data(identity_index, Qt.DisplayRole) return True, identity return False, None - async def refresh_identities(self, identities): + async def lookup_identities(self, text): + """ + Lookup for identities + :param str text: text contained in the identities to lookup + """ + return await self.identities_service.lookup(text) + + def refresh_identities(self, identities): """ Refresh the table with specified identities. If no identities is passed, use the account connections. """ - await self.table_model.sourceModel().refresh_identities(identities) + self.table_model.sourceModel().refresh_identities(identities) diff --git a/src/sakia/gui/navigation/identities/table_model.py b/src/sakia/gui/navigation/identities/table_model.py index 2b65d57557b581d73a1f9a9b55e58924ac0493ec..128506bb218f21fa3e9a9e38fe7affd48ddccdec 100644 --- a/src/sakia/gui/navigation/identities/table_model.py +++ b/src/sakia/gui/navigation/identities/table_model.py @@ -15,15 +15,6 @@ import asyncio class IdentitiesFilterProxyModel(QSortFilterProxyModel): def __init__(self, parent=None): super().__init__(parent) - self.community = None - - def setSourceModel(self, sourceModel): - self.community = sourceModel.community - super().setSourceModel(sourceModel) - - def change_community(self, community): - self.community = community - self.sourceModel().change_community(community) def lessThan(self, left, right): """ @@ -63,7 +54,7 @@ class IdentitiesFilterProxyModel(QSortFilterProxyModel): if role == Qt.DisplayRole: if source_index.column() in (self.sourceModel().columns_ids.index('renewed'), self.sourceModel().columns_ids.index('expiration')): - if source_data is not None: + if source_data: return QLocale.toString( QLocale(), QDateTime.fromTime_t(source_data).date(), @@ -72,7 +63,7 @@ class IdentitiesFilterProxyModel(QSortFilterProxyModel): else: return "" if source_index.column() == self.sourceModel().columns_ids.index('publication'): - if source_data is not None: + if source_data: return QLocale.toString( QLocale(), QDateTime.fromTime_t(source_data), @@ -107,19 +98,23 @@ class IdentitiesTableModel(QAbstractTableModel): A Qt abstract item model to display communities in a tree """ - def __init__(self, parent, community): + def __init__(self, parent, blockchain_service, identities_service): """ Constructor + :param parent: + :param sakia.services.BlockchainService blockchain_service: the blockchain service + :param sakia.services.IdentitiesService identities_service: the identities service """ super().__init__(parent) - self.community = community + self.blockchain_service = blockchain_service + self.identities_service = identities_service self.columns_titles = {'uid': lambda: self.tr('UID'), 'pubkey': lambda: self.tr('Pubkey'), 'renewed': lambda: self.tr('Renewed'), 'expiration': lambda: self.tr('Expiration'), 'publication': lambda: self.tr('Publication Date'), 'block': lambda: self.tr('Publication Block'),} - self.columns_ids = ('uid', 'pubkey', 'renewed', 'expiration', 'publication', 'block') + self.columns_ids = ('uid', 'pubkey', 'renewed', 'expiration', 'publication', 'block', 'identity') self.identities_data = [] self._sig_validity = 0 @@ -129,59 +124,40 @@ class IdentitiesTableModel(QAbstractTableModel): @property def pubkeys(self): """ - Ge - def resizeEvent(self, event): - self.busy.resize(event.size()) - super().resizeEvent(event)t pubkeys of displayed identities + Get pubkeys of displayed identities """ return [i[1] for i in self.identities_data] - async def identity_data(self, identity): + def identity_data(self, identity): """ Return the identity in the form a tuple to display - :param sakia.core.registry.Identity identity: The identity to get data from + :param sakia.data.entities.Identity identity: The identity to get data from :return: The identity data in the form of a tuple :rtype: tuple """ - try: - join_date = await identity.get_join_date(self.community) - expiration_date = await identity.get_expiration_date(self.community) - except MembershipNotFoundError: - join_date = None - expiration_date = None - - if identity.sigdate: - sigdate_ts = await self.community.time(identity.sigdate.number) - sigdate_block = identity.sigdate.sha_hash[:7] - else: - sigdate_ts = None - sigdate_block = None - - return identity.uid, identity.pubkey, join_date, expiration_date, sigdate_ts, sigdate_block - - async def refresh_identities(self, identities): + join_date = identity.membership_timestamp + expiration_date = self.identities_service.expiration_date(identity) + sigdate_ts = identity.timestamp + sigdate_block = identity.blockstamp.sha_hash[:7] + + return identity.uid, identity.pubkey, join_date, expiration_date, sigdate_ts, sigdate_block, identity + + def refresh_identities(self, identities): """ Change the identities to display - :param sakia.core.registry.IdentitiesRegistry identities: The new identities to display + :param list[sakia.data.entities.Identity] identities: The new identities to display """ logging.debug("Refresh {0} identities".format(len(identities))) self.beginResetModel() - self.identities_data = [] - self.endResetModel() - self.beginResetModel() identities_data = [] - requests_coro = [] for identity in identities: - coro = asyncio.ensure_future(self.identity_data(identity)) - requests_coro.append(coro) - - identities_data = await asyncio.gather(*requests_coro) + identities_data.append(self.identity_data(identity)) if len(identities) > 0: try: - parameters = await self.community.parameters() - self._sig_validity = parameters['sigValidity'] + parameters = self.blockchain_service.parameters() + self._sig_validity = parameters.sig_validity except NoPeerAvailable as e: logging.debug(str(e)) self._sig_validity = 0 @@ -192,7 +168,7 @@ class IdentitiesTableModel(QAbstractTableModel): return len(self.identities_data) def columnCount(self, parent): - return len(self.columns_ids) + return len(self.columns_ids) - 1 def headerData(self, section, orientation, role): if role == Qt.DisplayRole: diff --git a/src/sakia/gui/navigation/identities/view.py b/src/sakia/gui/navigation/identities/view.py index 24e6bb955d2f0a5a01838d65a5ae8f7328f74163..c5011b16d8ee0a5c03d61773d436038eb353d8a8 100644 --- a/src/sakia/gui/navigation/identities/view.py +++ b/src/sakia/gui/navigation/identities/view.py @@ -39,11 +39,11 @@ class IdentitiesView(QWidget, Ui_IdentitiesWidget): model.modelReset.connect(lambda: self.table_identities.setEnabled(True)) def request_search_by_text(self): - text = self.ui.edit_textsearch.text() + text = self.edit_textsearch.text() if len(text) < 2: return - self.ui.edit_textsearch.clear() - self.ui.edit_textsearch.setPlaceholderText(text) + self.edit_textsearch.clear() + self.edit_textsearch.setPlaceholderText(text) self.search_by_text_requested.emit(text) def request_search_direct_connections(self): diff --git a/src/sakia/gui/navigation/model.py b/src/sakia/gui/navigation/model.py index 794f2b1ec35fec8d635aee6b12f299afbd0de62c..883b520141d1fad1bf9161d6214840b2aa05991c 100644 --- a/src/sakia/gui/navigation/model.py +++ b/src/sakia/gui/navigation/model.py @@ -40,7 +40,7 @@ class NavigationModel(ComponentModel): 'blockchain_service': self.app.blockchain_services[connection.currency], 'identities_service': self.app.identities_services[connection.currency], 'sources_service': self.app.sources_services[connection.currency], - 'connection':connection, + 'connection': connection, }, 'children': [ # { @@ -58,13 +58,16 @@ class NavigationModel(ComponentModel): 'network_service': self.app.network_services[connection.currency], } }, - # { - # 'node': { - # 'title': self.tr('Identities'), - # 'icon': ':/icons/members_icon', - # 'component': "Identities", - # } - # }, + { + 'node': { + 'title': self.tr('Identities'), + 'icon': ':/icons/members_icon', + 'component': "Identities", + 'connection': connection, + 'blockchain_service': self.app.blockchain_services[connection.currency], + 'identities_service': self.app.identities_services[connection.currency], + } + }, # { # 'node': { # 'title': self.tr('Web of Trust'), diff --git a/src/sakia/services/blockchain.py b/src/sakia/services/blockchain.py index a777546a1d8831636768fe28e440a9488ed12266..dec471ab2a785ed4c7e93a629fce3904cfbb9617 100644 --- a/src/sakia/services/blockchain.py +++ b/src/sakia/services/blockchain.py @@ -29,9 +29,9 @@ class BlockchainService(QObject): """ Handle a new current block uid """ - with_identities = await self._blockchain_processor.new_blocks_with_identities() - with_money = await self._blockchain_processor.new_blocks_with_money() - blocks = await self._blockchain_processor.blocks(with_identities + with_money) + with_identities = await self._blockchain_processor.new_blocks_with_identities(self.currency) + with_money = await self._blockchain_processor.new_blocks_with_money(self.currency) + blocks = await self._blockchain_processor.blocks(with_identities + with_money, self.currency) self._identities_service.handle_new_blocks(blocks) def parameters(self): diff --git a/src/sakia/services/identities.py b/src/sakia/services/identities.py index 3e35164e7f9175b68210123bcd65cf57451c2ec6..fde264f00bb9634c303182dc47629af00735d8fb 100644 --- a/src/sakia/services/identities.py +++ b/src/sakia/services/identities.py @@ -251,3 +251,21 @@ class IdentitiesService(QObject): if req['uid'] == uid: return req + async def lookup(self, text): + """ + Lookup for a given text in the network and in local db + :param str text: text contained in identity data + :rtype: list[sakia.data.entities.Identity] + :return: the list of identities found + """ + return await self._identities_processor.lookup(self.currency, text) + + def expiration_date(self, identity): + """ + Get the expiration date of the identity + :param sakia.data.entities.Identity identity: + :return: the expiration timestamp + :rtype: int + """ + validity = self._blockchain_processor.parameters(self.currency).ms_validity + return identity.membership_timestamp + validity diff --git a/src/sakia/services/network.py b/src/sakia/services/network.py index 797d8b412fa5f5f9a54a8fd7aa502598c77b9953..9ceb864fb6b5c5f698af5a52772f3421dc96148f 100644 --- a/src/sakia/services/network.py +++ b/src/sakia/services/network.py @@ -241,7 +241,6 @@ class NetworkService(QObject): self._processor.delete_node(node) self.nodes_changed.emit() - @pyqtSlot() def handle_change(self): node_connector = self.sender()