radb 0.1.8

A Rust Implement Python AdbUtils
Documentation
//! # ADB Utils - Android Debug Bridge Utilities for Rust
//!
//! A comprehensive Rust library for interacting with Android devices through ADB (Android Debug Bridge).
//! This library provides both synchronous and asynchronous interfaces for device management, file operations,
//! shell command execution, and more.
//!
//! ## Features
//!
//! - **Dual API Support**: Both blocking and async/await interfaces
//! - **Device Management**: Connect, disconnect, and manage multiple devices
//! - **File Operations**: Push, pull, list, and manipulate files on devices
//! - **Shell Commands**: Execute shell commands with streaming support
//! - **Screen Operations**: Screenshots, input simulation, and screen control
//! - **App Management**: Install, uninstall, start, and stop applications
//! - **Network Operations**: Port forwarding, reverse forwarding, WiFi control, and network information
//! - **System Information**: Device properties, Android version, hardware info
//! - **Logging**: Logcat streaming and filtering
//!
//! ## Quick Start
//!
//! ### Blocking API
//!
//! ```rust,no_run
//! # #[cfg(feature = "blocking")]
//! # mod blocking_example {
//! use radb::prelude::*;
//!
//! fn main() -> AdbResult<()> {
//!     // Connect to ADB server
//!     let mut client = AdbClient::connect("127.0.0.1:5037")?;
//!     
//!     // Get device list
//!     let devices = client.list_devices()?;
//!     let mut device = devices.into_iter().next().unwrap();
//!     
//!     // Execute shell command
//!     let result = device.shell(["echo", "Hello, ADB!"])?;
//!     println!("Output: {}", result);
//!     
//!     // Take screenshot
//!     let screenshot = device.screenshot()?;
//!     println!("Screenshot: {}x{}", screenshot.width(), screenshot.height());
//!
//!     Ok(())
//! }
//! # }
//! ```
//!
//! ### Async API
//!
//! ```rust,no_run
//! # #[cfg(feature = "tokio_async")]
//! # mod async_example {
//! use radb::prelude::*;
//! use radb::AdbResult;
//! #[tokio::main]
//! async fn main() -> AdbResult<()> {
//!     // Connect to ADB server
//!     let mut client = AdbClient::connect("127.0.0.1:5037").await?;
//!     
//!     // Get device list
//!     let devices = client.list_devices().await?;
//!     let mut device = devices.into_iter().next().unwrap();
//!     
//!     // Execute shell command
//!     let result = device.shell(["echo", "Hello, ADB!"]).await?;
//!     println!("Output: {}", result);
//!     
//!     // Stream logcat
//!     let mut logcat = Box::pin(device.logcat(true, None).await?);
//!     while let Some(line) = logcat.as_mut().next().await {
//!         println!("Log: {}", line?);
//!     }
//!
//!     Ok(())
//! }
//! # }
//! ```
//!
//! ## Feature Flags
//!
//! - `blocking`: Enable blocking/synchronous API (default)
//! - `tokio_async`: Enable async/await API with Tokio runtime
//!
//! `blocking` and `tokio_async` share command construction, response parsing,
//! and ADB sync frame handling. The runtime-specific layers only handle
//! connection setup, IO, and `await` adaptation.
//!
//! ## Error Handling
//!
//! The library uses a comprehensive error system with specific error types:
//!
//! ```rust,no_run
//! use radb::prelude::*;
//!
//! let result: AdbResult<String> = Err(AdbError::command_failed(
//!     "shell invalid_command",
//!     "not found",
//! ));
//!
//! match result {
//!     Ok(output) => println!("Success: {}", output),
//!     Err(AdbError::CommandFailed { command, reason }) => {
//!         eprintln!("Command '{}' failed: {}", command, reason);
//!     }
//!     Err(AdbError::DeviceNotFound { serial }) => {
//!         eprintln!("Device '{}' not found", serial);
//!     }
//!     Err(e) => eprintln!("Other error: {}", e),
//! }
//! ```

