From 3c17ee16f06c8ab89dc502568c4fe1521c61504b Mon Sep 17 00:00:00 2001
From: Inso <insomniak.fr@gmail.com>
Date: Sat, 23 Jan 2016 19:46:46 +0100
Subject: [PATCH] Add peer to node files

---
 src/sakia/core/account.py     |  9 ++++-
 src/sakia/core/app.py         |  3 +-
 src/sakia/core/community.py   | 15 ++------
 src/sakia/core/net/network.py | 13 +++++--
 src/sakia/core/net/node.py    | 69 ++++++++++++++++++++---------------
 5 files changed, 60 insertions(+), 49 deletions(-)

diff --git a/src/sakia/core/account.py b/src/sakia/core/account.py
index 386788b2..820f0604 100644
--- a/src/sakia/core/account.py
+++ b/src/sakia/core/account.py
@@ -11,6 +11,7 @@ from ucoinpy.key import SigningKey
 import logging
 import time
 import asyncio
+from distutils.version import StrictVersion
 
 from PyQt5.QtCore import QObject, pyqtSignal
 
@@ -18,7 +19,7 @@ from . import money
 from .wallet import Wallet
 from .community import Community
 from .registry import LocalState
-from ..tools.exceptions import ContactAlreadyExists, NoPeerAvailable
+from ..tools.exceptions import ContactAlreadyExists
 from ucoinpy.api import bma
 from ucoinpy.api.bma import PROTOCOL_VERSION
 from aiohttp.errors import ClientError
@@ -102,6 +103,10 @@ class Account(QObject):
         """
         salt = json_data['salt']
         pubkey = json_data['pubkey']
+        if 'version' in json_data:
+            version = StrictVersion(json_data['version'])
+        else:
+            version = StrictVersion('0.11.5')
 
         name = json_data['name']
         contacts = []
@@ -115,7 +120,7 @@ class Account(QObject):
 
         communities = []
         for data in json_data['communities']:
-            community = Community.load(data)
+            community = Community.load(data, version)
             communities.append(community)
 
         account = cls(salt, pubkey, name, communities, wallets,
diff --git a/src/sakia/core/app.py b/src/sakia/core/app.py
index 8feedba6..a5ac832e 100644
--- a/src/sakia/core/app.py
+++ b/src/sakia/core/app.py
@@ -11,6 +11,7 @@ import shutil
 import json
 import datetime
 import aiohttp
+from distutils.version import StrictVersion
 
 from PyQt5.QtCore import QObject, pyqtSignal, QTranslator, QCoreApplication, QLocale
 from ucoinpy.api.bma import API
@@ -278,7 +279,7 @@ class Application(QObject):
                 with open(network_path, 'r') as json_data:
                     data = json.load(json_data)
                     logging.debug("Merging network : {0}".format(data))
-                    community.network.merge_with_json(data['network'])
+                    community.network.merge_with_json(data['network'], StrictVersion(data['version']))
 
             if os.path.exists(bma_path):
                 with open(bma_path, 'r') as json_data:
diff --git a/src/sakia/core/community.py b/src/sakia/core/community.py
index e9104305..2a368bc3 100644
--- a/src/sakia/core/community.py
+++ b/src/sakia/core/community.py
@@ -57,28 +57,19 @@ class Community(QObject):
         return community
 
     @classmethod
-    def load(cls, json_data):
+    def load(cls, json_data, version):
         """
         Load a community from json
 
         :param dict json_data: The community as a dict in json format
+        :param distutils.version.StrictVersion version: the file sakia version
         """
         currency = json_data['currency']
-        network = Network.from_json(currency, json_data['peers'])
+        network = Network.from_json(currency, json_data['peers'], version)
         bma_access = BmaAccess.create(network)
         community = cls(currency, network, bma_access)
         return community
 
-    def load_cache(self, bma_access_cache, network_cache):
-        """
-        Load the community cache.
-
-        :param dict bma_access_cache: The BmaAccess cache in json
-        :param dict network_cache: The network cache in json
-        """
-        self._bma_access.load_from_json(bma_access_cache)
-        self._network.merge_with_json(network_cache)
-
     @property
     def name(self):
         """
