From 5e8f718f393e4bde5764c42a87641d0d66b34e99 Mon Sep 17 00:00:00 2001 From: inso <insomniak.fr@gmaiL.com> Date: Wed, 26 Oct 2016 07:25:39 +0200 Subject: [PATCH] Network component --- src/sakia/data/connectors/node.py | 1 + src/sakia/data/entities/node.py | 2 + src/sakia/data/repositories/meta.sql | 1 + src/sakia/data/repositories/nodes.py | 2 +- src/sakia/gui/navigation/model.py | 1 + .../gui/navigation/network/controller.py | 5 +- src/sakia/gui/navigation/network/model.py | 30 ++++--- .../gui/navigation/network/table_model.py | 89 +++++++------------ src/sakia/services/network.py | 12 ++- 9 files changed, 70 insertions(+), 73 deletions(-) diff --git a/src/sakia/data/connectors/node.py b/src/sakia/data/connectors/node.py index 53b648f4..8539d7eb 100644 --- a/src/sakia/data/connectors/node.py +++ b/src/sakia/data/connectors/node.py @@ -230,6 +230,7 @@ class NodeConnector(QObject): 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_time = block_data['medianTime'] self._logger.debug("Changed block {0} -> {1}".format(self.node.current_buid.number, block_data['number'])) self.changed.emit() diff --git a/src/sakia/data/entities/node.py b/src/sakia/data/entities/node.py index 27126a3a..e89d9a44 100644 --- a/src/sakia/data/entities/node.py +++ b/src/sakia/data/entities/node.py @@ -59,6 +59,8 @@ class Node: uid = attr.ib(convert=str, cmp=False, default="") # The current block uid in /blockchain/current current_buid = attr.ib(convert=block_uid, cmp=False, default=None) + # The current block time in /blockchain/current + current_time = attr.ib(convert=int, cmp=False, default=0) # The previous block uid in /blockchain/current previous_buid = attr.ib(convert=block_uid, cmp=False, default=None) # The state of the node in Sakia diff --git a/src/sakia/data/repositories/meta.sql b/src/sakia/data/repositories/meta.sql index b77c0d47..6ee5f8a0 100644 --- a/src/sakia/data/repositories/meta.sql +++ b/src/sakia/data/repositories/meta.sql @@ -91,6 +91,7 @@ CREATE TABLE IF NOT EXISTS nodes( peer_buid VARCHAR(100), uid VARCHAR(50), current_buid VARCHAR(100), + current_time INT, previous_buid VARCHAR(100), state INT, software VARCHAR(100), diff --git a/src/sakia/data/repositories/nodes.py b/src/sakia/data/repositories/nodes.py index e7b2a06d..99a1ccd3 100644 --- a/src/sakia/data/repositories/nodes.py +++ b/src/sakia/data/repositories/nodes.py @@ -18,7 +18,7 @@ class NodesRepo: with self._conn: node_tuple = attr.astuple(node, tuple_factory=list) node_tuple[2] = "\n".join([str(n) for n in node_tuple[2]]) - node_tuple[11] = "\n".join([str(n) for n in node_tuple[11]]) + node_tuple[12] = "\n".join([str(n) for n in node_tuple[11]]) values = ",".join(['?'] * len(node_tuple)) self._conn.execute("INSERT INTO nodes VALUES ({0})".format(values), node_tuple) diff --git a/src/sakia/gui/navigation/model.py b/src/sakia/gui/navigation/model.py index 39ce6ccf..794f2b1e 100644 --- a/src/sakia/gui/navigation/model.py +++ b/src/sakia/gui/navigation/model.py @@ -55,6 +55,7 @@ class NavigationModel(ComponentModel): 'title': self.tr('Network'), 'icon': ':/icons/network_icon', 'component': "Network", + 'network_service': self.app.network_services[connection.currency], } }, # { diff --git a/src/sakia/gui/navigation/network/controller.py b/src/sakia/gui/navigation/network/controller.py index 65145dc4..3647fef6 100644 --- a/src/sakia/gui/navigation/network/controller.py +++ b/src/sakia/gui/navigation/network/controller.py @@ -26,11 +26,10 @@ class NetworkController(ComponentController): @classmethod def create(cls, parent, app, **kwargs): - account = kwargs['account'] - community = kwargs['community'] + network_service = kwargs['network_service'] view = NetworkView(parent.view) - model = NetworkModel(None, app, account, community) + model = NetworkModel(None, app, network_service) txhistory = cls(parent, view, model) model.setParent(txhistory) return txhistory diff --git a/src/sakia/gui/navigation/network/model.py b/src/sakia/gui/navigation/network/model.py index f395bfda..1dfd1f0f 100644 --- a/src/sakia/gui/navigation/network/model.py +++ b/src/sakia/gui/navigation/network/model.py @@ -8,23 +8,21 @@ class NetworkModel(ComponentModel): A network model """ - def __init__(self, parent, app, account, community): + def __init__(self, parent, app, network_service): """ Constructor of an network model :param sakia.gui.network.controller.NetworkController parent: the controller - :param sakia.core.Application app: the app - :param sakia.core.Account account: the account - :param sakia.core.Community community: the community + :param sakia.app.Application app: the app + :param sakia.services.NetworkService network_service: the service handling network state """ super().__init__(parent) self.app = app - self.account = account - self.community = community + self.network_service = network_service self.table_model = None def init_network_table_model(self): - model = NetworkTableModel(self.community) + model = NetworkTableModel(self.network_service) proxy = NetworkFilterProxyModel() proxy.setSourceModel(model) self.table_model = proxy @@ -36,7 +34,7 @@ class NetworkModel(ComponentModel): Start the refresh of the nodes :return: """ - self.community.network.refresh_once() + self.network_service.refresh_once() def table_model_data(self, index): """ @@ -49,13 +47,23 @@ class NetworkModel(ComponentModel): is_root_col = self.table_model.sourceModel().columns_types.index('is_root') is_root_index = self.table_model.sourceModel().index(source_index.row(), is_root_col) is_root = self.table_model.sourceModel().data(is_root_index, Qt.DisplayRole) - node = self.community.network.nodes(source_index.row()) + node = self.community.network.nodes()[source_index.row()] return True, node, is_root return False, None, None def add_root_node(self, node): - self.community.network.add_root_node(node) + """ + The node set as root + :param sakia.data.entities.Node node: the node + """ + node.root = True + self.network_service.commit_node(node) def unset_root_node(self, node): - self.community.network.remove_root_node(node) + """ + The node set as root + :param sakia.data.entities.Node node: the node + """ + node.root = False + self.network_service.commit_node(node) diff --git a/src/sakia/gui/navigation/network/table_model.py b/src/sakia/gui/navigation/network/table_model.py index f2fca71f..de931319 100644 --- a/src/sakia/gui/navigation/network/table_model.py +++ b/src/sakia/gui/navigation/network/table_model.py @@ -18,25 +18,10 @@ from sakia.decorators import asyncify, once_at_a_time class NetworkFilterProxyModel(QSortFilterProxyModel): def __init__(self, parent=None): super().__init__(parent) - self.community = None def columnCount(self, parent): return self.sourceModel().columnCount(None) - 2 - def change_community(self, community): - """ - Change current community and returns refresh task - :param sakia.core.Community community: - :return: the refresh task - :rtype: asyncio.Task - """ - self.community = community - return self.sourceModel().change_community(community) - - def setSourceModel(self, sourceModel): - self.community = sourceModel.community - super().setSourceModel(sourceModel) - def lessThan(self, left, right): """ Sort table by given column number. @@ -95,13 +80,6 @@ class NetworkFilterProxyModel(QSortFilterProxyModel): if index.column() == source_model.columns_types.index('current_hash') : return source_data[:10] - if index.column() == source_model.columns_types.index('current_time') and source_data: - return QLocale.toString( - QLocale(), - QDateTime.fromTime_t(source_data), - QLocale.dateTimeFormat(QLocale(), QLocale.ShortFormat) - ) - if role == Qt.TextAlignmentRole: if source_index.column() == source_model.columns_types.index('address') or source_index.column() == self.sourceModel().columns_types.index('current_block'): return Qt.AlignRight | Qt.AlignVCenter @@ -124,18 +102,19 @@ class NetworkTableModel(QAbstractTableModel): A Qt abstract item model to display """ - def __init__(self, community, parent=None): + def __init__(self, network_service, parent=None): """ - Constructor + The table showing nodes + :param sakia.services.NetworkService network_service: + :param parent: """ super().__init__(parent) - self.community = community + self.network_service = network_service self.columns_types = ( 'address', 'port', 'current_block', 'current_hash', - 'current_time', 'uid', 'is_member', 'pubkey', @@ -163,48 +142,44 @@ class NetworkTableModel(QAbstractTableModel): Node.CORRUPTED: lambda: self.tr('Corrupted') } self.nodes_data = [] - self.community.network.nodes_changed.connect(self.refresh_nodes) + self.network_service.nodes_changed.connect(self.refresh_nodes) - async def data_node(self, node: Node) -> tuple: + def data_node(self, node: Node) -> tuple: """ Return node data tuple :param ..core.net.node.Node node: Network node :return: """ - try: - members_pubkey = await self.community.members_pubkeys() - is_member = node.pubkey in members_pubkey - except NoPeerAvailable as e: - logging.error(e) - is_member = None - - address = "" - if node.endpoint.server: - address = node.endpoint.server - elif node.endpoint.ipv4: - address = node.endpoint.ipv4 - elif node.endpoint.ipv6: - address = node.endpoint.ipv6 - port = node.endpoint.port - - is_root = self.community.network.is_root_node(node) - if node.block: - number, block_hash, block_time = node.block['number'], node.block['hash'], node.block['medianTime'] + is_member = False + + addresses = [] + ports = [] + for e in node.endpoints: + if e.server: + addresses.append(e.server) + elif e.ipv4: + addresses.append(e.ipv4) + elif e.ipv6: + addresses.append(e.ipv6) + ports.append(str(e.port)) + address = "\n".join(addresses) + port = "\n".join(ports) + + is_root = node.root + if node.current_buid: + number, block_hash = node.current_buid.number, node.current_buid.hash else: - number, block_hash, block_time = "", "", "" - return (address, port, number, block_hash, block_time, node.uid, - is_member, node.pubkey, node.software, node.version, is_root, node.state) + number, block_hash = "", "" + return (address, port, number, block_hash, node.uid, + is_member, node.pubkey, node.software, node.version, node.root, node.state) - @once_at_a_time - @asyncify - async def refresh_nodes(self): + def refresh_nodes(self): self.beginResetModel() self.nodes_data = [] nodes_data = [] - if self.community: - for node in self.community.network.nodes: - data = await self.data_node(node) - nodes_data.append(data) + for node in self.network_service.nodes(): + data = self.data_node(node) + nodes_data.append(data) self.nodes_data = nodes_data self.endResetModel() diff --git a/src/sakia/services/network.py b/src/sakia/services/network.py index 0e200a03..bdb0da83 100644 --- a/src/sakia/services/network.py +++ b/src/sakia/services/network.py @@ -83,6 +83,16 @@ class NetworkService(QObject): """ asyncio.ensure_future(self.discover_network()) + def nodes(self): + """ + Get all nodes + :return: + """ + return self._processor.nodes(self.currency) + + def commit_node(self, node): + self._processor.commit_node(node) + async def stop_coroutines(self, closing=False): """ Stop network nodes crawling. @@ -227,7 +237,7 @@ class NetworkService(QObject): if node.state in (Node.OFFLINE, Node.CORRUPTED) and \ node.last_change + 3600 < time.time(): node.disconnect() - self.nodes.remove(node) + self._processor.delete_node(node) self.nodes_changed.emit() @pyqtSlot() -- GitLab