• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 { urlUtils } from '../utils/UrlUtils';
20import { logger } from '../utils/Logger';
21import { MediaUtils } from '../utils/MediaUtils';
22import { BackgroundTaskState, UPLOAD_TOKEN, TOAST_BOTTOM, TASK_MAX } from '../utils/Constants';
23
24const TAG: string = 'RequestUpload';
25const HEADER: Record<string, string> = { 'Content-Type': 'multipart/form-data' };
26
27class Upload {
28  private mediaUtils: MediaUtils = new MediaUtils();
29  private config: request.agent.Config = {
30    action: request.agent.Action.UPLOAD,
31    headers: HEADER,
32    url: '',
33    mode: request.agent.Mode.FOREGROUND,
34    method: 'POST',
35    title: 'upload',
36    network: request.agent.Network.ANY,
37    data: [],
38    token: UPLOAD_TOKEN
39  }
40  private context: common.UIAbilityContext | undefined = undefined;
41  private uploadTask: request.agent.Task | undefined = undefined;
42  private backgroundTask: request.agent.Task | undefined = undefined;
43  private waitList: Array<string> = [];
44
45  constructor() {
46    setInterval(() => {
47      this.flushBackgroundTask()
48    }, 2000);
49  }
50
51  async uploadFilesBackground(fileUris: Array<string>): Promise<void> {
52    logger.info(TAG, `uploadFiles begin, ${JSON.stringify(fileUris)}`);
53    this.context = getContext(this) as common.UIAbilityContext;
54    if (fileUris.length === 0) {
55      return;
56    }
57    fileUris.forEach((item: string) => {
58      this.waitList.push(item);
59    });
60  }
61
62  async flushBackgroundTask() {
63    let tasks = await request.agent.search({
64      state: request.agent.State.RUNNING
65    });
66    let state = AppStorage.get<number>('backTaskState');
67    if (state === BackgroundTaskState.RUNNING) {
68      if (tasks.length < TASK_MAX && this.waitList.length > 0) {
69        this.createBackgroundTask(this.waitList);
70        this.waitList = [];
71      } else {
72        if (this.backgroundTask === undefined || tasks.indexOf(this.backgroundTask.tid) === -1) {
73          AppStorage.setOrCreate('backTaskState', BackgroundTaskState.NONE);
74          this.backgroundTask = undefined;
75        }
76      }
77    }
78  }
79
80  async createBackgroundTask(fileUris: Array<string>) {
81    if (this.context === undefined) {
82      return;
83    }
84    this.config.url = await urlUtils.getUrl(this.context);
85    this.config.data = await this.getFilesAndData(this.context.cacheDir, fileUris);
86    this.config.mode = request.agent.Mode.BACKGROUND;
87    try {
88      this.backgroundTask = await request.agent.create(this.context, this.config);
89      await this.backgroundTask.start();
90      let state = AppStorage.get<number>('backTaskState');
91      if (state === BackgroundTaskState.PAUSE) {
92        await this.backgroundTask.pause();
93      }
94      logger.info(TAG, `createBackgroundTask success`);
95    } catch (err) {
96      logger.error(TAG, `task  err, err  = ${JSON.stringify(err)}`);
97    }
98  }
99
100  async uploadFiles(fileUris: Array<string>, callback: (progress: number, isSucceed: boolean) => void): Promise<void> {
101    logger.info(TAG, `uploadFiles begin, ${JSON.stringify(fileUris)}`);
102    if (fileUris.length === 0) {
103      return;
104    }
105    // 查询到存在正在执行的上传任务,提示并返回
106    let tasks = await request.agent.search({
107      state: request.agent.State.RUNNING,
108      action: request.agent.Action.UPLOAD,
109      mode: request.agent.Mode.FOREGROUND
110    });
111    if (tasks.length > 0) {
112      promptAction.showToast({ message: $r('app.string.have_upload_task_tips'), bottom: TOAST_BOTTOM });
113      return;
114    }
115    let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
116    this.config.data = await this.getFilesAndData(context.cacheDir, fileUris);
117    this.config.url = await urlUtils.getUrl(context);
118    this.config.mode = request.agent.Mode.FOREGROUND;
119    try {
120      this.uploadTask = await request.agent.create(context, this.config);
121      this.uploadTask.on('progress', (progress: request.agent.Progress) => {
122        logger.info(TAG, `progress,  progress = ${progress.processed} ${progress.state}`);
123        let processed = Number(progress.processed.toString()).valueOf();
124        let size = progress.sizes[0];
125        let process: number = Math.floor(processed / size * 100);
126        if (process < 100) {
127          callback(process, false);
128        }
129      });
130      this.uploadTask.on('completed', (progress: request.agent.Progress) => {
131        logger.info(TAG, `complete,  progress = ${progress.processed} ${progress.state}`);
132        callback(100, true);
133        this.cancelTask();
134      });
135      this.uploadTask.on('failed', async (progress: request.agent.Progress) => {
136        if (this.uploadTask) {
137          let taskInfo = await request.agent.touch(this.uploadTask.tid, UPLOAD_TOKEN);
138          logger.info(TAG, `fail,  resean = ${taskInfo.reason}, faults = ${JSON.stringify(taskInfo.faults)}`);
139        }
140        callback(100, false);
141        this.cancelTask();
142      });
143      await this.uploadTask.start();
144    } catch (err) {
145      logger.error(TAG, `task  err, err  = ${JSON.stringify(err)}`);
146      callback(100, false);
147    }
148  }
149
150  async cancelTask() {
151    if (this.uploadTask === undefined) {
152      return;
153    }
154    try {
155      this.uploadTask.off('progress');
156      this.uploadTask.off('failed');
157      this.uploadTask.off('completed');
158      await this.uploadTask.stop();
159      await request.agent.remove(this.uploadTask.tid);
160    } catch (err) {
161      logger.info(TAG, `deleteTask fail,err= ${JSON.stringify(err)}`);
162    }
163    this.uploadTask = undefined;
164  }
165
166  async pauseOrResume() {
167    let state = AppStorage.get<number>('backTaskState');
168    if (state === BackgroundTaskState.RUNNING) {
169      await this.pause();
170      AppStorage.setOrCreate('backTaskState', BackgroundTaskState.PAUSE);
171    } else if (state === BackgroundTaskState.PAUSE) {
172      await this.resume();
173      AppStorage.setOrCreate('backTaskState', BackgroundTaskState.RUNNING);
174    } else {
175      logger.info(TAG, 'this task state is error');
176    }
177  }
178
179  async pause() {
180    logger.info(TAG, 'pause');
181    if (this.backgroundTask === undefined) {
182      return;
183    }
184    try {
185      await this.backgroundTask.pause();
186    } catch (err) {
187      logger.info(TAG, `pause fail,err= ${JSON.stringify(err)}`);
188    }
189  }
190
191  async resume() {
192    logger.info(TAG, 'resume');
193    if (this.backgroundTask === undefined) {
194      return;
195    }
196    try {
197      await this.backgroundTask.resume();
198    } catch (err) {
199      logger.info(TAG, `resume fail,err= ${JSON.stringify(err)}`);
200    }
201  }
202
203  private async getFilesAndData(cacheDir: string, fileUris: Array<string>): Promise<Array<request.agent.FormItem>> {
204    logger.info(TAG, `getFilesAndData begin`);
205    let files: Array<request.agent.FormItem> = [];
206    for (let i = 0; i < fileUris.length; i++) {
207      logger.info(TAG, `getFile fileUri = ${fileUris[i]}`);
208      let imagePath = await this.mediaUtils.copyFileToCache(cacheDir, fileUris[i]);
209      logger.info(TAG, `getFilesAndData ${JSON.stringify(imagePath)}`);
210      let file: request.agent.FormItem = {
211        name: imagePath.split('cache/')[1],
212        value: {
213          path: './' + imagePath.split('cache/')[1]
214        }
215      }
216      files.push(file);
217    }
218    logger.info(TAG, `getFilesAndData ${JSON.stringify(files)}`);
219    return files;
220  }
221}
222
223export const requestUpload = new Upload();