// Core modules
pub mod beans;
pub mod client;
pub mod errors;
pub mod protocols;
pub mod sync_protocol;
pub mod utils;

// Re-exports for convenience
pub use client::{AdbClient, AdbDevice};
pub use errors::{AdbError, AdbResult};

// Prelude module for common imports
pub mod prelude {
    //! Common imports for ADB utilities
    //!
    //! This module re-exports the most commonly used types and traits.
    //! Import this module to get started quickly:
    //!
    //! ```rust
    //! use radb::prelude::*;
    //! ```

    pub use crate::beans::{AdbCommand, AppInfo, FileInfo, ForwardItem, NetworkType};
    pub use crate::client::{AdbClient, AdbDevice};
    pub use crate::errors::{AdbError, AdbResult, AdbResultExt};
    pub use crate::utils::{get_free_port, start_adb_server};

    // Re-export commonly used external types
    #[cfg(feature = "tokio_async")]
    pub use futures_util::StreamExt;

    #[cfg(feature = "blocking")]
    pub use std::net::TcpStream;

    #[cfg(feature = "tokio_async")]
    pub use tokio::net::TcpStream;
}

// Convenient type aliases
pub type Result<T> = std::result::Result<T, AdbError>;

// Version and metadata
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub const DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION");
pub const AUTHORS: &str = env!("CARGO_PKG_AUTHORS");

// Library information
pub mod info {
    //! Library metadata and version information

    /// Get library version
    pub fn version() -> &'static str {
        crate::VERSION
    }

    /// Get library description
    pub fn description() -> &'static str {
        crate::DESCRIPTION
    }

    /// Get library authors
    pub fn authors() -> &'static str {
        crate::AUTHORS
    }

    /// Print library information
    pub fn print_info() {
        println!("ADB Utils v{}", version());
        println!("Description: {}", description());
        println!("Authors: {}", authors());
    }
}

// Utilities module with public helpers
pub mod util {
    //! Utility functions for ADB operations

    pub use crate::utils::*;

    /// Check if ADB server is running
    pub fn is_adb_server_running() -> bool {
        use std::net::TcpStream;
        TcpStream::connect("127.0.0.1:5037").is_ok()
    }

    /// Start ADB server if not running
    pub fn ensure_adb_server() -> crate::AdbResult<()> {
        if !is_adb_server_running() {
            start_adb_server();
            // Wait a bit for server to start
            std::thread::sleep(std::time::Duration::from_millis(500));
        }
        Ok(())
    }

    /// Get ADB server version (convenience function)
    #[cfg(feature = "blocking")]
    pub fn get_adb_server_version() -> crate::AdbResult<String> {
        let mut client = crate::AdbClient::connect("127.0.0.1:5037")?;
        client.server_version()
    }

    /// Get ADB server version (async convenience function)
    #[cfg(feature = "tokio_async")]
    pub async fn get_adb_server_version_async() -> crate::AdbResult<String> {
        let mut client = crate::AdbClient::connect("127.0.0.1:5037").await?;
        client.server_version().await
    }
}

// Feature-specific modules
#[cfg(feature = "blocking")]
pub mod blocking {
    //! Blocking/synchronous API
    //!
    //! This module contains the blocking versions of ADB operations.
    //! Use this when you don't need async/await functionality.

    #[allow(unused_imports)]
    pub use crate::client::adb_client::blocking_impl::*;
    #[allow(unused_imports)]
    pub use crate::client::adb_device::blocking_impl::*;
    pub use crate::protocols::blocking::AdbProtocol;
}

#[cfg(feature = "tokio_async")]
pub mod r#async {
    //! Asynchronous API
    //!
    //! This module contains the async versions of ADB operations.
    //! Use this when you need async/await functionality with Tokio.

    #[allow(unused_imports)]
    pub use crate::client::adb_client::async_impl::*;
    #[allow(unused_imports)]
    pub use crate::client::adb_device::async_impl::*;
    pub use crate::protocols::tokio_async::AdbProtocol;
}

