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