audb_core/features/input/
scripts.rs

1use anyhow::Result;
2use crate::tools::{session::DeviceSession, ssh::SshClient};
3use russh::client::Handle;
4use std::path::Path;
5
6// Embed scripts at compile time
7const TAP_SCRIPT: &str = include_str!("../../scripts/tap.py");
8const SWIPE_SCRIPT: &str = include_str!("../../scripts/swipe.py");
9
10const REMOTE_TAP_PATH: &str = "/tmp/audb_tap.py";
11const REMOTE_SWIPE_PATH: &str = "/tmp/audb_swipe.py";
12
13pub struct ScriptManager;
14
15impl ScriptManager {
16    /// Ensure tap script is present on device (using DeviceSession)
17    pub fn ensure_tap_script_with_session(session: &mut DeviceSession) -> Result<()> {
18        Self::ensure_script_with_session(session, REMOTE_TAP_PATH, TAP_SCRIPT)
19    }
20
21    /// Ensure swipe script is present on device (using DeviceSession)
22    pub fn ensure_swipe_script_with_session(session: &mut DeviceSession) -> Result<()> {
23        Self::ensure_script_with_session(session, REMOTE_SWIPE_PATH, SWIPE_SCRIPT)
24    }
25
26    /// Ensure script is present on device with correct content (using DeviceSession)
27    fn ensure_script_with_session(
28        session: &mut DeviceSession,
29        remote_path: &str,
30        script_content: &str,
31    ) -> Result<()> {
32        // Check if script exists with correct size
33        let expected_size = script_content.len();
34        let check_cmd = format!(
35            "test -f {} && stat -c %s {} || echo 0",
36            remote_path, remote_path
37        );
38
39        let result = session.exec(&check_cmd)?;
40        let current_size: usize = result
41            .first()
42            .and_then(|s| s.parse().ok())
43            .unwrap_or(0);
44
45        if current_size != expected_size {
46            // Upload needed
47            let temp_file = std::env::temp_dir().join(
48                Path::new(remote_path).file_name().unwrap()
49            );
50            std::fs::write(&temp_file, script_content)?;
51
52            session.upload_file(&temp_file, Path::new(remote_path))?;
53
54            // Make executable
55            session.exec(&format!("chmod +x {}", remote_path))?;
56
57            // Cleanup local temp
58            std::fs::remove_file(&temp_file).ok();
59        }
60
61        Ok(())
62    }
63
64    // Legacy methods for backward compatibility - deprecated
65    #[deprecated(since = "0.1.0", note = "Use ensure_tap_script_with_session instead")]
66    pub fn ensure_tap_script(session: &mut Handle<SshClient>) -> Result<()> {
67        Self::ensure_script(session, REMOTE_TAP_PATH, TAP_SCRIPT)
68    }
69
70    #[deprecated(since = "0.1.0", note = "Use ensure_swipe_script_with_session instead")]
71    pub fn ensure_swipe_script(session: &mut Handle<SshClient>) -> Result<()> {
72        Self::ensure_script(session, REMOTE_SWIPE_PATH, SWIPE_SCRIPT)
73    }
74
75    #[allow(deprecated)]
76    fn ensure_script(
77        session: &mut Handle<SshClient>,
78        remote_path: &str,
79        script_content: &str,
80    ) -> Result<()> {
81        // Check if script exists with correct size
82        let expected_size = script_content.len();
83        let check_cmd = format!(
84            "test -f {} && stat -c %s {} || echo 0",
85            remote_path, remote_path
86        );
87
88        let result = SshClient::exec(session, &check_cmd)?;
89        let current_size: usize = result
90            .first()
91            .and_then(|s| s.parse().ok())
92            .unwrap_or(0);
93
94        if current_size != expected_size {
95            // Upload needed
96            let temp_file = std::env::temp_dir().join(
97                Path::new(remote_path).file_name().unwrap()
98            );
99            std::fs::write(&temp_file, script_content)?;
100
101            SshClient::upload(session, &temp_file, Path::new(remote_path))?;
102
103            // Make executable
104            SshClient::exec(session, &format!("chmod +x {}", remote_path))?;
105
106            // Cleanup local temp
107            std::fs::remove_file(&temp_file).ok();
108        }
109
110        Ok(())
111    }
112
113    pub fn tap_script_path() -> &'static str {
114        REMOTE_TAP_PATH
115    }
116
117    pub fn swipe_script_path() -> &'static str {
118        REMOTE_SWIPE_PATH
119    }
120
121    /// Get tap script content
122    pub const fn tap_script_content() -> &'static str {
123        TAP_SCRIPT
124    }
125
126    /// Get swipe script content
127    pub const fn swipe_script_content() -> &'static str {
128        SWIPE_SCRIPT
129    }
130}