mirror of
https://github.com/varun-r-mallya/py-libp2p.git
synced 2025-12-31 20:36:24 +00:00
* refactored : host_interface Co-authored-by: mystical-prog <jdgt.vd.0405@gmail.com> * refactored : network_interface Co-authored-by: mystical-prog <jdgt.vd.0405@gmail.com> * refactored : notifee_interface Co-authored-by: mystical-prog <jdgt.vd.0405@gmail.com> * refactored : net_connection_interface Co-authored-by: mystical-prog <jdgt.vd.0405@gmail.com> * refactored: raw_connection_interface, secure_conn_interface and stream_muxer abc.py * refactored: addrbook_interface * refactored :peerdata_interface Co-authored-by: mystical-prog <jdgt.vd.0405@gmail.com> * refactored :peermetadata_interface Co-authored-by: mystical-prog <jdgt.vd.0405@gmail.com> * refactored :multiselect_client_interface Co-authored-by: mystical-prog <jdgt.vd.0405@gmail.com> * refactored :multiselect_communicator_interface Co-authored-by: mystical-prog <jdgt.vd.0405@gmail.com> * refactored :multiselect_muxer_interface Co-authored-by: mystical-prog <jdgt.vd.0405@gmail.com> * refactored :interfaces Co-authored-by: mystical-prog <jdgt.vd.0405@gmail.com> * refactored :security_transport_interface Co-authored-by: mystical-prog <jdgt.vd.0405@gmail.com> * refactored :listener_interface Co-authored-by: mystical-prog <jdgt.vd.0405@gmail.com> * moved all interfaces and typing files Co-authored-by: mystical-prog <jdgt.vd.0405@gmail.com> * fixed documentation and moved pubsub abc.py Co-authored-by: Khwahish Patel <khwahish.p1@ahduni.edu.in> * added exclude-members in custom_types docs * added : newsfragment for moving all interfaces to libp2p.abc --------- Co-authored-by: mystical-prog <jdgt.vd.0405@gmail.com> Co-authored-by: Mystical <125946525+mystical-prog@users.noreply.github.com>
1051 lines
28 KiB
Python
1051 lines
28 KiB
Python
from abc import (
|
|
ABC,
|
|
abstractmethod,
|
|
)
|
|
from collections.abc import (
|
|
AsyncIterable,
|
|
Iterable,
|
|
KeysView,
|
|
Sequence,
|
|
)
|
|
from typing import (
|
|
TYPE_CHECKING,
|
|
Any,
|
|
AsyncContextManager,
|
|
)
|
|
|
|
from multiaddr import (
|
|
Multiaddr,
|
|
)
|
|
import trio
|
|
|
|
from libp2p.crypto.keys import (
|
|
KeyPair,
|
|
PrivateKey,
|
|
PublicKey,
|
|
)
|
|
from libp2p.custom_types import (
|
|
StreamHandlerFn,
|
|
THandler,
|
|
TProtocol,
|
|
ValidatorFn,
|
|
)
|
|
from libp2p.io.abc import (
|
|
Closer,
|
|
ReadWriteCloser,
|
|
)
|
|
from libp2p.peer.id import (
|
|
ID,
|
|
)
|
|
from libp2p.peer.peerinfo import (
|
|
PeerInfo,
|
|
)
|
|
|
|
if TYPE_CHECKING:
|
|
from libp2p.pubsub.pubsub import (
|
|
Pubsub,
|
|
)
|
|
|
|
from libp2p.pubsub.pb import (
|
|
rpc_pb2,
|
|
)
|
|
from libp2p.tools.async_service import (
|
|
ServiceAPI,
|
|
)
|
|
|
|
# -------------------------- raw_connection interface.py --------------------------
|
|
|
|
|
|
class IRawConnection(ReadWriteCloser):
|
|
"""A Raw Connection provides a Reader and a Writer."""
|
|
|
|
is_initiator: bool
|
|
|
|
|
|
# -------------------------- secure_conn interface.py --------------------------
|
|
|
|
|
|
"""
|
|
Represents a secured connection object, which includes a connection and details about
|
|
the security involved in the secured connection
|
|
|
|
Relevant go repo: https://github.com/libp2p/go-conn-security/blob/master/interface.go
|
|
"""
|
|
|
|
|
|
class AbstractSecureConn(ABC):
|
|
@abstractmethod
|
|
def get_local_peer(self) -> ID:
|
|
pass
|
|
|
|
@abstractmethod
|
|
def get_local_private_key(self) -> PrivateKey:
|
|
pass
|
|
|
|
@abstractmethod
|
|
def get_remote_peer(self) -> ID:
|
|
pass
|
|
|
|
@abstractmethod
|
|
def get_remote_public_key(self) -> PublicKey:
|
|
pass
|
|
|
|
|
|
class ISecureConn(AbstractSecureConn, IRawConnection):
|
|
pass
|
|
|
|
|
|
# -------------------------- stream_muxer abc.py --------------------------
|
|
|
|
|
|
class IMuxedConn(ABC):
|
|
"""
|
|
reference: https://github.com/libp2p/go-stream-muxer/blob/master/muxer.go
|
|
"""
|
|
|
|
peer_id: ID
|
|
event_started: trio.Event
|
|
|
|
@abstractmethod
|
|
def __init__(self, conn: ISecureConn, peer_id: ID) -> None:
|
|
"""
|
|
Create a new muxed connection.
|
|
|
|
:param conn: an instance of secured connection
|
|
for new muxed streams
|
|
:param peer_id: peer_id of peer the connection is to
|
|
"""
|
|
|
|
@property
|
|
@abstractmethod
|
|
def is_initiator(self) -> bool:
|
|
"""If this connection is the initiator."""
|
|
|
|
@abstractmethod
|
|
async def start(self) -> None:
|
|
"""Start the multiplexer."""
|
|
|
|
@abstractmethod
|
|
async def close(self) -> None:
|
|
"""Close connection."""
|
|
|
|
@property
|
|
@abstractmethod
|
|
def is_closed(self) -> bool:
|
|
"""
|
|
Check connection is fully closed.
|
|
|
|
:return: true if successful
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def open_stream(self) -> "IMuxedStream":
|
|
"""
|
|
Create a new muxed_stream.
|
|
|
|
:return: a new ``IMuxedStream`` stream
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def accept_stream(self) -> "IMuxedStream":
|
|
"""Accept a muxed stream opened by the other end."""
|
|
|
|
|
|
class IMuxedStream(ReadWriteCloser):
|
|
muxed_conn: IMuxedConn
|
|
|
|
@abstractmethod
|
|
async def reset(self) -> None:
|
|
"""Close both ends of the stream tells this remote side to hang up."""
|
|
|
|
@abstractmethod
|
|
def set_deadline(self, ttl: int) -> bool:
|
|
"""
|
|
Set deadline for muxed stream.
|
|
|
|
:return: a new stream
|
|
"""
|
|
|
|
|
|
# -------------------------- net_stream interface.py --------------------------
|
|
|
|
|
|
class INetStream(ReadWriteCloser):
|
|
muxed_conn: IMuxedConn
|
|
|
|
@abstractmethod
|
|
def get_protocol(self) -> TProtocol:
|
|
"""
|
|
:return: protocol id that stream runs on
|
|
"""
|
|
|
|
@abstractmethod
|
|
def set_protocol(self, protocol_id: TProtocol) -> None:
|
|
"""
|
|
:param protocol_id: protocol id that stream runs on
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def reset(self) -> None:
|
|
"""Close both ends of the stream."""
|
|
|
|
|
|
# -------------------------- net_connection interface.py --------------------------
|
|
|
|
|
|
class INetConn(Closer):
|
|
muxed_conn: IMuxedConn
|
|
event_started: trio.Event
|
|
|
|
@abstractmethod
|
|
async def new_stream(self) -> INetStream:
|
|
...
|
|
|
|
@abstractmethod
|
|
def get_streams(self) -> tuple[INetStream, ...]:
|
|
...
|
|
|
|
|
|
# -------------------------- peermetadata interface.py --------------------------
|
|
|
|
|
|
class IPeerMetadata(ABC):
|
|
@abstractmethod
|
|
def get(self, peer_id: ID, key: str) -> Any:
|
|
"""
|
|
:param peer_id: peer ID to lookup key for
|
|
:param key: key to look up
|
|
:return: value at key for given peer
|
|
:raise Exception: peer ID not found
|
|
"""
|
|
|
|
@abstractmethod
|
|
def put(self, peer_id: ID, key: str, val: Any) -> None:
|
|
"""
|
|
:param peer_id: peer ID to lookup key for
|
|
:param key: key to associate with peer
|
|
:param val: value to associated with key
|
|
:raise Exception: unsuccessful put
|
|
"""
|
|
|
|
|
|
# -------------------------- addrbook interface.py --------------------------
|
|
|
|
|
|
class IAddrBook(ABC):
|
|
@abstractmethod
|
|
def add_addr(self, peer_id: ID, addr: Multiaddr, ttl: int) -> None:
|
|
"""
|
|
Calls add_addrs(peer_id, [addr], ttl)
|
|
|
|
:param peer_id: the peer to add address for
|
|
:param addr: multiaddress of the peer
|
|
:param ttl: time-to-live for the address (after this time, address is no longer valid)
|
|
""" # noqa: E501
|
|
|
|
@abstractmethod
|
|
def add_addrs(self, peer_id: ID, addrs: Sequence[Multiaddr], ttl: int) -> None:
|
|
"""
|
|
Adds addresses for a given peer all with the same time-to-live. If one
|
|
of the addresses already exists for the peer and has a longer TTL, no
|
|
operation should take place. If one of the addresses exists with a
|
|
shorter TTL, extend the TTL to equal param ttl.
|
|
|
|
:param peer_id: the peer to add address for
|
|
:param addr: multiaddresses of the peer
|
|
:param ttl: time-to-live for the address (after this time, address is no longer valid
|
|
""" # noqa: E501
|
|
|
|
@abstractmethod
|
|
def addrs(self, peer_id: ID) -> list[Multiaddr]:
|
|
"""
|
|
:param peer_id: peer to get addresses of
|
|
:return: all known (and valid) addresses for the given peer
|
|
"""
|
|
|
|
@abstractmethod
|
|
def clear_addrs(self, peer_id: ID) -> None:
|
|
"""
|
|
Removes all previously stored addresses.
|
|
|
|
:param peer_id: peer to remove addresses of
|
|
"""
|
|
|
|
@abstractmethod
|
|
def peers_with_addrs(self) -> list[ID]:
|
|
"""
|
|
:return: all of the peer IDs stored with addresses
|
|
"""
|
|
|
|
|
|
# -------------------------- peerstore interface.py --------------------------
|
|
|
|
|
|
class IPeerStore(IAddrBook, IPeerMetadata):
|
|
@abstractmethod
|
|
def peer_info(self, peer_id: ID) -> PeerInfo:
|
|
"""
|
|
:param peer_id: peer ID to get info for
|
|
:return: peer info object
|
|
"""
|
|
|
|
@abstractmethod
|
|
def get_protocols(self, peer_id: ID) -> list[str]:
|
|
"""
|
|
:param peer_id: peer ID to get protocols for
|
|
:return: protocols (as list of strings)
|
|
:raise PeerStoreError: if peer ID not found
|
|
"""
|
|
|
|
@abstractmethod
|
|
def add_protocols(self, peer_id: ID, protocols: Sequence[str]) -> None:
|
|
"""
|
|
:param peer_id: peer ID to add protocols for
|
|
:param protocols: protocols to add
|
|
"""
|
|
|
|
@abstractmethod
|
|
def set_protocols(self, peer_id: ID, protocols: Sequence[str]) -> None:
|
|
"""
|
|
:param peer_id: peer ID to set protocols for
|
|
:param protocols: protocols to set
|
|
"""
|
|
|
|
@abstractmethod
|
|
def peer_ids(self) -> list[ID]:
|
|
"""
|
|
:return: all of the peer IDs stored in peer store
|
|
"""
|
|
|
|
@abstractmethod
|
|
def get(self, peer_id: ID, key: str) -> Any:
|
|
"""
|
|
:param peer_id: peer ID to get peer data for
|
|
:param key: the key to search value for
|
|
:return: value corresponding to the key
|
|
:raise PeerStoreError: if peer ID or value not found
|
|
"""
|
|
|
|
@abstractmethod
|
|
def put(self, peer_id: ID, key: str, val: Any) -> None:
|
|
"""
|
|
:param peer_id: peer ID to put peer data for
|
|
:param key:
|
|
:param value:
|
|
"""
|
|
|
|
@abstractmethod
|
|
def add_addr(self, peer_id: ID, addr: Multiaddr, ttl: int) -> None:
|
|
"""
|
|
:param peer_id: peer ID to add address for
|
|
:param addr:
|
|
:param ttl: time-to-live for the this record
|
|
"""
|
|
|
|
@abstractmethod
|
|
def add_addrs(self, peer_id: ID, addrs: Sequence[Multiaddr], ttl: int) -> None:
|
|
"""
|
|
:param peer_id: peer ID to add address for
|
|
:param addrs:
|
|
:param ttl: time-to-live for the this record
|
|
"""
|
|
|
|
@abstractmethod
|
|
def addrs(self, peer_id: ID) -> list[Multiaddr]:
|
|
"""
|
|
:param peer_id: peer ID to get addrs for
|
|
:return: list of addrs
|
|
"""
|
|
|
|
@abstractmethod
|
|
def clear_addrs(self, peer_id: ID) -> None:
|
|
"""
|
|
:param peer_id: peer ID to clear addrs for
|
|
"""
|
|
|
|
@abstractmethod
|
|
def peers_with_addrs(self) -> list[ID]:
|
|
"""
|
|
:return: all of the peer IDs which has addrs stored in peer store
|
|
"""
|
|
|
|
@abstractmethod
|
|
def add_pubkey(self, peer_id: ID, pubkey: PublicKey) -> None:
|
|
"""
|
|
:param peer_id: peer ID to add public key for
|
|
:param pubkey:
|
|
:raise PeerStoreError: if peer ID already has pubkey set
|
|
"""
|
|
|
|
@abstractmethod
|
|
def pubkey(self, peer_id: ID) -> PublicKey:
|
|
"""
|
|
:param peer_id: peer ID to get public key for
|
|
:return: public key of the peer
|
|
:raise PeerStoreError: if peer ID not found
|
|
"""
|
|
|
|
@abstractmethod
|
|
def add_privkey(self, peer_id: ID, privkey: PrivateKey) -> None:
|
|
"""
|
|
:param peer_id: peer ID to add private key for
|
|
:param privkey:
|
|
:raise PeerStoreError: if peer ID already has privkey set
|
|
"""
|
|
|
|
@abstractmethod
|
|
def privkey(self, peer_id: ID) -> PrivateKey:
|
|
"""
|
|
:param peer_id: peer ID to get private key for
|
|
:return: private key of the peer
|
|
:raise PeerStoreError: if peer ID not found
|
|
"""
|
|
|
|
@abstractmethod
|
|
def add_key_pair(self, peer_id: ID, key_pair: KeyPair) -> None:
|
|
"""
|
|
:param peer_id: peer ID to add private key for
|
|
:param key_pair:
|
|
:raise PeerStoreError: if peer ID already has pubkey or privkey set
|
|
"""
|
|
|
|
|
|
# -------------------------- listener interface.py --------------------------
|
|
|
|
|
|
class IListener(ABC):
|
|
@abstractmethod
|
|
async def listen(self, maddr: Multiaddr, nursery: trio.Nursery) -> bool:
|
|
"""
|
|
Put listener in listening mode and wait for incoming connections.
|
|
|
|
:param maddr: multiaddr of peer
|
|
:return: return True if successful
|
|
"""
|
|
|
|
@abstractmethod
|
|
def get_addrs(self) -> tuple[Multiaddr, ...]:
|
|
"""
|
|
Retrieve list of addresses the listener is listening on.
|
|
|
|
:return: return list of addrs
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def close(self) -> None:
|
|
...
|
|
|
|
|
|
# -------------------------- network interface.py --------------------------
|
|
|
|
|
|
class INetwork(ABC):
|
|
peerstore: IPeerStore
|
|
connections: dict[ID, INetConn]
|
|
listeners: dict[str, IListener]
|
|
|
|
@abstractmethod
|
|
def get_peer_id(self) -> ID:
|
|
"""
|
|
:return: the peer id
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def dial_peer(self, peer_id: ID) -> INetConn:
|
|
"""
|
|
dial_peer try to create a connection to peer_id.
|
|
|
|
:param peer_id: peer if we want to dial
|
|
:raises SwarmException: raised when an error occurs
|
|
:return: muxed connection
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def new_stream(self, peer_id: ID) -> INetStream:
|
|
"""
|
|
:param peer_id: peer_id of destination
|
|
:param protocol_ids: available protocol ids to use for stream
|
|
:return: net stream instance
|
|
"""
|
|
|
|
@abstractmethod
|
|
def set_stream_handler(self, stream_handler: StreamHandlerFn) -> None:
|
|
"""Set the stream handler for all incoming streams."""
|
|
|
|
@abstractmethod
|
|
async def listen(self, *multiaddrs: Sequence[Multiaddr]) -> bool:
|
|
"""
|
|
:param multiaddrs: one or many multiaddrs to start listening on
|
|
:return: True if at least one success
|
|
"""
|
|
|
|
@abstractmethod
|
|
def register_notifee(self, notifee: "INotifee") -> None:
|
|
"""
|
|
:param notifee: object implementing Notifee interface
|
|
:return: true if notifee registered successfully, false otherwise
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def close(self) -> None:
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def close_peer(self, peer_id: ID) -> None:
|
|
pass
|
|
|
|
|
|
class INetworkService(INetwork, ServiceAPI):
|
|
pass
|
|
|
|
|
|
# -------------------------- notifee interface.py --------------------------
|
|
|
|
|
|
class INotifee(ABC):
|
|
@abstractmethod
|
|
async def opened_stream(self, network: "INetwork", stream: INetStream) -> None:
|
|
"""
|
|
:param network: network the stream was opened on
|
|
:param stream: stream that was opened
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def closed_stream(self, network: "INetwork", stream: INetStream) -> None:
|
|
"""
|
|
:param network: network the stream was closed on
|
|
:param stream: stream that was closed
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def connected(self, network: "INetwork", conn: INetConn) -> None:
|
|
"""
|
|
:param network: network the connection was opened on
|
|
:param conn: connection that was opened
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def disconnected(self, network: "INetwork", conn: INetConn) -> None:
|
|
"""
|
|
:param network: network the connection was closed on
|
|
:param conn: connection that was closed
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def listen(self, network: "INetwork", multiaddr: Multiaddr) -> None:
|
|
"""
|
|
:param network: network the listener is listening on
|
|
:param multiaddr: multiaddress listener is listening on
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def listen_close(self, network: "INetwork", multiaddr: Multiaddr) -> None:
|
|
"""
|
|
:param network: network the connection was opened on
|
|
:param multiaddr: multiaddress listener is no longer listening on
|
|
"""
|
|
|
|
|
|
# -------------------------- host interface.py --------------------------
|
|
|
|
|
|
class IHost(ABC):
|
|
@abstractmethod
|
|
def get_id(self) -> ID:
|
|
"""
|
|
:return: peer_id of host
|
|
"""
|
|
|
|
@abstractmethod
|
|
def get_public_key(self) -> PublicKey:
|
|
"""
|
|
:return: the public key belonging to the peer
|
|
"""
|
|
|
|
@abstractmethod
|
|
def get_private_key(self) -> PrivateKey:
|
|
"""
|
|
:return: the private key belonging to the peer
|
|
"""
|
|
|
|
@abstractmethod
|
|
def get_network(self) -> INetworkService:
|
|
"""
|
|
:return: network instance of host
|
|
"""
|
|
|
|
# FIXME: Replace with correct return type
|
|
@abstractmethod
|
|
def get_mux(self) -> Any:
|
|
"""
|
|
:return: mux instance of host
|
|
"""
|
|
|
|
@abstractmethod
|
|
def get_addrs(self) -> list[Multiaddr]:
|
|
"""
|
|
:return: all the multiaddr addresses this host is listening to
|
|
"""
|
|
|
|
@abstractmethod
|
|
def get_connected_peers(self) -> list[ID]:
|
|
"""
|
|
:return: all the ids of peers this host is currently connected to
|
|
"""
|
|
|
|
@abstractmethod
|
|
def run(self, listen_addrs: Sequence[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
|
|
def set_stream_handler(
|
|
self, protocol_id: TProtocol, stream_handler: StreamHandlerFn
|
|
) -> None:
|
|
"""
|
|
Set stream handler for host.
|
|
|
|
:param protocol_id: protocol id used on stream
|
|
:param stream_handler: a stream handler function
|
|
"""
|
|
|
|
# protocol_id can be a list of protocol_ids
|
|
# stream will decide which protocol_id to run on
|
|
@abstractmethod
|
|
async def new_stream(
|
|
self, peer_id: ID, protocol_ids: Sequence[TProtocol]
|
|
) -> INetStream:
|
|
"""
|
|
:param peer_id: peer_id that host is connecting
|
|
:param protocol_ids: available protocol ids to use for stream
|
|
:return: stream: new stream created
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def connect(self, peer_info: PeerInfo) -> None:
|
|
"""
|
|
Ensure there is a connection between this host and the peer
|
|
with given peer_info.peer_id. connect will absorb the addresses in
|
|
peer_info into its internal peerstore. If there is not an active
|
|
connection, connect will issue a dial, and block until a connection is
|
|
opened, or an error is returned.
|
|
|
|
:param peer_info: peer_info of the peer we want to connect to
|
|
:type peer_info: peer.peerinfo.PeerInfo
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def disconnect(self, peer_id: ID) -> None:
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def close(self) -> None:
|
|
pass
|
|
|
|
|
|
# -------------------------- peerdata interface.py --------------------------
|
|
|
|
|
|
class IPeerData(ABC):
|
|
@abstractmethod
|
|
def get_protocols(self) -> list[str]:
|
|
"""
|
|
:return: all protocols associated with given peer
|
|
"""
|
|
|
|
@abstractmethod
|
|
def add_protocols(self, protocols: Sequence[str]) -> None:
|
|
"""
|
|
:param protocols: protocols to add
|
|
"""
|
|
|
|
@abstractmethod
|
|
def set_protocols(self, protocols: Sequence[str]) -> None:
|
|
"""
|
|
:param protocols: protocols to set
|
|
"""
|
|
|
|
@abstractmethod
|
|
def add_addrs(self, addrs: Sequence[Multiaddr]) -> None:
|
|
"""
|
|
:param addrs: multiaddresses to add
|
|
"""
|
|
|
|
@abstractmethod
|
|
def get_addrs(self) -> list[Multiaddr]:
|
|
"""
|
|
:return: all multiaddresses
|
|
"""
|
|
|
|
@abstractmethod
|
|
def clear_addrs(self) -> None:
|
|
"""Clear all addresses."""
|
|
|
|
@abstractmethod
|
|
def put_metadata(self, key: str, val: Any) -> None:
|
|
"""
|
|
:param key: key in KV pair
|
|
:param val: val to associate with key
|
|
"""
|
|
|
|
@abstractmethod
|
|
def get_metadata(self, key: str) -> IPeerMetadata:
|
|
"""
|
|
:param key: key in KV pair
|
|
:return: val for key
|
|
:raise PeerDataError: key not found
|
|
"""
|
|
|
|
@abstractmethod
|
|
def add_pubkey(self, pubkey: PublicKey) -> None:
|
|
"""
|
|
:param pubkey:
|
|
"""
|
|
|
|
@abstractmethod
|
|
def get_pubkey(self) -> PublicKey:
|
|
"""
|
|
:return: public key of the peer
|
|
:raise PeerDataError: if public key not found
|
|
"""
|
|
|
|
@abstractmethod
|
|
def add_privkey(self, privkey: PrivateKey) -> None:
|
|
"""
|
|
:param privkey:
|
|
"""
|
|
|
|
@abstractmethod
|
|
def get_privkey(self) -> PrivateKey:
|
|
"""
|
|
:return: private key of the peer
|
|
:raise PeerDataError: if private key not found
|
|
"""
|
|
|
|
|
|
# ------------------ multiselect_communicator interface.py ------------------
|
|
|
|
|
|
class IMultiselectCommunicator(ABC):
|
|
"""
|
|
Communicator helper class that ensures both the client and multistream
|
|
module will follow the same multistream protocol, which is necessary for
|
|
them to work.
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def write(self, msg_str: str) -> None:
|
|
"""
|
|
Write message to stream.
|
|
|
|
:param msg_str: message to write
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def read(self) -> str:
|
|
"""Reads message from stream until EOF."""
|
|
|
|
|
|
# -------------------------- multiselect_client interface.py --------------------------
|
|
|
|
|
|
class IMultiselectClient(ABC):
|
|
"""
|
|
Client for communicating with receiver's multiselect module in order to
|
|
select a protocol id to communicate over.
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def handshake(self, communicator: IMultiselectCommunicator) -> None:
|
|
"""
|
|
Ensure that the client and multiselect are both using the same
|
|
multiselect protocol.
|
|
|
|
:param stream: stream to communicate with multiselect over
|
|
:raise Exception: multiselect protocol ID mismatch
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def select_one_of(
|
|
self, protocols: Sequence[TProtocol], communicator: IMultiselectCommunicator
|
|
) -> TProtocol:
|
|
"""
|
|
For each protocol, send message to multiselect selecting protocol and
|
|
fail if multiselect does not return same protocol. Returns first
|
|
protocol that multiselect agrees on (i.e. that multiselect selects)
|
|
|
|
:param protocol: protocol to select
|
|
:param stream: stream to communicate with multiselect over
|
|
:return: selected protocol
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def try_select(
|
|
self, communicator: IMultiselectCommunicator, protocol: TProtocol
|
|
) -> TProtocol:
|
|
"""
|
|
Try to select the given protocol or raise exception if fails.
|
|
|
|
:param communicator: communicator to use to communicate with counterparty
|
|
:param protocol: protocol to select
|
|
:raise Exception: error in protocol selection
|
|
:return: selected protocol
|
|
"""
|
|
|
|
|
|
# -------------------------- multiselect_muxer interface.py --------------------------
|
|
|
|
|
|
class IMultiselectMuxer(ABC):
|
|
"""
|
|
Multiselect module that is responsible for responding to a multiselect
|
|
client and deciding on a specific protocol and handler pair to use for
|
|
communication.
|
|
"""
|
|
|
|
handlers: dict[TProtocol, StreamHandlerFn]
|
|
|
|
@abstractmethod
|
|
def add_handler(self, protocol: TProtocol, handler: StreamHandlerFn) -> None:
|
|
"""
|
|
Store the handler with the given protocol.
|
|
|
|
:param protocol: protocol name
|
|
:param handler: handler function
|
|
"""
|
|
|
|
def get_protocols(self) -> tuple[TProtocol, ...]:
|
|
return tuple(self.handlers.keys())
|
|
|
|
@abstractmethod
|
|
async def negotiate(
|
|
self, communicator: IMultiselectCommunicator
|
|
) -> tuple[TProtocol, StreamHandlerFn]:
|
|
"""
|
|
Negotiate performs protocol selection.
|
|
|
|
:param stream: stream to negotiate on
|
|
:return: selected protocol name, handler function
|
|
:raise Exception: negotiation failed exception
|
|
"""
|
|
|
|
|
|
# -------------------------- routing interface.py --------------------------
|
|
|
|
|
|
class IContentRouting(ABC):
|
|
@abstractmethod
|
|
def provide(self, cid: bytes, announce: bool = True) -> None:
|
|
"""
|
|
Provide adds the given cid to the content routing system.
|
|
|
|
If announce is True, it also announces it, otherwise it is just
|
|
kept in the local accounting of which objects are being
|
|
provided.
|
|
"""
|
|
|
|
@abstractmethod
|
|
def find_provider_iter(self, cid: bytes, count: int) -> Iterable[PeerInfo]:
|
|
"""
|
|
Search for peers who are able to provide a given key returns an
|
|
iterator of peer.PeerInfo.
|
|
"""
|
|
|
|
|
|
class IPeerRouting(ABC):
|
|
@abstractmethod
|
|
async def find_peer(self, peer_id: ID) -> PeerInfo:
|
|
"""
|
|
Find specific Peer FindPeer searches for a peer with given peer_id,
|
|
returns a peer.PeerInfo with relevant addresses.
|
|
"""
|
|
|
|
|
|
# -------------------------- security_transport interface.py --------------------------
|
|
|
|
|
|
"""
|
|
Transport that is used to secure a connection. This transport is
|
|
chosen by a security transport multistream module.
|
|
|
|
Relevant go repo: https://github.com/libp2p/go-conn-security/blob/master/interface.go
|
|
"""
|
|
|
|
|
|
class ISecureTransport(ABC):
|
|
@abstractmethod
|
|
async def secure_inbound(self, conn: IRawConnection) -> ISecureConn:
|
|
"""
|
|
Secure the connection, either locally or by communicating with opposing
|
|
node via conn, for an inbound connection (i.e. we are not the
|
|
initiator)
|
|
|
|
:return: secure connection object (that implements secure_conn_interface)
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def secure_outbound(self, conn: IRawConnection, peer_id: ID) -> ISecureConn:
|
|
"""
|
|
Secure the connection, either locally or by communicating with opposing
|
|
node via conn, for an inbound connection (i.e. we are the initiator)
|
|
|
|
:return: secure connection object (that implements secure_conn_interface)
|
|
"""
|
|
|
|
|
|
# -------------------------- transport interface.py --------------------------
|
|
|
|
|
|
class ITransport(ABC):
|
|
@abstractmethod
|
|
async def dial(self, maddr: Multiaddr) -> IRawConnection:
|
|
"""
|
|
Dial a transport to peer listening on multiaddr.
|
|
|
|
:param multiaddr: multiaddr of peer
|
|
:param self_id: peer_id of the dialer (to send to receiver)
|
|
:return: list of multiaddrs
|
|
"""
|
|
|
|
@abstractmethod
|
|
def create_listener(self, handler_function: THandler) -> IListener:
|
|
"""
|
|
Create listener on transport.
|
|
|
|
:param handler_function: a function called when a new conntion is received
|
|
that takes a connection as argument which implements interface-connection
|
|
:return: a listener object that implements listener_interface.py
|
|
"""
|
|
|
|
|
|
# -------------------------- pubsub abc.py --------------------------
|
|
|
|
|
|
class ISubscriptionAPI(
|
|
AsyncContextManager["ISubscriptionAPI"], AsyncIterable[rpc_pb2.Message]
|
|
):
|
|
@abstractmethod
|
|
async def unsubscribe(self) -> None:
|
|
...
|
|
|
|
@abstractmethod
|
|
async def get(self) -> rpc_pb2.Message:
|
|
...
|
|
|
|
|
|
class IPubsubRouter(ABC):
|
|
@abstractmethod
|
|
def get_protocols(self) -> list[TProtocol]:
|
|
"""
|
|
:return: the list of protocols supported by the router
|
|
"""
|
|
|
|
@abstractmethod
|
|
def attach(self, pubsub: "Pubsub") -> None:
|
|
"""
|
|
Attach is invoked by the PubSub constructor to attach the router to a
|
|
freshly initialized PubSub instance.
|
|
|
|
:param pubsub: pubsub instance to attach to
|
|
"""
|
|
|
|
@abstractmethod
|
|
def add_peer(self, peer_id: ID, protocol_id: TProtocol) -> None:
|
|
"""
|
|
Notifies the router that a new peer has been connected.
|
|
|
|
:param peer_id: id of peer to add
|
|
:param protocol_id: router protocol the peer speaks, e.g., floodsub, gossipsub
|
|
"""
|
|
|
|
@abstractmethod
|
|
def remove_peer(self, peer_id: ID) -> None:
|
|
"""
|
|
Notifies the router that a peer has been disconnected.
|
|
|
|
:param peer_id: id of peer to remove
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def handle_rpc(self, rpc: rpc_pb2.RPC, sender_peer_id: ID) -> None:
|
|
"""
|
|
Invoked to process control messages in the RPC envelope.
|
|
It is invoked after subscriptions and payload messages have been processed
|
|
|
|
:param rpc: RPC message
|
|
:param sender_peer_id: id of the peer who sent the message
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def publish(self, msg_forwarder: ID, pubsub_msg: rpc_pb2.Message) -> None:
|
|
"""
|
|
Invoked to forward a new message that has been validated.
|
|
|
|
:param msg_forwarder: peer_id of message sender
|
|
:param pubsub_msg: pubsub message to forward
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def join(self, topic: str) -> None:
|
|
"""
|
|
Join notifies the router that we want to receive and forward messages
|
|
in a topic. It is invoked after the subscription announcement.
|
|
|
|
:param topic: topic to join
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def leave(self, topic: str) -> None:
|
|
"""
|
|
Leave notifies the router that we are no longer interested in a topic.
|
|
It is invoked after the unsubscription announcement.
|
|
|
|
:param topic: topic to leave
|
|
"""
|
|
|
|
|
|
class IPubsub(ServiceAPI):
|
|
@property
|
|
@abstractmethod
|
|
def my_id(self) -> ID:
|
|
...
|
|
|
|
@property
|
|
@abstractmethod
|
|
def protocols(self) -> tuple[TProtocol, ...]:
|
|
...
|
|
|
|
@property
|
|
@abstractmethod
|
|
def topic_ids(self) -> KeysView[str]:
|
|
...
|
|
|
|
@abstractmethod
|
|
def set_topic_validator(
|
|
self, topic: str, validator: ValidatorFn, is_async_validator: bool
|
|
) -> None:
|
|
...
|
|
|
|
@abstractmethod
|
|
def remove_topic_validator(self, topic: str) -> None:
|
|
...
|
|
|
|
@abstractmethod
|
|
async def wait_until_ready(self) -> None:
|
|
...
|
|
|
|
@abstractmethod
|
|
async def subscribe(self, topic_id: str) -> ISubscriptionAPI:
|
|
...
|
|
|
|
@abstractmethod
|
|
async def unsubscribe(self, topic_id: str) -> None:
|
|
...
|
|
|
|
@abstractmethod
|
|
async def publish(self, topic_id: str, data: bytes) -> None:
|
|
...
|