xref: /developtools/hdc/hdc_rust/src/host/host_app.rs (revision cc290419)
1/*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15use hdc::common::base::Base;
16use hdc::common::filemanager::FileManager;
17use hdc::common::hdcfile;
18use hdc::common::hdctransfer::{self, HdcTransferBase};
19use hdc::config::HdcCommand;
20use hdc::config::TaskMessage;
21use hdc::config::TRANSFER_FUNC_NAME;
22use hdc::config::{self, INSTALL_TAR_MAX_CNT};
23use hdc::serializer::serialize::Serialization;
24use hdc::transfer;
25use hdc::transfer::EchoLevel;
26use hdc::utils;
27use std::collections::HashMap;
28use std::path::PathBuf;
29use std::sync::Arc;
30use ylong_runtime::sync::Mutex;
31#[cfg(feature = "host")]
32extern crate ylong_runtime_static as ylong_runtime;
33use hdc::tar::compress::Compress;
34
35pub struct HostAppTask {
36    pub transfer: HdcTransferBase,
37    pub printed_msg_len: usize,
38}
39
40impl HostAppTask {
41    ///  complie failed ,associated function `new` is never used
42    pub fn new(_session_id: u32, _channel_id: u32) -> Self {
43        Self {
44            transfer: HdcTransferBase::new(_session_id, _channel_id),
45            printed_msg_len: 0,
46        }
47    }
48}
49
50type HostAppTask_ = Arc<Mutex<HostAppTask>>;
51type HostAppTaskMap_ = Arc<Mutex<HashMap<(u32, u32), HostAppTask_>>>;
52
53pub struct HostAppTaskMap {}
54impl HostAppTaskMap {
55    fn get_instance() -> HostAppTaskMap_ {
56        static mut HOSTAPPTASKMAP: Option<HostAppTaskMap_> = None;
57        unsafe {
58            HOSTAPPTASKMAP
59                .get_or_insert_with(|| Arc::new(Mutex::new(HashMap::new())))
60                .clone()
61        }
62    }
63
64    pub async fn put(session_id: u32, channel_id: u32, host_app_task: HostAppTask) {
65        let arc_map = Self::get_instance();
66        let mut map = arc_map.lock().await;
67        map.insert(
68            (session_id, channel_id),
69            Arc::new(Mutex::new(host_app_task)),
70        );
71    }
72
73    pub async fn exist(session_id: u32, channel_id: u32) -> Result<bool, ()> {
74        let arc_map = Self::get_instance();
75        let map = arc_map.lock().await;
76        Ok(map.contains_key(&(session_id, channel_id)))
77    }
78
79    pub async fn remove(session_id: u32, channel_id: u32) -> Option<HostAppTask_> {
80        let arc_map = Self::get_instance();
81        let mut map = arc_map.lock().await;
82        map.remove(&(session_id, channel_id))
83    }
84
85    pub async fn get(session_id: u32, channel_id: u32) -> Option<HostAppTask_> {
86        let arc_map = Self::get_instance();
87        let map = arc_map.lock().await;
88        let Some(arc_task) = map.get(&(session_id, channel_id)) else {
89            return None;
90        };
91        Some(arc_task.clone())
92    }
93}
94
95async fn check_install_continue(
96    session_id: u32,
97    channel_id: u32,
98    mode_type: config::AppModeType,
99    str: String,
100) -> bool {
101    let mode_desc = match mode_type {
102        config::AppModeType::Install => String::from("App install"),
103        config::AppModeType::UnInstall => String::from("App uninstall"),
104    };
105    let Some(arc_task) = HostAppTaskMap::get(session_id, channel_id).await else {
106        hdc::error!("Get host app task failed");
107        return false;
108    };
109    let mut task = arc_task.lock().await;
110    let msg = str[task.printed_msg_len..].to_owned();
111    let local_path = if !task.transfer.local_tar_raw_path.is_empty() {
112        &task.transfer.local_tar_raw_path
113    } else {
114        &task.transfer.local_path
115    };
116    let message =
117        format!("{} path:{}, queuesize:{}, msg:{}", mode_desc, local_path, task.transfer.task_queue.len(), msg);
118    hdc::info!("{message}");
119    task.printed_msg_len = str.len();
120    let _ = transfer::send_channel_msg(channel_id, EchoLevel::INFO, message).await;
121    if task.transfer.task_queue.is_empty() {
122        let _ = transfer::send_channel_msg(channel_id, EchoLevel::INFO, String::from("AppMod finish")).await;
123        task_finish(session_id, channel_id).await;
124        hdctransfer::close_channel(channel_id).await;
125        return false;
126    }
127    drop(task);
128    if let Err(err_msg) = install_single(session_id, channel_id).await {
129        let _ = transfer::send_channel_msg(channel_id, EchoLevel::FAIL, err_msg).await;
130        task_finish(session_id, channel_id).await;
131        return false;
132    }
133    put_app_check(session_id, channel_id).await;
134    true
135}
136
137async fn do_app_uninstall(session_id: u32, channel_id: u32, payload: Vec<u8>) {
138    hdc::info!("send HdcCommand::AppUninstall");
139    let app_uninstall_message = TaskMessage { channel_id, command: HdcCommand::AppUninstall, payload };
140    transfer::put(session_id, app_uninstall_message).await;
141}
142
143async fn do_app_finish(session_id: u32, channel_id: u32, payload: &[u8]) -> bool {
144    let mode = config::AppModeType::try_from(payload[0]);
145    if let Ok(mode_type) = mode {
146        let str = match String::from_utf8(payload[2..].to_vec()) {
147            Ok(str) => str,
148            Err(err) => {
149                hdc::error!("do_app_finish from_utf8 error, {err}");
150                return false;
151            }
152        };
153        return check_install_continue(session_id, channel_id, mode_type, str).await;
154    }
155    false
156}
157
158fn dir_to_tar(dir_path: PathBuf) -> Result<String, String> {
159    let mut compress = Compress::new();
160    compress.updata_prefix(dir_path.clone());
161    if let Err(err) = compress.add_path(&dir_path) {
162        return Err(format!("Package as tar and add path error, {err}"));
163    }
164    compress.updata_max_count(INSTALL_TAR_MAX_CNT);
165
166    let tar_name = utils::get_pseudo_random_u32().to_string() + ".tar";
167    let tar_path = std::env::temp_dir().join(tar_name);
168    match compress.compress(tar_path.clone()) {
169        Ok(_) => Ok(tar_path.display().to_string()),
170        Err(err) => Err(format!("compress {} fial, {}", tar_path.display(), err)),
171    }
172}
173
174async fn task_finish(session_id: u32, channel_id: u32) {
175    HostAppTaskMap::remove(session_id, channel_id).await;
176    hdctransfer::transfer_task_finish(channel_id, session_id).await
177}
178
179async fn put_app_check(session_id: u32, channel_id: u32) {
180    let Some(arc_task) = HostAppTaskMap::get(session_id, channel_id).await else {
181        hdc::error!("Get host app task failed");
182        return;
183    };
184    let task = arc_task.lock().await;
185    hdc::info!("send HdcCommand::AppCheck");
186    let file_check_message = TaskMessage {
187        channel_id,
188        command: HdcCommand::AppCheck,
189        payload: task.transfer.transfer_config.serialize(),
190    };
191    transfer::put(session_id, file_check_message).await
192}
193
194async fn install_single(session_id: u32, channel_id: u32) -> Result<(), String> {
195    let Some(arc_task) = HostAppTaskMap::get(session_id, channel_id).await else {
196        hdc::error!("Get host app task failed");
197        return Err("Internal error, Pls try again".to_owned());
198    };
199    let mut task = arc_task.lock().await;
200    match task.transfer.task_queue.pop() {
201        Some(loc_path) => {
202            let loc_pathbuff = PathBuf::from(loc_path.clone());
203            if loc_pathbuff.is_file() {
204                task.transfer.local_path = loc_path;
205                task.transfer.local_tar_raw_path = String::new();
206            } else if loc_pathbuff.is_dir() {
207                match dir_to_tar(loc_pathbuff) {
208                    Ok(tar_file) => {
209                        hdc::info!("dir_to_tar success, path = {}", tar_file);
210                        task.transfer.local_path = tar_file;
211                        task.transfer.local_tar_raw_path = loc_path;
212                    }
213                    Err(err) => {
214                        hdc::error!("{}", err);
215                        return Err("Folder packaging failed".to_owned());
216                    }
217                }
218            } else {
219                return Err(format!("Error opening file: no such file or directory, path:{loc_path}"));
220            }
221        }
222        None => {
223            hdc::info!("task_queue is empty, not need install");
224            return Err("Not any installation package was found".to_owned());
225        }
226    }
227    let local_path = task.transfer.local_path.clone();
228    let mut file_manager = FileManager::new(local_path.clone());
229    let (open_result, error_msg) = file_manager.open();
230    if open_result {
231        let file_size = file_manager.file_size();
232        task.transfer.transfer_config.file_size = file_size;
233        task.transfer.file_size = file_size;
234        task.transfer.transfer_config.optional_name = utils::get_pseudo_random_u32().to_string();
235        if let Some(index) = local_path.rfind('.') {
236            let str = local_path.as_str();
237            task.transfer
238                .transfer_config
239                .optional_name
240                .push_str(&str[index..]);
241        }
242        task.transfer.transfer_config.path = task.transfer.remote_path.clone();
243        Ok(())
244    } else {
245        hdc::error!("file_manager.open {error_msg}");
246        Err(error_msg)
247    }
248}
249
250async fn init_install(session_id: u32, channel_id: u32, command: &String) -> Result<(), String> {
251    let (argv, argc) = Base::split_command_to_args(command);
252    if argc < 1 {
253        hdc::error!("argc {argc}, {command}");
254        return Err("Invalid parameter".to_owned());
255    }
256
257    let Some(arc_task) = HostAppTaskMap::get(session_id, channel_id).await else {
258        hdc::error!("Get host app task failed");
259        return Err("Internal error, Pls try again".to_owned());
260    };
261    let mut task = arc_task.lock().await;
262    let mut i = 1usize;
263    let mut options = String::from("");
264    while i < argc as usize {
265        if argv[i] == "-cwd" {
266            if i + 1 < argc as usize {
267                task.transfer.transfer_config.client_cwd = argv[i + 1].clone();
268                i += 1;
269            }
270        } else if argv[i].starts_with('-') {
271            if !options.is_empty() {
272                options.push(' ');
273            }
274            options.push_str(&argv[i].clone());
275        } else {
276            let mut path = argv[i].clone() as String;
277            path = Base::extract_relative_path(
278                &task.transfer.transfer_config.client_cwd,
279                path.as_str(),
280            );
281            if path.ends_with(".hap") || path.ends_with(".hsp") {
282                task.transfer.task_queue.push(path);
283            } else {
284                let pathbuff = PathBuf::from(path.clone());
285                if pathbuff.is_dir() {
286                    task.transfer.task_queue.push(path);
287                }
288            }
289        }
290        i += 1;
291    }
292
293    if task.transfer.task_queue.is_empty() {
294        return Err("Not any installation package was found".to_owned());
295    }
296
297    task.transfer.transfer_config.options = options.clone();
298    task.transfer.transfer_config.function_name = TRANSFER_FUNC_NAME.to_string();
299    task.transfer.is_master = true;
300    drop(task);
301    install_single(session_id, channel_id).await
302}
303
304async fn task_app_install(session_id: u32, channel_id: u32, payload: &[u8]) -> Result<(), String> {
305    match String::from_utf8(payload.to_vec()) {
306        Ok(str) => {
307            hdc::info!("cmd : {str}");
308            init_install(session_id, channel_id, &str).await?;
309            hdcfile::wake_up_slaver(session_id, channel_id).await;
310            put_app_check(session_id, channel_id).await
311        }
312        Err(e) => {
313            hdc::error!("error {}", e);
314            let err_msg = "Internal error, Pls try again".to_owned();
315            return Err(err_msg);
316        }
317    }
318    Ok(())
319}
320
321async fn task_app_uninstall(session_id: u32, channel_id: u32, payload: &[u8]) -> Result<(), String> {
322    match String::from_utf8(payload.to_vec()) {
323        Ok(str) => {
324            hdc::info!("cmd {str}");
325            let (argv, argc) = Base::split_command_to_args(&str);
326            if argc < 1 {
327                hdc::error!("argc {argc}");
328                let err_msg = String::from("Invalid input parameters");
329                return Err(err_msg);
330            }
331            let (_opt, pack): (Vec<&String>, Vec<&String>) = argv.iter().partition(|arg| arg.starts_with('-'));
332            if pack.len() <= 1 {
333                let err_msg = String::from("Invalid input parameters");
334                return Err(err_msg);
335            }
336            let options = argv[1..].join(" ");
337            let payload = options.as_bytes().to_vec();
338            do_app_uninstall(session_id, channel_id, payload).await;
339        }
340        Err(e) => {
341            println!("error {}", e);
342            let err_msg = "Internal error, Pls try again".to_owned();
343            return Err(err_msg);
344        }
345    }
346    Ok(())
347}
348
349pub async fn command_dispatch(
350    session_id: u32, channel_id: u32, command: HdcCommand, payload: &[u8],
351) -> Result<bool, &str> {
352    match command {
353        HdcCommand::AppInit => {
354            if let Err(err_msg) = task_app_install(session_id, channel_id, payload).await {
355                let _ = transfer::send_channel_msg(channel_id, EchoLevel::FAIL, err_msg).await;
356                transfer::TcpMap::end(channel_id).await;
357                task_finish(session_id, channel_id).await;
358                return Ok(false);
359            }
360        }
361        HdcCommand::AppBegin => {
362            let Some(arc_task) = HostAppTaskMap::get(session_id, channel_id).await else {
363                hdc::error!("Get host app task failed");
364                let err_msg = "Internal error, Pls try again".to_owned();
365                let _ = transfer::send_channel_msg(channel_id, EchoLevel::FAIL, err_msg).await;
366                transfer::TcpMap::end(channel_id).await;
367                task_finish(session_id, channel_id).await;
368                return Ok(false);
369            };
370            let task = arc_task.lock().await;
371            hdc::info!("recv HdcCommand::AppBegin");
372            hdctransfer::transfer_begin(&task.transfer, HdcCommand::AppData).await;
373        }
374        HdcCommand::AppUninstall => {
375            if let Err(err_msg) = task_app_uninstall(session_id, channel_id, payload).await {
376                let _ = transfer::send_channel_msg(channel_id, EchoLevel::FAIL, err_msg).await;
377                transfer::TcpMap::end(channel_id).await;
378                task_finish(session_id, channel_id).await;
379                return Ok(false);
380            }
381        },
382        HdcCommand::AppFinish => {
383            hdc::info!("recv HdcCommand::AppFinish");
384            do_app_finish(session_id, channel_id, payload).await;
385        }
386        _ => {
387            println!("other command");
388        }
389    }
390    Ok(true)
391}
392