|
@@ -18,8 +18,10 @@ import hivemind.hivemind_cli as cli
|
|
|
import hivemind.p2p.p2p_daemon_bindings.p2pclient as p2pclient
|
|
|
from hivemind.p2p.p2p_daemon_bindings.control import DEFAULT_MAX_MSG_SIZE, P2PDaemonError, P2PHandlerError
|
|
|
from hivemind.p2p.p2p_daemon_bindings.datastructures import PeerID, PeerInfo, StreamInfo
|
|
|
+from hivemind.proto import crypto_pb2
|
|
|
from hivemind.proto.p2pd_pb2 import RPCError
|
|
|
from hivemind.utils.asyncio import as_aiter, asingle
|
|
|
+from hivemind.utils.crypto import RSAPrivateKey
|
|
|
from hivemind.utils.logging import get_logger, golog_level_to_python, loglevel, python_level_to_golog
|
|
|
|
|
|
logger = get_logger(__name__)
|
|
@@ -113,8 +115,8 @@ class P2P:
|
|
|
Details: https://pkg.go.dev/github.com/libp2p/go-libp2p-kad-dht#ModeOpt
|
|
|
:param force_reachability: Force reachability mode (public/private)
|
|
|
:param host_maddrs: Multiaddrs to listen for external connections from other p2p instances
|
|
|
- :param identity_path: Path to a pre-generated private key file. If defined, makes the peer ID deterministic.
|
|
|
- May be generated using ``./p2p-keygen`` from ``go-libp2p-daemon``.
|
|
|
+ :param identity_path: Path to a private key file. If defined, makes the peer ID deterministic.
|
|
|
+ If the file does not exist yet, writes a new private key to this file.
|
|
|
:param idle_timeout: kill daemon if client has been idle for a given number of
|
|
|
seconds before opening persistent streams
|
|
|
:param nat_port_map: Enables NAT port mapping
|
|
@@ -156,7 +158,7 @@ class P2P:
|
|
|
raise ValueError("Please specify an explicit port in announce_maddrs: port 0 is not supported")
|
|
|
|
|
|
need_bootstrap = bool(initial_peers) or use_ipfs
|
|
|
- process_kwargs = cls.DHT_MODE_MAPPING.get(dht_mode, {"dht": 0})
|
|
|
+ process_kwargs = cls.DHT_MODE_MAPPING[dht_mode].copy()
|
|
|
process_kwargs.update(cls.FORCE_REACHABILITY_MAPPING.get(force_reachability, {}))
|
|
|
for param, value in [
|
|
|
("bootstrapPeers", initial_peers),
|
|
@@ -165,7 +167,11 @@ class P2P:
|
|
|
]:
|
|
|
if value:
|
|
|
process_kwargs[param] = self._maddrs_to_str(value)
|
|
|
+
|
|
|
if identity_path is not None:
|
|
|
+ if not os.path.isfile(identity_path):
|
|
|
+ logger.info(f"Generating new identity (libp2p private key) in `{identity_path}`")
|
|
|
+ self.generate_identity(identity_path)
|
|
|
process_kwargs["id"] = identity_path
|
|
|
|
|
|
proc_args = self._make_process_args(
|
|
@@ -211,6 +217,20 @@ class P2P:
|
|
|
await self._ping_daemon()
|
|
|
return self
|
|
|
|
|
|
+ @staticmethod
|
|
|
+ def generate_identity(identity_path: str) -> None:
|
|
|
+ private_key = RSAPrivateKey()
|
|
|
+ protobuf = crypto_pb2.PrivateKey(key_type=crypto_pb2.KeyType.RSA, data=private_key.to_bytes())
|
|
|
+
|
|
|
+ try:
|
|
|
+ with open(identity_path, "wb") as f:
|
|
|
+ f.write(protobuf.SerializeToString())
|
|
|
+ except FileNotFoundError:
|
|
|
+ raise FileNotFoundError(
|
|
|
+ f"The directory `{os.path.dirname(identity_path)}` for saving the identity does not exist"
|
|
|
+ )
|
|
|
+ os.chmod(identity_path, 0o400)
|
|
|
+
|
|
|
@classmethod
|
|
|
async def replicate(cls, daemon_listen_maddr: Multiaddr) -> "P2P":
|
|
|
"""
|