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::io;
29 use std::path::PathBuf;
30 use std::sync::Arc;
31 use ylong_runtime::sync::Mutex;
32 #[cfg(feature = "host")]
33 extern crate ylong_runtime_static as ylong_runtime;
34 use hdc::tar::compress::Compress;
35
36 pub struct HostAppTask {
37 pub transfer: HdcTransferBase,
38 pub printed_msg_len: usize,
39 }
40
41 impl HostAppTask {
42 /// complie failed ,associated function `new` is never used
new(_session_id: u32, _channel_id: u32) -> Self43 pub fn new(_session_id: u32, _channel_id: u32) -> Self {
44 Self {
45 transfer: HdcTransferBase::new(_session_id, _channel_id),
46 printed_msg_len: 0,
47 }
48 }
49 }
50
51 type HostAppTask_ = Arc<Mutex<HostAppTask>>;
52 type HostAppTaskMap_ = Arc<Mutex<HashMap<(u32, u32), HostAppTask_>>>;
53
54 pub struct HostAppTaskMap {}
55 impl HostAppTaskMap {
get_instance() -> HostAppTaskMap_56 fn get_instance() -> HostAppTaskMap_ {
57 static mut HOSTAPPTASKMAP: Option<HostAppTaskMap_> = None;
58 unsafe {
59 HOSTAPPTASKMAP
60 .get_or_insert_with(|| Arc::new(Mutex::new(HashMap::new())))
61 .clone()
62 }
63 }
64
put(session_id: u32, channel_id: u32, host_app_task: HostAppTask)65 pub async fn put(session_id: u32, channel_id: u32, host_app_task: HostAppTask) {
66 let arc_map = Self::get_instance();
67 let mut map = arc_map.lock().await;
68 map.insert(
69 (session_id, channel_id),
70 Arc::new(Mutex::new(host_app_task)),
71 );
72 }
73
exist(session_id: u32, channel_id: u32) -> Result<bool, ()>74 pub async fn exist(session_id: u32, channel_id: u32) -> Result<bool, ()> {
75 let arc_map = Self::get_instance();
76 let map = arc_map.lock().await;
77 Ok(map.contains_key(&(session_id, channel_id)))
78 }
79
remove(session_id: u32, channel_id: u32) -> Option<HostAppTask_>80 pub async fn remove(session_id: u32, channel_id: u32) -> Option<HostAppTask_> {
81 let arc_map = Self::get_instance();
82 let mut map = arc_map.lock().await;
83 map.remove(&(session_id, channel_id))
84 }
85
get(session_id: u32, channel_id: u32) -> Option<HostAppTask_>86 pub async fn get(session_id: u32, channel_id: u32) -> Option<HostAppTask_> {
87 let arc_map = Self::get_instance();
88 let map = arc_map.lock().await;
89 let Some(arc_task) = map.get(&(session_id, channel_id)) else {
90 return None;
91 };
92 Some(arc_task.clone())
93 }
94 }
95
send_to_client(channel_id: u32, level: EchoLevel, message: String) -> io::Result<()>96 pub async fn send_to_client(channel_id: u32, level: EchoLevel, message: String) -> io::Result<()> {
97 transfer::send_channel_msg(channel_id, level, message).await
98 }
99
echo_client(channel_id: u32, message: String) -> io::Result<()>100 pub async fn echo_client(channel_id: u32, message: String) -> io::Result<()> {
101 send_to_client(channel_id, EchoLevel::INFO, message).await
102 }
103
check_install_continue( session_id: u32, channel_id: u32, mode_type: config::AppModeType, str: String, ) -> bool104 async fn check_install_continue(
105 session_id: u32,
106 channel_id: u32,
107 mode_type: config::AppModeType,
108 str: String,
109 ) -> bool {
110 let mut _mode_desc = String::from("");
111 match mode_type {
112 config::AppModeType::Install => _mode_desc = String::from("App install"),
113 config::AppModeType::UnInstall => _mode_desc = String::from("App uninstall"),
114 }
115 let Some(arc_task) = HostAppTaskMap::get(session_id, channel_id).await else {
116 hdc::error!("Get host app task failed");
117 return false;
118 };
119 let mut task = arc_task.lock().await;
120 let msg = str[task.printed_msg_len..].to_owned();
121 let message = format!(
122 "{} path:{}, queuesize:{}, msg:{}",
123 _mode_desc,
124 task.transfer.local_path.clone(),
125 task.transfer.task_queue.len(),
126 msg
127 );
128 task.printed_msg_len = str.len();
129 let _ = echo_client(channel_id, message).await;
130 if task.transfer.task_queue.is_empty() {
131 let _ = echo_client(channel_id, String::from("AppMod finish")).await;
132 task_finish(session_id, channel_id).await;
133 hdctransfer::close_channel(channel_id).await;
134 return false;
135 }
136 drop(task);
137 install_single(session_id, channel_id).await;
138 put_app_check(session_id, channel_id).await;
139 true
140 }
141
do_app_uninstall(session_id: u32, channel_id: u32, _payload: &[u8])142 async fn do_app_uninstall(session_id: u32, channel_id: u32, _payload: &[u8]) {
143 let app_uninstall_message = TaskMessage {
144 channel_id,
145 command: HdcCommand::AppUninstall,
146 payload: _payload.to_vec(),
147 };
148 transfer::put(session_id, app_uninstall_message).await;
149 }
150
do_app_finish(session_id: u32, channel_id: u32, _payload: &[u8]) -> bool151 async fn do_app_finish(session_id: u32, channel_id: u32, _payload: &[u8]) -> bool {
152 let mode = config::AppModeType::try_from(_payload[0]);
153 if let Ok(mode_type) = mode {
154 let str = match String::from_utf8(_payload[2..].to_vec()) {
155 Ok(str) => str,
156 Err(err) => {
157 hdc::error!("do_app_finish from_utf8 error, {err}");
158 return false;
159 }
160 };
161 return check_install_continue(session_id, channel_id, mode_type, str).await;
162 }
163 false
164 }
165
dir_to_tar(dir_path: PathBuf) -> Result<String, String>166 fn dir_to_tar(dir_path: PathBuf) -> Result<String, String> {
167 let mut compress = Compress::new();
168 compress.updata_prefix(dir_path.clone());
169 if let Err(err) = compress.add_path(&dir_path) {
170 return Err(format!("add path fail, {err}"));
171 }
172 compress.updata_max_count(INSTALL_TAR_MAX_CNT);
173
174 let tar_name = utils::get_pseudo_random_u32().to_string() + ".tar";
175 let tar_path = std::env::temp_dir().join(tar_name);
176 match compress.compress(tar_path.clone()) {
177 Ok(_) => Ok(tar_path.display().to_string()),
178 Err(err) => Err(format!("compress {} fial, {}", tar_path.display(), err)),
179 }
180 }
181
task_finish(session_id: u32, channel_id: u32)182 async fn task_finish(session_id: u32, channel_id: u32) {
183 hdctransfer::transfer_task_finish(channel_id, session_id).await
184 }
185
put_app_check(session_id: u32, channel_id: u32)186 async fn put_app_check(session_id: u32, channel_id: u32) {
187 let Some(arc_task) = HostAppTaskMap::get(session_id, channel_id).await else {
188 hdc::error!("Get host app task failed");
189 return;
190 };
191 let task = arc_task.lock().await;
192 let file_check_message = TaskMessage {
193 channel_id,
194 command: HdcCommand::AppCheck,
195 payload: task.transfer.transfer_config.serialize(),
196 };
197 transfer::put(session_id, file_check_message).await
198 }
199
install_single(session_id: u32, channel_id: u32)200 async fn install_single(session_id: u32, channel_id: u32) {
201 let Some(arc_task) = HostAppTaskMap::get(session_id, channel_id).await else {
202 hdc::error!("Get host app task failed");
203 return;
204 };
205 let mut task = arc_task.lock().await;
206 match task.transfer.task_queue.pop() {
207 Some(loc_path) => task.transfer.local_path = loc_path,
208 None => {
209 hdc::error!("Get local path is None");
210 task_finish(session_id, channel_id).await;
211 return;
212 }
213 }
214 let local_path = task.transfer.local_path.clone();
215 let mut file_manager = FileManager::new(local_path.clone());
216 let (open_result, error_msg) = file_manager.open();
217 if open_result {
218 let file_size = file_manager.file_size();
219 task.transfer.transfer_config.file_size = file_size;
220 task.transfer.file_size = file_size;
221 task.transfer.transfer_config.optional_name = utils::get_pseudo_random_u32().to_string();
222 if let Some(index) = local_path.rfind('.') {
223 let str = local_path.as_str();
224 task.transfer
225 .transfer_config
226 .optional_name
227 .push_str(&str[index..]);
228 }
229 // if config.hold_timestamp {}
230 task.transfer.transfer_config.path = task.transfer.remote_path.clone();
231 } else {
232 println!("other command {:#?}", error_msg);
233 task_finish(session_id, channel_id).await;
234 }
235 }
236
init_install(session_id: u32, channel_id: u32, command: &String) -> bool237 async fn init_install(session_id: u32, channel_id: u32, command: &String) -> bool {
238 let (argv, argc) = Base::split_command_to_args(command);
239 if argc < 1 {
240 return false;
241 }
242
243 let Some(arc_task) = HostAppTaskMap::get(session_id, channel_id).await else {
244 hdc::error!("Get host app task failed");
245 return false;
246 };
247 let mut task = arc_task.lock().await;
248 let mut i = 1usize;
249 let mut options = String::from("");
250 while i < argc as usize {
251 if argv[i] == "-cwd" {
252 if i + 1 < argc as usize {
253 task.transfer.transfer_config.client_cwd = argv[i + 1].clone();
254 i += 1;
255 }
256 } else if argv[i].starts_with('-') {
257 if !options.is_empty() {
258 options.push(' ');
259 }
260 options.push_str(&argv[i].clone());
261 } else {
262 let mut path = argv[i].clone() as String;
263 path = Base::extract_relative_path(
264 &task.transfer.transfer_config.client_cwd,
265 path.as_str(),
266 );
267 if path.ends_with(".hap") || path.ends_with(".hsp") {
268 task.transfer.task_queue.push(path.clone());
269 } else {
270 match dir_to_tar(PathBuf::from(path)) {
271 Ok(tar_file) => {
272 hdc::info!("dir_to_tar success, path = {}", tar_file);
273 task.transfer.task_queue.push(tar_file)
274 }
275 Err(err) => {
276 hdc::error!("{}", err);
277 return false;
278 }
279 }
280 }
281 }
282 i += 1;
283 }
284
285 if task.transfer.task_queue.is_empty() {
286 return false;
287 }
288
289 task.transfer.transfer_config.options = options.clone();
290 task.transfer.transfer_config.function_name = TRANSFER_FUNC_NAME.to_string();
291 task.transfer.is_master = true;
292 drop(task);
293 install_single(session_id, channel_id).await;
294
295 true
296 }
297
command_dispatch( session_id: u32, channel_id: u32, _command: HdcCommand, _payload: &[u8], _payload_size: u16, ) -> Result<bool, &str>298 pub async fn command_dispatch(
299 session_id: u32,
300 channel_id: u32,
301 _command: HdcCommand,
302 _payload: &[u8],
303 _payload_size: u16,
304 ) -> Result<bool, &str> {
305 match _command {
306 HdcCommand::AppInit => {
307 let s = String::from_utf8(_payload.to_vec());
308 match s {
309 Ok(str) => {
310 if !init_install(session_id, channel_id, &str).await {
311 let message = "Not any installation package was found";
312 let _ =
313 send_to_client(channel_id, EchoLevel::FAIL, message.to_owned()).await;
314 transfer::TcpMap::end(channel_id).await;
315 return Ok(false);
316 }
317 hdcfile::wake_up_slaver(session_id, channel_id).await;
318 put_app_check(session_id, channel_id).await
319 }
320 Err(e) => {
321 println!("error {}", e);
322 }
323 }
324 }
325 HdcCommand::AppBegin => {
326 let Some(arc_task) = HostAppTaskMap::get(session_id, channel_id).await else {
327 hdc::error!("Get host app task failed");
328 return Ok(false);
329 };
330 let task = arc_task.lock().await;
331 hdctransfer::transfer_begin(&task.transfer, HdcCommand::AppData).await;
332 }
333 HdcCommand::AppUninstall => {
334 let s = String::from_utf8(_payload.to_vec());
335 let mut options = String::from("");
336 match s {
337 Ok(str) => {
338 let (argv, argc) = Base::split_command_to_args(&str);
339 if argc < 1 {
340 return Ok(false);
341 }
342 options = argv[1..].join(" ");
343 }
344 Err(e) => {
345 println!("error {}", e);
346 }
347 }
348 do_app_uninstall(session_id, channel_id, options.as_bytes()).await;
349 }
350 HdcCommand::AppFinish => {
351 do_app_finish(session_id, channel_id, _payload).await;
352 }
353 _ => {
354 println!("other command");
355 }
356 }
357 Ok(true)
358 }
359