diff --git a/chia/cmds/start_funcs.py b/chia/cmds/start_funcs.py index 6340abb0704e..618a7a796482 100644 --- a/chia/cmds/start_funcs.py +++ b/chia/cmds/start_funcs.py @@ -33,9 +33,11 @@ def launch_start_daemon(root_path: Path) -> subprocess.Popen: print(f"Starting daemon: {cmd_to_execute} run_daemon --wait-for-unlock", flush=True) process = subprocess.Popen( [cmd_to_execute, "run_daemon", "--wait-for-unlock"], - encoding="utf-8", - stdout=subprocess.PIPE, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + stdin=subprocess.DEVNULL, creationflags=creationflags, + start_new_session=True, ) return process @@ -48,13 +50,8 @@ async def create_start_daemon_connection( if connection is None: print("Starting daemon", flush=True) # launch a daemon - process = launch_start_daemon(root_path) - # give the daemon a chance to start up - if process.stdout: - process.stdout.readline() - await asyncio.sleep(1) - # it prints "daemon: listening" - connection = await connect_to_daemon_and_validate(root_path, config) + launch_start_daemon(root_path) + connection = await connect_to_daemon_and_validate(root_path, config, wait_for_start=True) if connection: if skip_keyring: print("Skipping to unlock keyring") diff --git a/chia/daemon/client.py b/chia/daemon/client.py index 3a4866ab2f95..9ae1a8e8d9cd 100644 --- a/chia/daemon/client.py +++ b/chia/daemon/client.py @@ -36,20 +36,30 @@ def format_request(self, command: str, data: dict[str, Any]) -> WsRpcMessage: request = create_payload_dict(command, data, "client", "daemon") return request - async def start(self) -> None: - try: - self.client_session = aiohttp.ClientSession() - self.websocket = await self.client_session.ws_connect( - self._uri, - autoclose=True, - autoping=True, - heartbeat=self.heartbeat, - ssl=self.ssl_context if self.ssl_context is not None else True, - max_msg_size=self.max_message_size, - ) - except Exception: + async def start(self, wait_for_start: bool = False) -> None: + self.client_session = aiohttp.ClientSession() + + connect_backoff = 2 + while (self.websocket is None or self.websocket.closed) and connect_backoff <= 60: + try: + self.websocket = await self.client_session.ws_connect( + self._uri, + autoclose=True, + autoping=True, + heartbeat=self.heartbeat, + ssl=self.ssl_context if self.ssl_context is not None else True, + max_msg_size=self.max_message_size, + ) + break + except aiohttp.ClientError: + if not wait_for_start: + break + await asyncio.sleep(connect_backoff) + connect_backoff *= 2 + + if self.websocket is None or self.websocket.closed: await self.close() - raise + raise Exception("Failed to connect to daemon") async def listener_task() -> None: try: @@ -161,7 +171,12 @@ async def get_keys_for_plotting(self, fingerprints: Optional[list[uint32]] = Non async def connect_to_daemon( - self_hostname: str, daemon_port: int, max_message_size: int, ssl_context: ssl.SSLContext, heartbeat: int + self_hostname: str, + daemon_port: int, + max_message_size: int, + ssl_context: ssl.SSLContext, + heartbeat: int, + wait_for_start: bool = False, ) -> DaemonProxy: """ Connect to the local daemon. @@ -173,12 +188,13 @@ async def connect_to_daemon( max_message_size=max_message_size, heartbeat=heartbeat, ) - await client.start() + + await client.start(wait_for_start=wait_for_start) return client async def connect_to_daemon_and_validate( - root_path: Path, config: dict[str, Any], quiet: bool = False + root_path: Path, config: dict[str, Any], quiet: bool = False, wait_for_start: bool = False ) -> Optional[DaemonProxy]: """ Connect to the local daemon and do a ping to ensure that something is really @@ -200,6 +216,7 @@ async def connect_to_daemon_and_validate( max_message_size=daemon_max_message_size, ssl_context=ssl_context, heartbeat=daemon_heartbeat, + wait_for_start=wait_for_start, ) r = await connection.ping() diff --git a/chia/daemon/keychain_proxy.py b/chia/daemon/keychain_proxy.py index 2bbdbc89ded1..b7330c2cc8f5 100644 --- a/chia/daemon/keychain_proxy.py +++ b/chia/daemon/keychain_proxy.py @@ -98,7 +98,7 @@ async def _get(self, request: WsRpcMessage) -> WsRpcMessage: except asyncio.TimeoutError: raise KeychainProxyConnectionTimeout() - async def start(self) -> None: + async def start(self, wait_for_start: bool = False) -> None: self.keychain_connection_task = asyncio.create_task(self.connect_to_keychain()) await self.connection_established.wait() # wait until connection is established. diff --git a/chia/daemon/server.py b/chia/daemon/server.py index 36ca9e442986..505a10e5e96e 100644 --- a/chia/daemon/server.py +++ b/chia/daemon/server.py @@ -1548,17 +1548,6 @@ async def async_run_daemon(root_path: Path, wait_for_unlock: bool = False) -> in ca_crt_path = root_path / config["private_ssl_ca"]["crt"] ca_key_path = root_path / config["private_ssl_ca"]["key"] sys.stdout.flush() - json_msg = dict_to_json_str( - { - "message": "cert_path", - "success": True, - "cert": f"{crt_path}", - "key": f"{key_path}", - "ca_crt": f"{ca_crt_path}", - } - ) - sys.stdout.write("\n" + json_msg + "\n") - sys.stdout.flush() try: with Lockfile.create(daemon_launch_lock_path(root_path), timeout=1): log.info(f"chia-blockchain version: {chia_short_version()}")