audb_core/features/app/
launch.rs

1// Launch command implementation for Aurora OS applications
2//
3// Uses RuntimeManager D-Bus API to start applications via:
4// gdbus call --system --dest ru.omp.RuntimeManager
5//   --object-path /ru/omp/RuntimeManager/Control1
6//   --method ru.omp.RuntimeManager.Control1.Start "app_name"
7
8use crate::features::config::{device_store::DeviceStore, state::DeviceState};
9use crate::tools::{
10    macros::print_info,
11    session::DeviceSession,
12    types::DeviceIdentifier,
13};
14use anyhow::{anyhow, Context, Result};
15
16pub async fn execute(app_name: &str) -> Result<()> {
17    // Validate app_name
18    validate_app_name(app_name)?;
19
20    // Get device and establish session
21    let current_host = DeviceState::get_current()?;
22    let device_id = DeviceIdentifier::Host(current_host);
23    let device = DeviceStore::find(&device_id)?;
24
25    print_info(format!("Launching {} on device {}", app_name, device.display_name()));
26    print_info(format!("Connecting to {}:{}...", device.host, device.port));
27
28    let mut session = DeviceSession::connect(&device)
29        .context("Failed to connect to device")?;
30
31    // Build D-Bus command to launch app using RuntimeManager
32    let launch_command = format!(
33        "gdbus call --system --dest ru.omp.RuntimeManager \
34         --object-path /ru/omp/RuntimeManager/Control1 \
35         --method ru.omp.RuntimeManager.Control1.Start \"{}\"",
36        app_name
37    );
38
39    print_info("Launching application...");
40
41    let output = session.exec(&launch_command)
42        .context("Failed to launch application")?;
43
44    // Display output (shows instance ID and PID)
45    for line in &output {
46        if !line.is_empty() {
47            println!("{}", line);
48        }
49    }
50
51    print_info("Application launched successfully");
52    Ok(())
53}
54
55fn validate_app_name(app_name: &str) -> Result<()> {
56    if app_name.is_empty() {
57        return Err(anyhow!("App name cannot be empty"));
58    }
59    if !app_name.contains('.') {
60        return Err(anyhow!(
61            "Invalid app name: '{}'. Expected D-Bus format: ru.domain.AppName",
62            app_name
63        ));
64    }
65    if app_name.len() > 255 {
66        return Err(anyhow!("App name exceeds D-Bus limit of 255 characters"));
67    }
68    Ok(())
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn test_validate_app_name_valid() {
77        assert!(validate_app_name("ru.auroraos.MLPackLearning").is_ok());
78        assert!(validate_app_name("com.example.App").is_ok());
79    }
80
81    #[test]
82    fn test_validate_app_name_empty() {
83        assert!(validate_app_name("").is_err());
84    }
85
86    #[test]
87    fn test_validate_app_name_no_dot() {
88        assert!(validate_app_name("InvalidAppName").is_err());
89    }
90
91    #[test]
92    fn test_validate_app_name_too_long() {
93        let long_name = "a".repeat(256);
94        assert!(validate_app_name(&long_name).is_err());
95    }
96}