PR feedback: async with host.run()

This commit is contained in:
mhchia
2020-01-26 16:44:42 +08:00
parent dcc4aa52fc
commit 6e01a7da31
8 changed files with 75 additions and 71 deletions

View File

@ -4,7 +4,7 @@ import sys
import multiaddr import multiaddr
import trio import trio
from libp2p import new_host_trio from libp2p import new_host
from libp2p.network.stream.net_stream_interface import INetStream from libp2p.network.stream.net_stream_interface import INetStream
from libp2p.peer.peerinfo import info_from_p2p_addr from libp2p.peer.peerinfo import info_from_p2p_addr
from libp2p.typing import TProtocol from libp2p.typing import TProtocol
@ -34,9 +34,8 @@ async def write_data(stream: INetStream) -> None:
async def run(port: int, destination: str) -> None: async def run(port: int, destination: str) -> None:
localhost_ip = "127.0.0.1" localhost_ip = "127.0.0.1"
listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}") listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}")
async with new_host_trio( host = new_host()
listen_addrs=[listen_addr] async with host.run(listen_addrs=[listen_addr]), trio.open_nursery() as nursery:
) as host, trio.open_nursery() as nursery:
if not destination: # its the server if not destination: # its the server
async def stream_handler(stream: INetStream) -> None: async def stream_handler(stream: INetStream) -> None:

View File

@ -3,7 +3,7 @@ import argparse
import multiaddr import multiaddr
import trio import trio
from libp2p import new_host_trio from libp2p import new_host
from libp2p.crypto.secp256k1 import create_new_key_pair from libp2p.crypto.secp256k1 import create_new_key_pair
from libp2p.network.stream.net_stream_interface import INetStream from libp2p.network.stream.net_stream_interface import INetStream
from libp2p.peer.peerinfo import info_from_p2p_addr from libp2p.peer.peerinfo import info_from_p2p_addr
@ -34,9 +34,8 @@ async def run(port: int, destination: str, seed: int = None) -> None:
secret = secrets.token_bytes(32) secret = secrets.token_bytes(32)
async with new_host_trio( host = new_host(key_pair=create_new_key_pair(secret))
listen_addrs=[listen_addr], key_pair=create_new_key_pair(secret) async with host.run(listen_addrs=[listen_addr]):
) as host:
print(f"I am {host.get_id().to_string()}") print(f"I am {host.get_id().to_string()}")

View File

