• 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 
16 #include "request_event.h"
17 
18 #include "log.h"
19 #include "request_manager.h"
20 
21 namespace OHOS::Request {
22 constexpr const std::int32_t DECIMALISM = 10;
23 static constexpr const char *EVENT_COMPLETED = "completed";
24 static constexpr const char *EVENT_FAILED = "failed";
25 static constexpr const char *EVENT_PAUSE = "pause";
26 static constexpr const char *EVENT_RESUME = "resume";
27 static constexpr const char *EVENT_REMOVE = "remove";
28 static constexpr const char *EVENT_PROGRESS = "progress";
29 static constexpr const char *EVENT_HEADERRECEIVE = "headerReceive";
30 static constexpr const char *EVENT_FAIL = "fail";
31 static constexpr const char *EVENT_COMPLETE = "complete";
32 
33 std::unordered_set<std::string> RequestEvent::supportEventsV9_ = {
34     EVENT_COMPLETE,
35     EVENT_PAUSE,
36     EVENT_REMOVE,
37     EVENT_PROGRESS,
38     EVENT_HEADERRECEIVE,
39     EVENT_FAIL,
40 };
41 
42 std::unordered_set<std::string> RequestEvent::supportEventsV10_ = {
43     EVENT_PROGRESS,
44     EVENT_COMPLETED,
45     EVENT_FAILED,
46     EVENT_PAUSE,
47     EVENT_RESUME,
48     EVENT_REMOVE,
49 };
50 
51 std::map<std::string, RequestEvent::Event> RequestEvent::requestEvent_ = {
52     { FUNCTION_PAUSE, RequestEvent::PauseExec },
53     { FUNCTION_QUERY, RequestEvent::QueryExec },
54     { FUNCTION_QUERY_MIME_TYPE, RequestEvent::QueryMimeTypeExec },
55     { FUNCTION_REMOVE, RequestEvent::RemoveExec },
56     { FUNCTION_RESUME, RequestEvent::ResumeExec },
57     { FUNCTION_START, RequestEvent::StartExec },
58     { FUNCTION_STOP, RequestEvent::StopExec },
59 };
60 
61 std::map<std::string, uint32_t> RequestEvent::resMap_ = {
62     { FUNCTION_PAUSE, BOOL_RES },
63     { FUNCTION_QUERY, INFO_RES },
64     { FUNCTION_QUERY_MIME_TYPE, STR_RES },
65     { FUNCTION_REMOVE, BOOL_RES },
66     { FUNCTION_RESUME, BOOL_RES },
67     { FUNCTION_START, BOOL_RES },
68 };
69 
70 std::map<State, DownloadStatus> RequestEvent::stateMap_ = {
71     { State::INITIALIZED, SESSION_PENDING },
72     { State::WAITING, SESSION_PAUSED },
73     { State::RUNNING, SESSION_RUNNING },
74     { State::RETRYING, SESSION_RUNNING },
75     { State::PAUSED, SESSION_PAUSED },
76     { State::COMPLETED, SESSION_SUCCESS },
77     { State::STOPPED, SESSION_FAILED },
78     { State::FAILED, SESSION_FAILED },
79 };
80 
81 std::map<Reason, DownloadErrorCode> RequestEvent::failMap_ = {
82     { REASON_OK, ERROR_FILE_ALREADY_EXISTS },
83     { IO_ERROR, ERROR_FILE_ERROR },
84     { REDIRECT_ERROR, ERROR_TOO_MANY_REDIRECTS },
85     { OTHERS_ERROR, ERROR_UNKNOWN },
86     { NETWORK_OFFLINE, ERROR_OFFLINE },
87     { UNSUPPORTED_NETWORK_TYPE, ERROR_UNSUPPORTED_NETWORK_TYPE },
88     { UNSUPPORT_RANGE_REQUEST, ERROR_UNKNOWN },
89 };
90 
Pause(napi_env env,napi_callback_info info)91 napi_value RequestEvent::Pause(napi_env env, napi_callback_info info)
92 {
93     REQUEST_HILOGD("Pause in");
94     return Exec(env, info, FUNCTION_PAUSE);
95 }
96 
Query(napi_env env,napi_callback_info info)97 napi_value RequestEvent::Query(napi_env env, napi_callback_info info)
98 {
99     REQUEST_HILOGD("QueryV8 in");
100     return Exec(env, info, FUNCTION_QUERY);
101 }
102 
QueryMimeType(napi_env env,napi_callback_info info)103 napi_value RequestEvent::QueryMimeType(napi_env env, napi_callback_info info)
104 {
105     REQUEST_HILOGD("QueryMimeType in");
106     return Exec(env, info, FUNCTION_QUERY_MIME_TYPE);
107 }
108 
Remove(napi_env env,napi_callback_info info)109 napi_value RequestEvent::Remove(napi_env env, napi_callback_info info)
110 {
111     REQUEST_HILOGD("RemoveV8 in");
112     return Exec(env, info, FUNCTION_REMOVE);
113 }
114 
Resume(napi_env env,napi_callback_info info)115 napi_value RequestEvent::Resume(napi_env env, napi_callback_info info)
116 {
117     REQUEST_HILOGD("Resume in");
118     return Exec(env, info, FUNCTION_RESUME);
119 }
120 
Start(napi_env env,napi_callback_info info)121 napi_value RequestEvent::Start(napi_env env, napi_callback_info info)
122 {
123     REQUEST_HILOGD("Start in");
124     return Exec(env, info, FUNCTION_START);
125 }
126 
Stop(napi_env env,napi_callback_info info)127 napi_value RequestEvent::Stop(napi_env env, napi_callback_info info)
128 {
129     REQUEST_HILOGD("Stop in");
130     return Exec(env, info, FUNCTION_STOP);
131 }
132 
On(napi_env env,napi_callback_info info)133 napi_value RequestEvent::On(napi_env env, napi_callback_info info)
134 {
135     JsParam jsParam;
136     ExceptionError err = ParseOnOffParameters(env, info, true, jsParam);
137     if (err.code != E_OK) {
138         bool withErrCode = jsParam.task->config_.version == Version::API10;
139         NapiUtils::ThrowError(env, err.code, err.errInfo, withErrCode);
140         return nullptr;
141     }
142 
143     sptr<RequestNotify> listener = new (std::nothrow) RequestNotify(env, jsParam.callback);
144     if (listener == nullptr) {
145         REQUEST_HILOGE("Create callback object fail");
146         return nullptr;
147     }
148     REQUEST_HILOGD("On event %{public}s + %{public}s", jsParam.type.c_str(), jsParam.task->GetTid().c_str());
149     std::string key = jsParam.type + jsParam.task->GetTid();
150     jsParam.task->AddListener(key, listener);
151     if (jsParam.task->GetListenerSize(key) == 1) {
152         RequestManager::GetInstance()->On(
153             jsParam.type, jsParam.task->GetTid(), listener, jsParam.task->config_.version);
154     }
155     return nullptr;
156 }
157 
Off(napi_env env,napi_callback_info info)158 napi_value RequestEvent::Off(napi_env env, napi_callback_info info)
159 {
160     JsParam jsParam;
161     ExceptionError err = ParseOnOffParameters(env, info, false, jsParam);
162     if (err.code != E_OK) {
163         bool withErrCode = jsParam.task->config_.version == Version::API10;
164         NapiUtils::ThrowError(env, err.code, err.errInfo, withErrCode);
165         return nullptr;
166     }
167 
168     if (jsParam.callback == nullptr) {
169         jsParam.task->RemoveListener(jsParam.type, jsParam.task->GetTid(), jsParam.task->config_.version);
170     } else {
171         jsParam.task->RemoveListener(
172             jsParam.type, jsParam.task->GetTid(), jsParam.callback, jsParam.task->config_.version);
173     }
174     return nullptr;
175 }
176 
IsSupportType(const std::string & type,Version version)177 bool RequestEvent::IsSupportType(const std::string &type, Version version)
178 {
179     if (version == Version::API10) {
180         return supportEventsV10_.find(type) != supportEventsV10_.end();
181     } else {
182         return supportEventsV9_.find(type) != supportEventsV9_.end();
183     }
184 }
185 
BuildNotifyData(const std::shared_ptr<TaskInfo> & taskInfo)186 NotifyData RequestEvent::BuildNotifyData(const std::shared_ptr<TaskInfo> &taskInfo)
187 {
188     NotifyData notifyData;
189     notifyData.progress = taskInfo->progress;
190     notifyData.action = taskInfo->action;
191     notifyData.version = taskInfo->version;
192     notifyData.mode = taskInfo->mode;
193     notifyData.taskStates = taskInfo->taskStates;
194     return notifyData;
195 }
196 
ParseOnOffParameters(napi_env env,napi_callback_info info,bool IsRequiredParam,JsParam & jsParam)197 ExceptionError RequestEvent::ParseOnOffParameters(
198     napi_env env, napi_callback_info info, bool IsRequiredParam, JsParam &jsParam)
199 {
200     ExceptionError err = { .code = E_OK };
201     size_t argc = NapiUtils::MAX_ARGC;
202     napi_value argv[NapiUtils::MAX_ARGC] = { nullptr };
203     napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsParam.self, nullptr);
204     if (status != napi_ok) {
205         return { .code = E_PARAMETER_CHECK, .errInfo = "Failed to obtain parameters" };
206     }
207     napi_unwrap(env, jsParam.self, reinterpret_cast<void **>(&jsParam.task));
208     if (jsParam.task == nullptr) {
209         return { .code = E_PARAMETER_CHECK, .errInfo = "Failed to obtain the current object" };
210     }
211 
212     if ((IsRequiredParam && argc < NapiUtils::TWO_ARG) || (!IsRequiredParam && argc < NapiUtils::ONE_ARG)) {
213         return { .code = E_PARAMETER_CHECK, .errInfo = "Wrong number of arguments" };
214     }
215     napi_valuetype valuetype;
216     napi_typeof(env, argv[NapiUtils::FIRST_ARGV], &valuetype);
217     if (valuetype != napi_string) {
218         return { .code = E_PARAMETER_CHECK, .errInfo = "The first parameter is not of string type" };
219     }
220     jsParam.type = NapiUtils::Convert2String(env, argv[NapiUtils::FIRST_ARGV]);
221     if (!IsSupportType(jsParam.type, jsParam.task->config_.version)) {
222         return { .code = E_PARAMETER_CHECK, .errInfo = "First parameter error" };
223     }
224     ConvertType(jsParam.type);
225     if (argc == NapiUtils::ONE_ARG) {
226         return err;
227     }
228     valuetype = napi_undefined;
229     napi_typeof(env, argv[NapiUtils::SECOND_ARGV], &valuetype);
230     if (valuetype != napi_function) {
231         return { .code = E_PARAMETER_CHECK, .errInfo = "The second parameter is not of function type" };
232     }
233     jsParam.callback = argv[NapiUtils::SECOND_ARGV];
234     return err;
235 }
236 
ConvertType(std::string & type)237 void RequestEvent::ConvertType(std::string &type)
238 {
239     if (type == EVENT_COMPLETED) {
240         type = EVENT_COMPLETE;
241     }
242     if (type == EVENT_FAILED) {
243         type = EVENT_FAIL;
244     }
245 }
246 
Exec(napi_env env,napi_callback_info info,const std::string & execType)247 napi_value RequestEvent::Exec(napi_env env, napi_callback_info info, const std::string &execType)
248 {
249     auto context = std::make_shared<ExecContext>();
250     auto input = [context](size_t argc, napi_value *argv, napi_value self) -> napi_status {
251         return ParseInputParameters(context->env_, argc, self, context);
252     };
253     auto output = [context, execType](napi_value *result) -> napi_status {
254         if (context->innerCode_ != E_OK) {
255             return napi_generic_failure;
256         }
257         return GetResult(context->env_, context, execType, *result);
258     };
259     auto exec = [context, execType]() {
260         auto handle = requestEvent_.find(execType);
261         if (handle != requestEvent_.end()) {
262             context->innerCode_ = handle->second(context);
263         }
264     };
265 
266     context->SetInput(input).SetOutput(output).SetExec(exec);
267     AsyncCall asyncCall(env, info, context);
268     return asyncCall.Call(context, execType);
269 }
270 
ParseInputParameters(napi_env env,size_t argc,napi_value self,const std::shared_ptr<ExecContext> & context)271 napi_status RequestEvent::ParseInputParameters(
272     napi_env env, size_t argc, napi_value self, const std::shared_ptr<ExecContext> &context)
273 {
274     NAPI_ASSERT_BASE(env, self != nullptr, "self is nullptr", napi_invalid_arg);
275     NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast<void **>(&context->task)), napi_invalid_arg);
276     NAPI_ASSERT_BASE(env, context->task != nullptr, "there is no native task", napi_invalid_arg);
277     context->version_ = context->task->config_.version;
278     context->withErrCode_ = context->version_ != Version::API8;
279     return napi_ok;
280 }
281 
GetResult(napi_env env,const std::shared_ptr<ExecContext> & context,const std::string & execType,napi_value & result)282 napi_status RequestEvent::GetResult(
283     napi_env env, const std::shared_ptr<ExecContext> &context, const std::string &execType, napi_value &result)
284 {
285     if (resMap_[execType] == BOOL_RES) {
286         return NapiUtils::Convert2JSValue(env, context->boolRes, result);
287     }
288     if (resMap_[execType] == STR_RES) {
289         return NapiUtils::Convert2JSValue(env, context->strRes, result);
290     }
291     if (resMap_[execType] == INFO_RES) {
292         return NapiUtils::Convert2JSValue(env, context->infoRes, result);
293     }
294     return napi_generic_failure;
295 }
296 
StartExec(const std::shared_ptr<ExecContext> & context)297 int32_t RequestEvent::StartExec(const std::shared_ptr<ExecContext> &context)
298 {
299     int32_t ret = RequestManager::GetInstance()->Start(context->task->GetTid());
300     if (ret == E_OK) {
301         context->boolRes = true;
302     }
303     return ret;
304 }
305 
StopExec(const std::shared_ptr<ExecContext> & context)306 int32_t RequestEvent::StopExec(const std::shared_ptr<ExecContext> &context)
307 {
308     int32_t ret = RequestManager::GetInstance()->Stop(context->task->GetTid());
309     if (ret == E_OK) {
310         context->boolRes = true;
311     }
312     return ret;
313 }
314 
PauseExec(const std::shared_ptr<ExecContext> & context)315 int32_t RequestEvent::PauseExec(const std::shared_ptr<ExecContext> &context)
316 {
317     int32_t ret = RequestManager::GetInstance()->Pause(context->task->GetTid(), context->version_);
318     if (ret == E_OK) {
319         context->boolRes = true;
320     }
321     if (context->version_ != Version::API10 && ret != E_PERMISSION) {
322         return E_OK;
323     }
324     return ret;
325 }
326 
QueryExec(const std::shared_ptr<ExecContext> & context)327 int32_t RequestEvent::QueryExec(const std::shared_ptr<ExecContext> &context)
328 {
329     TaskInfo infoRes;
330     int32_t ret = E_OK;
331     if (!RequestManager::GetInstance()->LoadRequestServer()) {
332         ret = E_SERVICE_ERROR;
333         return ret;
334     }
335     ret = RequestManager::GetInstance()->Show(context->task->GetTid(), infoRes);
336     if (context->version_ != Version::API10 && ret != E_PERMISSION) {
337         ret = E_OK;
338     }
339     GetDownloadInfo(infoRes, context->infoRes);
340     return ret;
341 }
342 
QueryMimeTypeExec(const std::shared_ptr<ExecContext> & context)343 int32_t RequestEvent::QueryMimeTypeExec(const std::shared_ptr<ExecContext> &context)
344 {
345     int32_t ret = E_OK;
346     if (!RequestManager::GetInstance()->LoadRequestServer()) {
347         ret = E_SERVICE_ERROR;
348         return ret;
349     }
350     ret = RequestManager::GetInstance()->QueryMimeType(context->task->GetTid(), context->strRes);
351     if (context->version_ != Version::API10 && ret != E_PERMISSION) {
352         ret = E_OK;
353     }
354     return ret;
355 }
356 
GetDownloadInfo(const TaskInfo & infoRes,DownloadInfo & info)357 void RequestEvent::GetDownloadInfo(const TaskInfo &infoRes, DownloadInfo &info)
358 {
359     info.downloadId = strtoul(infoRes.tid.c_str(), NULL, DECIMALISM);
360     if (infoRes.progress.state == State::FAILED) {
361         auto it = failMap_.find(infoRes.code);
362         if (it != failMap_.end()) {
363             info.failedReason = it->second;
364         } else {
365             info.failedReason = ERROR_UNKNOWN;
366         }
367     }
368     if (infoRes.progress.state == State::WAITING
369         && (infoRes.code == NETWORK_OFFLINE || infoRes.code == UNSUPPORTED_NETWORK_TYPE)) {
370         info.pausedReason = PAUSED_WAITING_FOR_NETWORK;
371     }
372     if (infoRes.progress.state == State::PAUSED) {
373         if (infoRes.code == USER_OPERATION) {
374             info.pausedReason = PAUSED_BY_USER;
375         }
376     }
377     if (!infoRes.files.empty()) {
378         info.fileName = infoRes.files[0].filename;
379         info.filePath = infoRes.files[0].uri;
380     }
381     auto it = stateMap_.find(infoRes.progress.state);
382     if (it != stateMap_.end()) {
383         info.status = it->second;
384     }
385     info.url = infoRes.url;
386     info.downloadTitle = infoRes.title;
387     if (!infoRes.progress.sizes.empty()) {
388         info.downloadTotalBytes = infoRes.progress.sizes[0];
389     }
390     info.description = infoRes.description;
391     info.downloadedBytes = infoRes.progress.processed;
392 }
393 
RemoveExec(const std::shared_ptr<ExecContext> & context)394 int32_t RequestEvent::RemoveExec(const std::shared_ptr<ExecContext> &context)
395 {
396     int32_t ret = RequestManager::GetInstance()->Remove(context->task->GetTid(), context->version_);
397     if (context->version_ != Version::API10 && ret != E_PERMISSION) {
398         ret = E_OK;
399     }
400     if (ret == E_OK) {
401         context->boolRes = true;
402     }
403     return ret;
404 }
405 
ResumeExec(const std::shared_ptr<ExecContext> & context)406 int32_t RequestEvent::ResumeExec(const std::shared_ptr<ExecContext> &context)
407 {
408     int32_t ret = E_OK;
409     if (!RequestManager::GetInstance()->LoadRequestServer()) {
410         ret = E_SERVICE_ERROR;
411         return ret;
412     }
413     ret = RequestManager::GetInstance()->Resume(context->task->GetTid());
414     if (context->version_ != Version::API10 && ret != E_PERMISSION) {
415         ret = E_OK;
416     }
417     if (ret == E_OK) {
418         context->boolRes = true;
419     }
420     return ret;
421 }
422 } // namespace OHOS::Request
423