// Builder pattern for common operations
pub mod builder {
    //! Builder patterns for complex operations

    use crate::prelude::*;

    /// Builder for ADB client configuration
    pub struct AdbClientBuilder {
        addr: Option<String>,
        timeout: Option<std::time::Duration>,
    }

    impl AdbClientBuilder {
        /// Create a new client builder
        pub fn new() -> Self {
            Self {
                addr: None,
                timeout: None,
            }
        }

        /// Set ADB server address
        pub fn addr<S: Into<String>>(mut self, addr: S) -> Self {
            self.addr = Some(addr.into());
            self
        }

        /// Set connection timeout
        pub fn timeout(mut self, timeout: std::time::Duration) -> Self {
            self.timeout = Some(timeout);
            self
        }

        /// Build the client (blocking version)
        #[cfg(feature = "blocking")]
        pub fn build(self) -> AdbResult<AdbClient> {
            let addr = self.addr.unwrap_or_else(|| "127.0.0.1:5037".to_string());
            AdbClient::connect(addr)
        }

        /// Build the client (async version)
        #[cfg(feature = "tokio_async")]
        pub async fn build_async(self) -> AdbResult<AdbClient> {
            let addr = self.addr.unwrap_or_else(|| "127.0.0.1:5037".to_string());
            AdbClient::connect(addr).await
        }
    }

    impl Default for AdbClientBuilder {
        fn default() -> Self {
            Self::new()
        }
    }
}

// Testing utilities (only available in tests)
#[cfg(test)]
pub mod test_utils {
    //! Testing utilities for ADB operations

    use std::fmt::Debug;

    use crate::prelude::*;

    /// Setup test environment
    pub fn setup_test_env() {
        crate::utils::start_adb_server();
        std::thread::sleep(std::time::Duration::from_millis(500));
    }

    /// Get test device (if available)
    #[cfg(feature = "blocking")]
    pub fn get_test_device() -> Option<AdbDevice<impl std::net::ToSocketAddrs + Clone + Debug>> {
        let mut client = AdbClient::connect("127.0.0.1:5037").ok()?;
        client.list_devices().ok()?.into_iter().next()
    }

    /// Get test device (async version)
    #[cfg(feature = "tokio_async")]
    pub async fn get_test_device_async(
    ) -> Option<AdbDevice<impl tokio::net::ToSocketAddrs + Clone + Debug>> {
        let mut client = AdbClient::connect("127.0.0.1:5037").await.ok()?;
        client.list_devices().await.ok()?.into_iter().next()
    }
}

// Macros for common operations
#[macro_export]
macro_rules! adb_shell {
    ($device:expr, $($arg:expr),+) => {
        $device.shell([$($arg),+])
    };
}

#[macro_export]
macro_rules! adb_expect_device {
    ($client:expr) => {
        $client
            .list_devices()?
            .into_iter()
            .next()
            .ok_or_else(|| $crate::AdbError::device_not_found("No devices found"))?
    };
}

pub use anyhow;
pub use log;

// Conditional exports based on features
#[cfg(feature = "tokio_async")]
pub use tokio;

#[cfg(feature = "blocking")]
pub use std::net;

// Documentation examples
#[cfg(doctest)]
doc_comment::doctest!("../README.md");

// Feature compatibility checks
#[cfg(all(feature = "blocking", feature = "tokio_async"))]
compile_error!("Cannot use both 'blocking' and 'tokio_async' features simultaneously");

#[cfg(not(any(feature = "blocking", feature = "tokio_async")))]
compile_error!("Must enable either 'blocking' or 'tokio_async' feature");

// Platform-specific optimizations
#[cfg(target_os = "android")]
compile_error!("This library is not intended to run on Android devices");

// Export the main ADB namespace for convenience
pub mod adb {
    //! Main ADB namespace with all core functionality

    pub use crate::beans::*;
    pub use crate::client::*;
    pub use crate::errors::*;
    pub use crate::prelude::*;
}