@ -1,14 +1,9 @@
from typing import AsyncIterator, Sequence
from async_generator import asynccontextmanager
from async_service import background_trio_service
from libp2p.crypto.keys import KeyPair from libp2p.crypto.keys import KeyPair
from libp2p.crypto.rsa import create_new_key_pair from libp2p.crypto.rsa import create_new_key_pair
from libp2p.host.basic_host import BasicHost from libp2p.host.basic_host import BasicHost
from libp2p.host.host_interface import IHost from libp2p.host.host_interface import IHost
from libp2p.host.routed_host import RoutedHost from libp2p.host.routed_host import RoutedHost
from libp2p.network.network_interface import INetwork, INetworkService from libp2p.network.network_interface import INetworkService
from libp2p.network.swarm import Swarm from libp2p.network.swarm import Swarm
from libp2p.peer.id import ID from libp2p.peer.id import ID
from libp2p.peer.peerstore import PeerStore from libp2p.peer.peerstore import PeerStore
@ -32,14 +27,14 @@ def generate_peer_id_from(key_pair: KeyPair) -> ID:
return ID.from_pubkey(public_key) return ID.from_pubkey(public_key)
def initialize_default_swarm( def new_swarm(
key_pair: KeyPair = None, key_pair: KeyPair = None,
muxer_opt: TMuxerOptions = None, muxer_opt: TMuxerOptions = None,
sec_opt: TSecurityOptions = None, sec_opt: TSecurityOptions = None,
peerstore_opt: IPeerStore = None, peerstore_opt: IPeerStore = None,
) -> INetworkService: ) -> INetworkService:
""" """
initialize swarm when no swarm is passed in. Create a swarm instance based on the parameters.
:param key_pair: optional choice of the ``KeyPair`` :param key_pair: optional choice of the ``KeyPair``
:param muxer_opt: optional choice of stream muxer :param muxer_opt: optional choice of stream muxer
@ -48,7 +43,7 @@ def initialize_default_swarm(
:return: return a default swarm instance :return: return a default swarm instance
""" """
if not key_pair: if key_pair is None:
key_pair = generate_new_rsa_identity() key_pair = generate_new_rsa_identity()
id_opt = generate_peer_id_from(key_pair) id_opt = generate_peer_id_from(key_pair)
@ -72,45 +67,32 @@ def initialize_default_swarm(
return Swarm(id_opt, peerstore, upgrader, transport) return Swarm(id_opt, peerstore, upgrader, transport)
def _new_host(swarm_opt: INetwork, disc_opt: IPeerRouting = None) -> IHost: def new_host(
"""
create new libp2p host.
:param swarm_opt: optional swarm
:param disc_opt: optional discovery
:return: return a host instance
"""
# TODO enable support for other host type
# TODO routing unimplemented
host: IHost # If not explicitly typed, MyPy raises error
if disc_opt:
host = RoutedHost(swarm_opt, disc_opt)
else:
host = BasicHost(swarm_opt)
return host
@asynccontextmanager
async def new_host_trio(
listen_addrs: Sequence[str],
key_pair: KeyPair = None, key_pair: KeyPair = None,
swarm_opt: INetwork = None,
muxer_opt: TMuxerOptions = None, muxer_opt: TMuxerOptions = None,
sec_opt: TSecurityOptions = None, sec_opt: TSecurityOptions = None,
peerstore_opt: IPeerStore = None, peerstore_opt: IPeerStore = None,
disc_opt: IPeerRouting = None, disc_opt: IPeerRouting = None,
) -> AsyncIterator[IHost]: ) -> IHost:
swarm = initialize_default_swarm( """
Create a new libp2p host based on the given parameters.
:param key_pair: optional choice of the ``KeyPair``
:param muxer_opt: optional choice of stream muxer
:param sec_opt: optional choice of security upgrade
:param peerstore_opt: optional peerstore
:param disc_opt: optional discovery
:return: return a host instance
"""
swarm = new_swarm(
key_pair=key_pair, key_pair=key_pair,
muxer_opt=muxer_opt, muxer_opt=muxer_opt,
sec_opt=sec_opt, sec_opt=sec_opt,
peerstore_opt=peerstore_opt, peerstore_opt=peerstore_opt,
) )
async with background_trio_service(swarm): host: IHost
await swarm.listen(*listen_addrs) if disc_opt:
host = _new_host(swarm_opt=swarm, disc_opt=disc_opt) host = RoutedHost(swarm, disc_opt)
yield host else:
host = BasicHost(swarm)
return host
# TODO: Support asyncio

View File

@ -1,12 +1,14 @@
import logging import logging
from typing import TYPE_CHECKING, List, Sequence from typing import TYPE_CHECKING, AsyncIterator, List, Sequence
from async_generator import asynccontextmanager
from async_service import background_trio_service
import multiaddr import multiaddr
from libp2p.crypto.keys import PrivateKey, PublicKey from libp2p.crypto.keys import PrivateKey, PublicKey
from libp2p.host.defaults import get_default_protocols from libp2p.host.defaults import get_default_protocols
from libp2p.host.exceptions import StreamFailure from libp2p.host.exceptions import StreamFailure
from libp2p.network.network_interface import INetwork from libp2p.network.network_interface import INetworkService
from libp2p.network.stream.net_stream_interface import INetStream from libp2p.network.stream.net_stream_interface import INetStream
from libp2p.peer.id import ID from libp2p.peer.id import ID
from libp2p.peer.peerinfo import PeerInfo from libp2p.peer.peerinfo import PeerInfo
@ -39,7 +41,7 @@ class BasicHost(IHost):
right after a stream is initialized. right after a stream is initialized.
""" """
_network: INetwork _network: INetworkService
peerstore: IPeerStore peerstore: IPeerStore
multiselect: Multiselect multiselect: Multiselect
@ -47,7 +49,7 @@ class BasicHost(IHost):
def __init__( def __init__(
self, self,
network: INetwork, network: INetworkService,
default_protocols: "OrderedDict[TProtocol, StreamHandlerFn]" = None, default_protocols: "OrderedDict[TProtocol, StreamHandlerFn]" = None,
) -> None: ) -> None:
self._network = network self._network = network
@ -70,7 +72,7 @@ class BasicHost(IHost):
def get_private_key(self) -> PrivateKey: def get_private_key(self) -> PrivateKey:
return self.peerstore.privkey(self.get_id()) return self.peerstore.privkey(self.get_id())
def get_network(self) -> INetwork: def get_network(self) -> INetworkService:
""" """
:return: network instance of host :return: network instance of host
""" """
@ -101,6 +103,20 @@ class BasicHost(IHost):
addrs.append(addr.encapsulate(p2p_part)) addrs.append(addr.encapsulate(p2p_part))
return addrs return addrs
@asynccontextmanager
async def run(
self, listen_addrs: Sequence[multiaddr.Multiaddr]
) -> AsyncIterator[None]:
"""
run the host instance and listen to ``listen_addrs``.
:param listen_addrs: a sequence of multiaddrs that we want to listen to
"""
network = self.get_network()
async with background_trio_service(network):
await network.listen(*listen_addrs)
yield
def set_stream_handler( def set_stream_handler(
self, protocol_id: TProtocol, stream_handler: StreamHandlerFn self, protocol_id: TProtocol, stream_handler: StreamHandlerFn
) -> None: ) -> None:

View File

@ -1,10 +1,10 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import Any, List, Sequence from typing import Any, AsyncContextManager, List, Sequence
import multiaddr import multiaddr
from libp2p.crypto.keys import PrivateKey, PublicKey from libp2p.crypto.keys import PrivateKey, PublicKey
from libp2p.network.network_interface import INetwork from libp2p.network.network_interface import INetworkService
from libp2p.network.stream.net_stream_interface import INetStream from libp2p.network.stream.net_stream_interface import INetStream
from libp2p.peer.id import ID from libp2p.peer.id import ID
from libp2p.peer.peerinfo import PeerInfo from libp2p.peer.peerinfo import PeerInfo
@ -31,7 +31,7 @@ class IHost(ABC):
""" """
@abstractmethod @abstractmethod
def get_network(self) -> INetwork: def get_network(self) -> INetworkService:
""" """
:return: network instance of host :return: network instance of host
""" """
@ -49,6 +49,16 @@ class IHost(ABC):
:return: all the multiaddr addresses this host is listening to :return: all the multiaddr addresses this host is listening to
""" """
@abstractmethod
def run(
self, listen_addrs: Sequence[multiaddr.Multiaddr]
) -> AsyncContextManager[None]:
"""
run the host instance and listen to ``listen_addrs``.
:param listen_addrs: a sequence of multiaddrs that we want to listen to
"""
@abstractmethod @abstractmethod
def set_stream_handler( def set_stream_handler(
self, protocol_id: TProtocol, stream_handler: StreamHandlerFn self, protocol_id: TProtocol, stream_handler: StreamHandlerFn

View File

@ -1,6 +1,6 @@
from libp2p.host.basic_host import BasicHost from libp2p.host.basic_host import BasicHost
from libp2p.host.exceptions import ConnectionFailure from libp2p.host.exceptions import ConnectionFailure
from libp2p.network.network_interface import INetwork from libp2p.network.network_interface import INetworkService
from libp2p.peer.peerinfo import PeerInfo from libp2p.peer.peerinfo import PeerInfo
from libp2p.routing.interfaces import IPeerRouting from libp2p.routing.interfaces import IPeerRouting
@ -10,7 +10,7 @@ from libp2p.routing.interfaces import IPeerRouting
class RoutedHost(BasicHost): class RoutedHost(BasicHost):
_router: IPeerRouting _router: IPeerRouting
def __init__(self, network: INetwork, router: IPeerRouting): def __init__(self, network: INetworkService, router: IPeerRouting):
super().__init__(network) super().__init__(network)
self._router = router self._router = router

View File

@ -1,4 +1,4 @@
from libp2p import initialize_default_swarm from libp2p import new_swarm
from libp2p.crypto.rsa import create_new_key_pair from libp2p.crypto.rsa import create_new_key_pair
from libp2p.host.basic_host import BasicHost from libp2p.host.basic_host import BasicHost
from libp2p.host.defaults import get_default_protocols from libp2p.host.defaults import get_default_protocols
@ -6,7 +6,7 @@ from libp2p.host.defaults import get_default_protocols
def test_default_protocols(): def test_default_protocols():
key_pair = create_new_key_pair() key_pair = create_new_key_pair()
swarm = initialize_default_swarm(key_pair) swarm = new_swarm(key_pair)
host = BasicHost(swarm) host = BasicHost(swarm)
mux = host.get_mux() mux = host.get_mux()

View File

@ -1,7 +1,7 @@
import pytest import pytest
import trio import trio
from libp2p import new_host_trio from libp2p import new_host
from libp2p.crypto.rsa import create_new_key_pair from libp2p.crypto.rsa import create_new_key_pair
from libp2p.security.insecure.transport import InsecureSession, InsecureTransport from libp2p.security.insecure.transport import InsecureSession, InsecureTransport
from libp2p.tools.constants import LISTEN_MADDR from libp2p.tools.constants import LISTEN_MADDR
@ -29,15 +29,13 @@ async def perform_simple_test(
# for testing, we do NOT want to communicate over a stream so we can't just create two nodes # for testing, we do NOT want to communicate over a stream so we can't just create two nodes
# and use their conn because our mplex will internally relay messages to a stream # and use their conn because our mplex will internally relay messages to a stream
async with new_host_trio( node1 = new_host(key_pair=initiator_key_pair, sec_opt=transports_for_initiator)
listen_addrs=[LISTEN_MADDR], node2 = new_host(
key_pair=initiator_key_pair, key_pair=noninitiator_key_pair, sec_opt=transports_for_noninitiator
sec_opt=transports_for_initiator, )
) as node1, new_host_trio( async with node1.run(listen_addrs=[LISTEN_MADDR]), node2.run(
listen_addrs=[LISTEN_MADDR], listen_addrs=[LISTEN_MADDR]
key_pair=noninitiator_key_pair, ):
sec_opt=transports_for_noninitiator,
) as node2:
await connect(node1, node2) await connect(node1, node2)
# Wait a very short period to allow conns to be stored (since the functions # Wait a very short period to allow conns to be stored (since the functions