From d6d2a27c6e62d16a348a1d5f55c574dca3a0f483 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Fri, 17 Jan 2025 17:18:07 -0800 Subject: [PATCH] pass configs through to android mobile launch --- packages/cli/src/config/serve.rs | 19 ++++--------- packages/cli/src/logging.rs | 6 ++-- packages/cli/src/serve/server.rs | 29 +++++++++++++++---- packages/desktop/src/protocol.rs | 2 +- packages/dioxus/src/launch.rs | 2 +- packages/mobile/src/lib.rs | 49 +++++++++++++++++++++++++------- 6 files changed, 71 insertions(+), 36 deletions(-) diff --git a/packages/cli/src/config/serve.rs b/packages/cli/src/config/serve.rs index b04dbaa7b1..a2e0e9d178 100644 --- a/packages/cli/src/config/serve.rs +++ b/packages/cli/src/config/serve.rs @@ -8,27 +8,18 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4}; pub(crate) struct AddressArguments { /// The port the server will run on #[clap(long)] - #[clap(default_value_t = default_port())] - pub(crate) port: u16, + pub(crate) port: Option, /// The address the server will run on - #[clap(long, default_value_t = default_address())] - pub(crate) addr: std::net::IpAddr, + #[clap(long)] + pub(crate) addr: Option, } impl Default for AddressArguments { fn default() -> Self { Self { - port: default_port(), - addr: default_address(), + port: None, + addr: None, } } } - -fn default_port() -> u16 { - 8080 -} - -fn default_address() -> IpAddr { - IpAddr::V4(std::net::Ipv4Addr::new(0, 0, 0, 0)) -} diff --git a/packages/cli/src/logging.rs b/packages/cli/src/logging.rs index 7b702bb05a..4f61de1484 100644 --- a/packages/cli/src/logging.rs +++ b/packages/cli/src/logging.rs @@ -18,7 +18,7 @@ use crate::{serve::ServeUpdate, Cli, Commands, Platform as TargetPlatform, Verbo use cargo_metadata::{diagnostic::DiagnosticLevel, CompilerMessage}; use clap::Parser; use futures_channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}; -use once_cell::sync::{Lazy, OnceCell}; +use once_cell::sync::OnceCell; use std::{ collections::HashMap, env, @@ -27,7 +27,7 @@ use std::{ path::PathBuf, sync::{ atomic::{AtomicBool, Ordering}, - Arc, Mutex, + Mutex, }, time::Instant, }; @@ -46,8 +46,6 @@ const LOG_ENV: &str = "DIOXUS_LOG"; const LOG_FILE_NAME: &str = "dx.log"; const DX_SRC_FLAG: &str = "dx_src"; -pub static TUI_INTERACTIVE_DISABLED: Lazy> = - Lazy::new(|| Arc::new(AtomicBool::new(false))); static TUI_ACTIVE: AtomicBool = AtomicBool::new(false); static TUI_TX: OnceCell> = OnceCell::new(); pub static VERBOSITY: OnceCell = OnceCell::new(); diff --git a/packages/cli/src/serve/server.rs b/packages/cli/src/serve/server.rs index 5ea6397777..32b542075e 100644 --- a/packages/cli/src/serve/server.rs +++ b/packages/cli/src/serve/server.rs @@ -71,19 +71,28 @@ impl WebServer { let (hot_reload_sockets_tx, hot_reload_sockets_rx) = futures_channel::mpsc::unbounded(); let (build_status_sockets_tx, build_status_sockets_rx) = futures_channel::mpsc::unbounded(); - let devserver_bind_ip = args.address.addr; - let devserver_port = args.address.port; - let devserver_bind_address = SocketAddr::new(devserver_bind_ip, devserver_port); + const SELF_IP: IpAddr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)); + + // Use 0.0.0.0 as the default address if none is specified - this will let us expose the + // devserver to the network (for other devices like phones/embedded) + let devserver_bind_ip = args.address.addr.unwrap_or_else(|| SELF_IP); + + // If the user specified a port, use that, otherwise use any available port, preferring 8080 + let devserver_port = args + .address + .port + .unwrap_or_else(|| get_available_port(devserver_bind_ip, Some(8080)).unwrap_or(8080)); // All servers will end up behind us (the devserver) but on a different port // This is so we can serve a loading screen as well as devtools without anything particularly fancy let proxied_port = args .should_proxy_build() - .then(|| get_available_port(devserver_bind_ip)) + .then(|| get_available_port(devserver_bind_ip, None)) .flatten(); // Create the listener that we'll pass into the devserver, but save its IP here so // we can display it to the user in the tui + let devserver_bind_address = SocketAddr::new(devserver_bind_ip, devserver_port); let listener = std::net::TcpListener::bind(devserver_bind_address).with_context(|| { anyhow::anyhow!( "Failed to bind server to: {devserver_bind_address}, is there another devserver running?\nTo run multiple devservers, use the --port flag to specify a different port" @@ -92,7 +101,7 @@ impl WebServer { // If the IP is 0.0.0.0, we need to get the actual IP of the machine // This will let ios/android/network clients connect to the devserver - let devserver_exposed_ip = if devserver_bind_ip == IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)) { + let devserver_exposed_ip = if devserver_bind_ip == SELF_IP { local_ip_address::local_ip().unwrap_or(devserver_bind_ip) } else { devserver_bind_ip @@ -626,7 +635,15 @@ async fn get_rustls(web_config: &WebHttpsConfig) -> Result<(String, String)> { /// /// Todo: we might want to do this on every new build in case the OS tries to bind things to this port /// and we don't already have something bound to it. There's no great way of "reserving" a port. -fn get_available_port(address: IpAddr) -> Option { +fn get_available_port(address: IpAddr, prefer: Option) -> Option { + // First, try to bind to the preferred port + if let Some(port) = prefer { + if let Ok(_listener) = TcpListener::bind((address, port)) { + return Some(port); + } + } + + // Otherwise, try to bind to any port and return the first one we can TcpListener::bind((address, 0)) .map(|listener| listener.local_addr().unwrap().port()) .ok() diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index ff8755c87b..677fe5e6f2 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -288,7 +288,7 @@ pub(crate) fn to_java_load_asset(filepath: &str) -> Option> { } } - use std::{io::Read, ptr::NonNull}; + use std::ptr::NonNull; let ctx = ndk_context::android_context(); let vm = unsafe { jni::JavaVM::from_raw(ctx.vm().cast()) }.unwrap(); diff --git a/packages/dioxus/src/launch.rs b/packages/dioxus/src/launch.rs index 7dd6acf7e0..1ad29393e3 100644 --- a/packages/dioxus/src/launch.rs +++ b/packages/dioxus/src/launch.rs @@ -87,7 +87,7 @@ impl LaunchBuilder { #[cfg_attr(docsrs, doc(cfg(feature = "mobile")))] pub fn mobile() -> LaunchBuilder { LaunchBuilder { - launch_fn: |root, contexts, cfg| dioxus_mobile::launch::launch(root, contexts, cfg), + launch_fn: |root, contexts, cfg| dioxus_mobile::launch_cfg(root, contexts, cfg), contexts: Vec::new(), configs: Vec::new(), } diff --git a/packages/mobile/src/lib.rs b/packages/mobile/src/lib.rs index f5cd224d0f..dda326fdf8 100644 --- a/packages/mobile/src/lib.rs +++ b/packages/mobile/src/lib.rs @@ -4,18 +4,18 @@ pub use dioxus_desktop::*; use dioxus_lib::prelude::*; +use std::any::Any; use std::sync::Mutex; pub mod launch_bindings { - use std::any::Any; use super::*; pub fn launch( root: fn() -> Element, - _contexts: Vec Box + Send + Sync>>, - _platform_config: Vec>, + contexts: Vec Box + Send + Sync>>, + platform_config: Vec>, ) { - super::launch(root); + super::launch_cfg(root, contexts, platform_config); } pub fn launch_virtual_dom(_virtual_dom: VirtualDom, _desktop_config: Config) -> ! { @@ -24,27 +24,56 @@ pub mod launch_bindings { } /// Launch via the binding API -pub fn launch(incoming: fn() -> Element) { +pub fn launch(root: fn() -> Element) { + launch_cfg(root, vec![], vec![]); +} + +pub fn launch_cfg( + root: fn() -> Element, + contexts: Vec Box + Send + Sync>>, + platform_config: Vec>, +) { #[cfg(target_os = "android")] { - *APP_FN_PTR.lock().unwrap() = Some(incoming); + *APP_OBJECTS.lock().unwrap() = Some(BoundLaunchObjects { + root, + contexts, + platform_config, + }); } #[cfg(not(target_os = "android"))] { - dioxus_desktop::launch::launch(incoming, vec![], Default::default()); + dioxus_desktop::launch::launch(root, contexts, platform_config); } } -static APP_FN_PTR: Mutex Element>> = Mutex::new(None); +static APP_OBJECTS: Mutex> = Mutex::new(None); + +struct BoundLaunchObjects { + root: fn() -> Element, + contexts: Vec Box + Send + Sync>>, + platform_config: Vec>, +} + +unsafe impl Send for BoundLaunchObjects {} +unsafe impl Sync for BoundLaunchObjects {} +#[doc(hidden)] pub fn root() { - let app = APP_FN_PTR + let app = APP_OBJECTS .lock() .expect("APP_FN_PTR lock failed") + .take() .expect("Android to have set the app trampoline"); - dioxus_desktop::launch::launch(app, vec![], Default::default()); + let BoundLaunchObjects { + root, + contexts, + platform_config, + } = app; + + dioxus_desktop::launch::launch(root, contexts, platform_config); } /// Expose the `Java_dev_dioxus_main_WryActivity_create` function to the JNI layer.