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 16import common from '@ohos.app.ability.common'; 17import request from '@ohos.request'; 18import promptAction from '@ohos.promptAction'; 19import { logger } from '../utils/Logger'; 20import { BackgroundTaskState, TASK_MAX, TOAST_BOTTOM } from '../utils/Constants'; 21 22const TAG: string = 'RequestDownload'; 23 24class RequestDownload { 25 private context: common.UIAbilityContext | undefined = undefined; 26 private waitList: Array<string[]> = []; 27 private downloadTask: request.agent.Task | undefined = undefined; 28 private backgroundDownloadTaskList: Array<request.agent.Task> = []; 29 30 constructor() { 31 setInterval(() => { 32 this.flushBackgroundTask() 33 }, 2000); 34 } 35 36 async downloadFilesBackground(folder: string, files: Array<string>) { 37 logger.info(TAG, 'downloadFiles'); 38 this.context = getContext(this) as common.UIAbilityContext; 39 files.forEach((item: string) => { 40 this.waitList.push([folder, item]); 41 }); 42 } 43 44 async flushBackgroundTask() { 45 let tasks = await request.agent.search({ 46 state: request.agent.State.RUNNING 47 }); 48 if (tasks.length < TASK_MAX && this.waitList.length > 0) { 49 let downloadList: Array<string[]> = []; 50 if (this.waitList.length <= TASK_MAX - tasks.length) { 51 downloadList = this.waitList; 52 this.waitList = []; 53 } else { 54 downloadList = this.waitList.slice(0, TASK_MAX - tasks.length); 55 this.waitList = this.waitList.slice(TASK_MAX - tasks.length, this.waitList.length); 56 } 57 logger.info(TAG, `this.waitList = ${JSON.stringify(this.waitList)}`); 58 this.createBackgroundTask(downloadList); 59 } else { 60 let state = AppStorage.get<number>('backDownTaskState'); 61 logger.info(TAG, `backLists = ${this.backgroundDownloadTaskList.map(i => i.tid)}`); 62 if (state === BackgroundTaskState.RUNNING) { 63 if (tasks.length === 0) { 64 AppStorage.setOrCreate('backDownTaskState', BackgroundTaskState.NONE); 65 this.backgroundDownloadTaskList = []; 66 } 67 } 68 } 69 } 70 71 async createBackgroundTask(downloadList: Array<string[]>) { 72 if (this.context === undefined) { 73 return; 74 } 75 for (let i = 0; i < downloadList.length; i++) { 76 try { 77 let splitUrl = downloadList[i][1].split('//')[1].split('/'); 78 let downloadConfig: request.agent.Config = { 79 action: request.agent.Action.DOWNLOAD, 80 url: downloadList[i][1], 81 method: 'POST', 82 title: 'download', 83 mode: request.agent.Mode.BACKGROUND, 84 network: request.agent.Network.ANY, 85 saveas: `./${downloadList[i][0]}/${splitUrl[splitUrl.length-1]}`, 86 overwrite: true, 87 gauge: true 88 } 89 let downTask = await request.agent.create(this.context, downloadConfig); 90 if (this.backgroundDownloadTaskList.findIndex(task => task.config.url === downTask.config.url) === -1) { 91 this.backgroundDownloadTaskList.push(downTask); 92 } 93 await downTask.start(); 94 } catch (err) { 95 logger.error(TAG, `task err, err = ${JSON.stringify(err)}`); 96 this.waitList.push(downloadList[i]); 97 } 98 } 99 } 100 101 async downloadFile(folder: string, url: string, callback: (progress: number, isSuccess: boolean) => void) { 102 logger.info(TAG, 'downloadFile'); 103 // 查询到存在正在执行的下载任务,提示并返回 104 let tasks = await request.agent.search({ 105 state: request.agent.State.RUNNING, 106 action: request.agent.Action.DOWNLOAD, 107 mode: request.agent.Mode.FOREGROUND 108 }); 109 if (tasks.length > 0) { 110 promptAction.showToast({ message: $r('app.string.have_download_task_tips'), bottom: TOAST_BOTTOM }); 111 return; 112 } 113 let splitUrl = url.split('//')[1].split('/'); 114 let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; 115 let downloadConfig: request.agent.Config = { 116 action: request.agent.Action.DOWNLOAD, 117 url: url, 118 method: 'POST', 119 title: 'download', 120 mode: request.agent.Mode.FOREGROUND, 121 network: request.agent.Network.ANY, 122 saveas: `./${folder}/${splitUrl[splitUrl.length-1]}`, 123 overwrite: true 124 } 125 logger.info(TAG, `downloadFile, downloadConfig = ${JSON.stringify(downloadConfig)}`); 126 try { 127 this.downloadTask = await request.agent.create(context, downloadConfig); 128 this.downloadTask.on('progress', (progress: request.agent.Progress) => { 129 logger.info(TAG, `progress, progress = ${progress.processed} ${progress.state}`); 130 let processed = Number(progress.processed.toString()).valueOf(); 131 let size = progress.sizes[0]; 132 let process: number = Math.floor(processed / size * 100); 133 if (process < 100) { 134 callback(process, false); 135 } 136 }) 137 this.downloadTask.on('completed', (progress: request.agent.Progress) => { 138 logger.info(TAG, `download complete, file= ${url}, progress = ${progress.processed}`); 139 callback(100, true); 140 this.deleteTask(); 141 }) 142 this.downloadTask.on('failed', async (progress: request.agent.Progress) => { 143 if (this.downloadTask) { 144 let taskInfo = await request.agent.show(this.downloadTask.tid); 145 logger.info(TAG, `fail, resean = ${taskInfo.reason}, faults = ${JSON.stringify(taskInfo.faults)}`); 146 } 147 callback(100, false); 148 this.deleteTask(); 149 }) 150 await this.downloadTask.start(); 151 } catch (err) { 152 logger.error(TAG, `task err, err = ${JSON.stringify(err)}`); 153 callback(100, false); 154 } 155 } 156 157 async pauseOrResume() { 158 let state = AppStorage.get<number>('backDownTaskState'); 159 if (state === BackgroundTaskState.RUNNING) { 160 await this.pause(); 161 AppStorage.setOrCreate('backDownTaskState', BackgroundTaskState.PAUSE); 162 } else if (state === BackgroundTaskState.PAUSE) { 163 await this.resume(); 164 AppStorage.setOrCreate('backDownTaskState', BackgroundTaskState.RUNNING); 165 } else { 166 logger.info(TAG, 'this task state is error'); 167 } 168 } 169 170 async pause() { 171 logger.info(TAG, 'pause'); 172 if (this.backgroundDownloadTaskList.length === 0) { 173 return; 174 } 175 try { 176 this.backgroundDownloadTaskList.forEach(async task => { 177 await task.pause(); 178 }) 179 } catch (err) { 180 logger.info(TAG, `pause fail,err= ${JSON.stringify(err)}`); 181 } 182 } 183 184 async resume() { 185 logger.info(TAG, 'resume'); 186 if (this.backgroundDownloadTaskList.length === 0) { 187 return; 188 } 189 try { 190 this.backgroundDownloadTaskList.forEach(async task => { 191 await task.resume(); 192 }) 193 } catch (err) { 194 logger.info(TAG, `resume fail,err= ${JSON.stringify(err)}`); 195 } 196 } 197 198 async deleteTask() { 199 if (this.downloadTask) { 200 try { 201 this.downloadTask.off('progress'); 202 this.downloadTask.off('completed'); 203 this.downloadTask.off('failed'); 204 await request.agent.remove(this.downloadTask.tid); 205 } catch (err) { 206 logger.info(TAG, `deleteTask fail, err= ${JSON.stringify(err)}`); 207 } 208 } 209 this.downloadTask = undefined; 210 } 211 212 async deleteAllBackTasks() { 213 if (this.backgroundDownloadTaskList.length > 0) { 214 try { 215 this.backgroundDownloadTaskList.forEach(async task => { 216 await request.agent.remove(task.tid); 217 }) 218 this.backgroundDownloadTaskList = []; 219 AppStorage.setOrCreate('backDownTaskState', BackgroundTaskState.NONE); 220 } catch (err) { 221 logger.info(TAG, `deleteAllTask fail, err= ${JSON.stringify(err)}`); 222 } 223 } 224 } 225} 226 227export const requestDownload = new RequestDownload();