Shifting things around a bit, introducing ProxyRESTRoutes, and starting to implmenet rest_information().

pull/424/head
jMyles 2018-08-30 17:12:37 +02:00
parent a6baa8c2c7
commit d2250b2a84
4 changed files with 63 additions and 61 deletions

View File

@ -1092,12 +1092,12 @@ class Ursula(Character, VerifiableNode, Miner):
blockchain_power = BlockchainPower(blockchain=self.blockchain, account=self.checksum_public_address) blockchain_power = BlockchainPower(blockchain=self.blockchain, account=self.checksum_public_address)
self._crypto_power.consume_power_up(blockchain_power) self._crypto_power.consume_power_up(blockchain_power)
rest_server = ProxyRESTServer( rest_server = ProxyRESTServer(
rest_host=rest_host, rest_host=rest_host,
rest_port=rest_port, rest_port=rest_port,
db_name=db_name, db_name=db_name,
tls_private_key=tls_private_key,
tls_curve=tls_curve,
) )
tls_hosting_keypair = HostingKeypair( tls_hosting_keypair = HostingKeypair(
@ -1117,9 +1117,18 @@ class Ursula(Character, VerifiableNode, Miner):
if not federated_only: if not federated_only:
self.substantiate_stamp() self.substantiate_stamp()
def rest_information(self):
hosting_power = self._crypto_power.power_ups(TLSHostingPower)
return (
hosting_power.rest_server.rest_interface,
hosting_power.keypair.certificate,
hosting_power.keypair.pubkey
)
def __bytes__(self): def __bytes__(self):
interface_info = VariableLengthBytestring(self.rest_interface) interface_info = VariableLengthBytestring(self.rest_information()[0])
if self.dht_interface: if self.dht_interface:
interface_info += VariableLengthBytestring(self.dht_interface) interface_info += VariableLengthBytestring(self.dht_interface)
@ -1218,11 +1227,13 @@ class Ursula(Character, VerifiableNode, Miner):
@property @property
def rest_app(self): def rest_app(self):
if not self._rest_app: rest_app_on_server = self._crypto_power.power_ups(TLSHostingPower).rest_server._rest_app
if not rest_app_on_server:
m = "This Ursula doesn't have a REST app attached. If you want one, init with is_me and attach_server." m = "This Ursula doesn't have a REST app attached. If you want one, init with is_me and attach_server."
raise AttributeError(m) raise AttributeError(m)
else: else:
return self._rest_app return rest_app_on_server
def interface_info_with_metadata(self): def interface_info_with_metadata(self):
# TODO: Do we ever actually use this without using the rest of the serialized Ursula? 337 # TODO: Do we ever actually use this without using the rest of the serialized Ursula? 337

View File

@ -87,8 +87,8 @@ class VerifiableNode:
self.validate_metadata(accept_federated_only) # This is both the stamp and interface check. self.validate_metadata(accept_federated_only) # This is both the stamp and interface check.
# The node's metadata is valid; let's be sure the interface is in order. # The node's metadata is valid; let's be sure the interface is in order.
response = network_middleware.node_information(host=self.rest_interface.host, response = network_middleware.node_information(host=self.rest_information()[0].host,
port=self.rest_interface.port) port=self.rest_information()[0].port)
if not response.status_code == 200: if not response.status_code == 200:
raise RuntimeError("Or something.") # TODO: Raise an error here? Or return False? Or something? raise RuntimeError("Or something.") # TODO: Raise an error here? Or return False? Or something?
signature, identity_evidence, verifying_key, encrypting_key, public_address, rest_info, dht_info = self._internal_splitter(response.content) signature, identity_evidence, verifying_key, encrypting_key, public_address, rest_info, dht_info = self._internal_splitter(response.content)
@ -112,7 +112,7 @@ class VerifiableNode:
self._evidence_of_decentralized_identity = signature self._evidence_of_decentralized_identity = signature
def _signable_interface_info_message(self): def _signable_interface_info_message(self):
message = self.canonical_public_address + self.rest_interface + self.dht_interface message = self.canonical_public_address + self.rest_information()[0] + self.dht_interface
return message return message
def _sign_interface_info(self): def _sign_interface_info(self):

View File

@ -1,7 +1,7 @@
import asyncio import asyncio
import binascii import binascii
import random import random
from typing import ClassVar from logging import getLogger
import kademlia import kademlia
from apistar import http, Route, App from apistar import http, Route, App
@ -101,33 +101,47 @@ class NucypherSeedOnlyDHTServer(NucypherDHTServer):
class ProxyRESTServer: class ProxyRESTServer:
log = getLogger("characters")
def __init__(self, def __init__(self,
rest_host=None, rest_host,
rest_port=None, rest_port,
db_name=None, routes,
tls_private_key=None, ) -> None:
tls_curve=None,
certificate=None,
common_name=None,
*args, ** kwargs) -> None:
self.rest_interface = InterfaceInfo(host=rest_host, port=rest_port) self.rest_interface = InterfaceInfo(host=rest_host, port=rest_port)
def start_datastore(self, db_name):
if not db_name:
raise TypeError("In order to start a datastore, you need to supply a db_name.")
from nucypher.keystore import keystore
from nucypher.keystore.db import Base
from sqlalchemy.engine import create_engine
self.log.info("Starting datastore {}".format(db_name))
engine = create_engine('sqlite:///{}'.format(db_name))
Base.metadata.create_all(engine)
self.datastore = keystore.KeyStore(engine)
self.db_engine = engine
def rest_url(self):
return "{}:{}".format(self.rest_information()[0].host, self.rest_information()[0].port)
#####################################
# Actual REST Endpoints and utilities
#####################################
def get_deployer(self):
deployer = self._crypto_power.power_ups(TLSHostingPower).get_deployer(rest_app=self._rest_app,
port=self.rest_information()[0].port)
return deployer
class ProxyRESTRoutes:
def __init__(self, db_name=None):
self.db_name = db_name self.db_name = db_name
self._rest_app = None
def public_material(self, power_class: ClassVar):
"""Implemented on Ursula"""
raise NotImplementedError
def canonical_public_address(self):
"""Implemented on Ursula"""
raise NotImplementedError
def stamp(self, *args, **kwargs):
"""Implemented on Ursula"""
raise NotImplementedError
def attach_rest_server(self):
routes = [ routes = [
Route('/kFrag/{id_as_hex}', Route('/kFrag/{id_as_hex}',
@ -156,27 +170,6 @@ class ProxyRESTServer:
self._rest_app = App(routes=routes) self._rest_app = App(routes=routes)
self.start_datastore(self.db_name) self.start_datastore(self.db_name)
def start_datastore(self, db_name):
if not db_name:
raise TypeError("In order to start a datastore, you need to supply a db_name.")
from nucypher.keystore import keystore
from nucypher.keystore.db import Base
from sqlalchemy.engine import create_engine
self.log.info("Starting datastore {}".format(db_name))
engine = create_engine('sqlite:///{}'.format(db_name))
Base.metadata.create_all(engine)
self.datastore = keystore.KeyStore(engine)
self.db_engine = engine
def rest_url(self):
return "{}:{}".format(self.rest_interface.host, self.rest_interface.port)
#####################################
# Actual REST Endpoints and utilities
#####################################
def public_information(self): def public_information(self):
""" """
REST endpoint for public keys and address.. REST endpoint for public keys and address..
@ -331,11 +324,6 @@ class ProxyRESTServer:
self.log.info("Bad TreasureMap ID; not storing {}".format(treasure_map_id)) self.log.info("Bad TreasureMap ID; not storing {}".format(treasure_map_id))
assert False assert False
def get_deployer(self):
deployer = self._crypto_power.power_ups(TLSHostingPower).get_deployer(rest_app=self._rest_app,
port=self.rest_interface.port)
return deployer
class TLSHostingPower(KeyPairBasedPower): class TLSHostingPower(KeyPairBasedPower):
_keypair_class = HostingKeypair _keypair_class = HostingKeypair

View File

@ -96,7 +96,10 @@ def make_ursulas(ether_addresses: list,
ursula.federated_only = True ursula.federated_only = True
ursulas.add(ursula) ursulas.add(ursula)
_TEST_KNOWN_URSULAS_CACHE[ursula.rest_information().port] = ursula
# Store this Ursula in our global cache.
port = ursula.rest_information()[0].port
_TEST_KNOWN_URSULAS_CACHE[port] = ursula
if know_each_other and not bare: if know_each_other and not bare:
@ -108,7 +111,7 @@ def make_ursulas(ether_addresses: list,
event_loop.run_until_complete( event_loop.run_until_complete(
ursula.dht_server.bootstrap( ursula.dht_server.bootstrap(
[("localhost", starting_port + _c) for _c in range(len(ursulas))])) [("localhost", starting_port + _c) for _c in range(len(ursulas))]))
ursula.publish_dht_information() # ursula.publish_dht_information()
return ursulas return ursulas