From 95f32dbff9b162dd0b11dac8bdf78d0bf85e5fe6 Mon Sep 17 00:00:00 2001 From: Vincent Zhang Date: Wed, 9 Oct 2024 11:32:49 +0800 Subject: [PATCH] Add PostStart actor after PocketIcProxy actor to output info messages. --- src/dfx/src/actors/mod.rs | 16 ++++++++ src/dfx/src/actors/pocketic_proxy.rs | 36 ++++++++++++++++-- src/dfx/src/actors/post_start.rs | 56 ++++++++++++++++++++++++++++ src/dfx/src/commands/start.rs | 15 ++++++-- 4 files changed, 116 insertions(+), 7 deletions(-) create mode 100644 src/dfx/src/actors/post_start.rs diff --git a/src/dfx/src/actors/mod.rs b/src/dfx/src/actors/mod.rs index ee44edd16b..22589041db 100644 --- a/src/dfx/src/actors/mod.rs +++ b/src/dfx/src/actors/mod.rs @@ -13,6 +13,7 @@ use dfx_core::config::model::replica_config::ReplicaConfig; use fn_error_context::context; use pocketic_proxy::signals::PortReadySubscribe; use pocketic_proxy::{PocketIcProxy, PocketIcProxyConfig}; +use post_start::PostStart; use std::fs; use std::path::PathBuf; @@ -22,6 +23,7 @@ pub mod btc_adapter; pub mod canister_http_adapter; pub mod pocketic; pub mod pocketic_proxy; +pub mod post_start; pub mod replica; mod shutdown; pub mod shutdown_controller; @@ -213,3 +215,17 @@ pub fn start_pocketic_actor( }; Ok(pocketic::PocketIc::new(actor_config).start()) } + +#[context("Failed to start PostStart actor.")] +pub fn start_post_start_actor( + env: &dyn Environment, + background: bool, + pocketic_proxy: Option>, +) -> DfxResult> { + let config = post_start::Config { + logger: env.get_logger().clone(), + background, + pocketic_proxy, + }; + Ok(PostStart::new(config).start()) +} diff --git a/src/dfx/src/actors/pocketic_proxy.rs b/src/dfx/src/actors/pocketic_proxy.rs index ba86f0d580..4f6da239bf 100644 --- a/src/dfx/src/actors/pocketic_proxy.rs +++ b/src/dfx/src/actors/pocketic_proxy.rs @@ -1,4 +1,5 @@ use crate::actors::pocketic_proxy::signals::{PortReadySignal, PortReadySubscribe}; +use crate::actors::post_start::signals::{PocketIcProxyReadySignal, PocketIcProxyReadySubscribe}; use crate::actors::shutdown::{wait_for_child_or_receiver, ChildOrReceiver}; use crate::actors::shutdown_controller::signals::outbound::Shutdown; use crate::actors::shutdown_controller::signals::ShutdownSubscribe; @@ -70,6 +71,9 @@ pub struct PocketIcProxy { stop_sender: Option>, thread_join: Option>, + + /// Ready Signal subscribers. + ready_subscribers: Vec>, } impl PocketIcProxy { @@ -81,10 +85,11 @@ impl PocketIcProxy { stop_sender: None, thread_join: None, logger, + ready_subscribers: Vec::new(), } } - fn start_pocketic_proxy(&mut self, replica_url: Url) -> DfxResult { + fn start_pocketic_proxy(&mut self, replica_url: Url, addr: Addr) -> DfxResult { let logger = self.logger.clone(); let config = &self.config.pocketic_proxy_config; let pocketic_proxy_path = self.config.pocketic_proxy_path.clone(); @@ -100,6 +105,7 @@ impl PocketIcProxy { pocketic_proxy_path, pocketic_proxy_pid_path, pocketic_proxy_port_path, + addr, receiver, config.verbose, config.domains.clone(), @@ -164,7 +170,7 @@ impl Actor for PocketIcProxy { .do_send(ShutdownSubscribe(ctx.address().recipient::())); if let Some(replica_url) = &self.config.pocketic_proxy_config.replica_url { - self.start_pocketic_proxy(replica_url.clone()) + self.start_pocketic_proxy(replica_url.clone(), ctx.address()) .expect("Could not start PocketIC HTTP gateway"); } } @@ -179,7 +185,7 @@ impl Actor for PocketIcProxy { impl Handler for PocketIcProxy { type Result = (); - fn handle(&mut self, msg: PortReadySignal, _ctx: &mut Self::Context) { + fn handle(&mut self, msg: PortReadySignal, ctx: &mut Self::Context) { debug!( self.logger, "replica ready on {}, so re/starting HTTP gateway", msg.url @@ -189,11 +195,29 @@ impl Handler for PocketIcProxy { let replica_url = Url::parse(&msg.url).unwrap(); - self.start_pocketic_proxy(replica_url) + self.start_pocketic_proxy(replica_url, ctx.address()) .expect("Could not start PocketIC HTTP gateway"); } } +impl Handler for PocketIcProxy { + type Result = (); + + fn handle(&mut self, msg: PocketIcProxyReadySubscribe, _ctx: &mut Self::Context) { + self.ready_subscribers.push(msg.0); + } +} + +impl Handler for PocketIcProxy { + type Result = (); + + fn handle(&mut self, _msg: PocketIcProxyReadySignal, _ctx: &mut Self::Context) { + for sub in &self.ready_subscribers { + sub.do_send(PocketIcProxyReadySignal); + } + } +} + impl Handler for PocketIcProxy { type Result = ResponseActFuture>; @@ -217,6 +241,7 @@ fn pocketic_proxy_start_thread( pocketic_proxy_path: PathBuf, pocketic_proxy_pid_path: PathBuf, pocketic_proxy_port_path: PathBuf, + addr: Addr, receiver: Receiver<()>, verbose: bool, domains: Option>, @@ -277,6 +302,9 @@ fn pocketic_proxy_start_thread( } info!(logger, "Replica API running on {address}"); + // Send PocketIcProxyReadySignal to PocketIcProxy. + addr.do_send(PocketIcProxyReadySignal); + // This waits for the child to stop, or the receiver to receive a message. // We don't restart pocket-ic if done = true. match wait_for_child_or_receiver(&mut child, &receiver) { diff --git a/src/dfx/src/actors/post_start.rs b/src/dfx/src/actors/post_start.rs new file mode 100644 index 0000000000..ff4971b3af --- /dev/null +++ b/src/dfx/src/actors/post_start.rs @@ -0,0 +1,56 @@ +use crate::actors::post_start::signals::{PocketIcProxyReadySignal, PocketIcProxyReadySubscribe}; +use crate::actors::pocketic_proxy::PocketIcProxy; +use actix::{Actor, Addr, AsyncContext, Context, Handler}; +use slog::{info, Logger}; + +pub mod signals { + use actix::prelude::*; + + #[derive(Message)] + #[rtype(result = "()")] + pub struct PocketIcProxyReadySignal; + + #[derive(Message)] + #[rtype(result = "()")] + pub struct PocketIcProxyReadySubscribe(pub Recipient); +} + +pub struct Config { + pub logger: Logger, + pub background: bool, + pub pocketic_proxy: Option>, +} + +pub struct PostStart { + config: Config, +} + +impl PostStart { + pub fn new(config: Config) -> Self { + Self { config } + } +} + +impl Actor for PostStart { + type Context = Context; + + fn started(&mut self, ctx: &mut Self::Context) { + // Register the PostStart recipent to PocketIcProxy. + if let Some(pocketic_proxy) = &self.config.pocketic_proxy { + pocketic_proxy.do_send(PocketIcProxyReadySubscribe(ctx.address().recipient())); + } + } +} + +impl Handler for PostStart { + type Result = (); + + fn handle(&mut self, _msg: PocketIcProxyReadySignal, _ctx: &mut Self::Context) -> Self::Result { + let logger = &self.config.logger; + if self.config.background { + info!(logger, "The dfx server is running in the background.") + } else { + info!(logger, "The dfx server is running.\nYou can start a new terminal to continue developing, or quit with 'Ctrl-C'."); + } + } +} diff --git a/src/dfx/src/commands/start.rs b/src/dfx/src/commands/start.rs index b5f96855f5..2a44dbb7bb 100644 --- a/src/dfx/src/commands/start.rs +++ b/src/dfx/src/commands/start.rs @@ -1,7 +1,8 @@ use crate::actors::pocketic_proxy::{signals::PortReadySubscribe, PocketIcProxyConfig}; use crate::actors::{ start_btc_adapter_actor, start_canister_http_adapter_actor, start_pocketic_actor, - start_pocketic_proxy_actor, start_replica_actor, start_shutdown_controller, + start_pocketic_proxy_actor, start_post_start_actor, start_replica_actor, + start_shutdown_controller, }; use crate::config::dfx_version_str; use crate::error_invalid_argument; @@ -264,6 +265,10 @@ pub fn exec( } local_server_descriptor.describe(env.get_logger()); + // Get the original background flag set by the user from the command arguments. + // Get it from the environment variable as the `--background` flag will be ignored by the send_background() method. + let original_background = std::env::var("original_background").is_ok(); + write_pid(&pid_file_path); fs::write(&webserver_port_path, address_and_port.port().to_string())?; @@ -413,7 +418,10 @@ pub fn exec( pocketic_proxy_pid_file_path, pocketic_proxy_port_file_path, )?; - Ok::<_, Error>(proxy) + + let post_start = start_post_start_actor(env, original_background, Some(proxy))?; + + Ok::<_, Error>(post_start) })?; system.run()?; @@ -574,7 +582,8 @@ fn send_background() -> DfxResult<()> { .skip(1) .filter(|a| !a.eq("--background")) .filter(|a| !a.eq("--clean")), - ); + ) + .env("original_background", "true"); // Set the `original_background` environment variable which will be used by the second start. cmd.spawn().context("Failed to spawn child process.")?; Ok(())