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  */
15 use hdc::common::base::Base;
16 use hdc::common::filemanager::FileManager;
17 use hdc::common::hdcfile;
18 use hdc::common::hdctransfer::{self, HdcTransferBase};
19 use hdc::config::HdcCommand;
20 use hdc::config::TaskMessage;
21 use hdc::config::TRANSFER_FUNC_NAME;
22 use hdc::config::{self, INSTALL_TAR_MAX_CNT};
23 use hdc::serializer::serialize::Serialization;
24 use hdc::transfer;
25 use hdc::transfer::EchoLevel;
26 use hdc::utils;
27 use std::collections::HashMap;
28 use std::path::PathBuf;
29 use std::sync::Arc;
30 use ylong_runtime::sync::Mutex;
31 #[cfg(feature = "host")]
32 extern crate ylong_runtime_static as ylong_runtime;
33 use hdc::tar::compress::Compress;
34 
35 pub struct HostAppTask {
36     pub transfer: HdcTransferBase,
37     pub printed_msg_len: usize,
38 }
39 
40 impl HostAppTask {
41     ///  complie failed ,associated function `new` is never used
newnull42     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 
50 type HostAppTask_ = Arc<Mutex<HostAppTask>>;
51 type HostAppTaskMap_ = Arc<Mutex<HashMap<(u32, u32), HostAppTask_>>>;
52 
53 pub struct HostAppTaskMap {}
54 impl HostAppTaskMap {
get_instancenull55     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 
95 async 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 
137 async 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 
143 async 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 
dir_to_tarnull158 fn 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 
174 async 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 
179 async 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 
194 async 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 
250 async 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 
304 async 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 
321 async 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 
349 pub 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