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