diff --git a/src/sakia/core/net/network.py b/src/sakia/core/net/network.py
index eeb9d3a5..4ca32327 100644
--- a/src/sakia/core/net/network.py
+++ b/src/sakia/core/net/network.py
@@ -57,15 +57,16 @@ class Network(QObject):
         network = cls(node.currency, nodes)
         return network
 
-    def merge_with_json(self, json_data):
+    def merge_with_json(self, json_data, file_version):
         """
         We merge with knew nodes when we
         last stopped sakia
 
         :param dict json_data: Nodes in json format
+        :param distutils.version.StrictVersion file_version: The node version
         """
         for data in json_data:
-            node = Node.from_json(self.currency, data)
+            node = Node.from_json(self.currency, data, file_version)
             if node.pubkey not in [n.pubkey for n in self.nodes]:
                 self.add_node(node)
                 logging.debug("Loading : {:}".format(data['pubkey']))
@@ -74,6 +75,7 @@ class Network(QObject):
                 other_node._uid = node.uid
                 other_node._version = node.version
                 other_node._software = node.software
+                other_node._peer = node.peer
                 switch = False
                 if other_node.block and node.block:
                     if other_node.block['hash'] != node.block['hash']:
@@ -86,16 +88,17 @@ class Network(QObject):
                     other_node.state = node.state
 
     @classmethod
-    def from_json(cls, currency, json_data):
+    def from_json(cls, currency, json_data, version):
         """
         Load a network from a configured community
 
         :param str currency: The currency name of a community
         :param dict json_data: A json_data view of a network
+        :param distutils.version.StrictVersion version: the version of the json file
         """
         nodes = []
         for data in json_data:
-            node = Node.from_json(currency, data)
+            node = Node.from_json(currency, data, version)
             nodes.append(node)
         network = cls(currency, nodes)
         return network
@@ -340,6 +343,8 @@ class Network(QObject):
                 self.nodes_changed.emit()
             except InvalidNodeCurrency as e:
                 logging.debug(str(e))
+        else:
+            node = [n for n in self.nodes if n.pubkey == pubkey][0]
 
     @pyqtSlot()
     def handle_identity_change(self):
diff --git a/src/sakia/core/net/node.py b/src/sakia/core/net/node.py
index 348aa406..1b2a8341 100644
--- a/src/sakia/core/net/node.py
+++ b/src/sakia/core/net/node.py
@@ -5,18 +5,18 @@ Created on 21 févr. 2015
 """
 
 from ucoinpy.documents.peer import Peer, Endpoint, BMAEndpoint
+from ucoinpy.documents import Block
 from ...tools.exceptions import InvalidNodeCurrency
 from ...tools.decorators import asyncify
 from ucoinpy.api import bma as bma
 from ucoinpy.api.bma import ConnectionHandler
 
-import asyncio
 from aiohttp.errors import ClientError, DisconnectedError
 from asyncio import TimeoutError
 import logging
 import time
 import jsonschema
-import aiohttp
+from distutils.version import StrictVersion
 from socket import gaierror
 
 from PyQt5.QtCore import QObject, pyqtSignal
@@ -42,20 +42,19 @@ class Node(QObject):
     identity_changed = pyqtSignal()
     neighbour_found = pyqtSignal(Peer, str)
 
-    def __init__(self, currency, endpoints, uid, pubkey, block,
+    def __init__(self, peer, uid, pubkey, block,
                  state, last_change, last_merkle, software, version, fork_window):
         """
         Constructor
         """
         super().__init__()
-        self._endpoints = endpoints
+        self._peer = peer
         self._uid = uid
         self._pubkey = pubkey
         self._block = block
         self.main_chain_previous_block = None
         self._state = state
         self._neighbours = []
-        self._currency = currency
         self._last_change = last_change
         self._last_merkle = last_merkle
         self._software = software
@@ -84,8 +83,7 @@ class Node(QObject):
             if peer.currency != currency:
                 raise InvalidNodeCurrency(peer.currency, currency)
 
-        node = cls(peer.currency,
-                   [Endpoint.from_inline(e.inline()) for e in peer.endpoints],
+        node = cls(peer,
                    "", peer.pubkey, None, Node.ONLINE, time.time(),
                    {'root': "", 'leaves': []}, "", "", 0)
         logging.debug("Node from address : {:}".format(str(node)))
@@ -106,8 +104,7 @@ class Node(QObject):
             if peer.currency != currency:
                 raise InvalidNodeCurrency(peer.currency, currency)
 
-        node = cls(peer.currency, peer.endpoints,
-                   "", pubkey, None,
+        node = cls(peer, "", pubkey, None,
                    Node.OFFLINE, time.time(),
                    {'root': "", 'leaves': []},
                    "", "", 0)
@@ -115,7 +112,16 @@ class Node(QObject):
         return node
 
     @classmethod
-    def from_json(cls, currency, data):
+    def from_json(cls, currency, data, file_version):
+        """
+        Loads a node from json data
+
+        :param str currency: the currency of the community
+        :param dict data: the json data of the node
+        :param StrictVersion file_version: the version of the file
+        :return: A new node
+        :rtype: Node
+        """
         endpoints = []
         uid = ""
         pubkey = ""
@@ -126,12 +132,6 @@ class Node(QObject):
         last_change = time.time()
         state = Node.OFFLINE
         logging.debug(data)
-        for endpoint_data in data['endpoints']:
-            endpoints.append(Endpoint.from_inline(endpoint_data))
-
-        if currency in data:
-            currency = data['currency']
-
         if 'uid' in data:
             uid = data['uid']
 
@@ -156,11 +156,23 @@ class Node(QObject):
         if 'fork_window' in data:
             fork_window = data['fork_window']
 
-        node = cls(currency, endpoints,
-                   uid, pubkey, block,
+        if file_version < StrictVersion("0.12"):
+            for endpoint_data in data['endpoints']:
+                endpoints.append(Endpoint.from_inline(endpoint_data))
+
+            if currency in data:
+                currency = data['currency']
+
+            peer = Peer("1", currency, pubkey, "0-{0}".format(Block.Empty_Hash), endpoints, "SOMEFAKESIGNATURE")
+        else:
+            if 'peer' in data:
+                peer = Peer.from_signed_raw(data['peer'])
+
+        node = cls(peer, uid, pubkey, block,
                    state, last_change,
                    {'root': "", 'leaves': []},
                    software, version, fork_window)
+
         logging.debug("Node from json : {:}".format(str(node)))
         return node
 
@@ -168,18 +180,15 @@ class Node(QObject):
         logging.debug("Saving root node : {:}".format(str(self)))
         data = {'pubkey': self._pubkey,
                 'uid': self._uid,
-                'currency': self._currency}
-        endpoints = []
-        for e in self._endpoints:
-            endpoints.append(e.inline())
-        data['endpoints'] = endpoints
+                'currency': self._currency,
+                'peer': self._peer.signed_raw()}
         return data
 
     def jsonify(self):
         logging.debug("Saving node : {:}".format(str(self)))
         data = {'pubkey': self._pubkey,
                 'uid': self._uid,
-                'currency': self._currency,
+                'peer': self._peer.signed_raw(),
                 'state': self._state,
                 'last_change': self._last_change,
                 'block': self.block,
@@ -187,10 +196,6 @@ class Node(QObject):
                 'version': self._version,
                 'fork_window': self._fork_window
                 }
-        endpoints = []
-        for e in self._endpoints:
-            endpoints.append(e.inline())
-        data['endpoints'] = endpoints
         return data
 
     @property
@@ -199,7 +204,7 @@ class Node(QObject):
 
     @property
     def endpoint(self) -> BMAEndpoint:
-        return next((e for e in self._endpoints if type(e) is BMAEndpoint))
+        return next((e for e in self._peer.endpoints if type(e) is BMAEndpoint))
 
     @property
     def block(self):
@@ -214,7 +219,7 @@ class Node(QObject):
 
     @property
     def currency(self):
-        return self._currency
+        return self._peer.currency
 
     @property
     def neighbours(self):
@@ -232,6 +237,10 @@ class Node(QObject):
     def software(self):
         return self._software
 
+    @property
+    def peer(self):
+        return self._peer
+
     @software.setter
     def software(self, new_soft):
         if self._software != new_soft:
-- 
GitLab