2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "download/download_instance.h"
21 #include <net_connection.h>
23 #include "common/filesystem/filesystem_provider.h"
24 #include "common/logger.h"
25 #include "common/picojson.h"
26 #include "common/scope_exit.h"
27 #include "common/tools.h"
28 #include "common/typeutil.h"
33 std::vector<DownloadInstance*> DownloadInstance::instances_;
34 std::mutex DownloadInstance::instances_mutex_;
37 // The privileges that required in Download API
38 const std::string kPrivilegeDownload = "http://tizen.org/privilege/download";
39 const std::string kDownloadManagerListenerId = "DownloadManagerListener";
43 DownloadInstance::DownloadInstance() {
45 using std::placeholders::_1;
46 using std::placeholders::_2;
49 #define REGISTER_METHOD(M) \
50 RegisterSyncHandler(#M, std::bind(&DownloadInstance::M, this, _1, _2))
52 REGISTER_METHOD(DownloadManagerGetMimeType);
53 REGISTER_METHOD(DownloadManagerStart);
54 REGISTER_METHOD(DownloadManagerCancel);
55 REGISTER_METHOD(DownloadManagerPause);
56 REGISTER_METHOD(DownloadManagerAbandon);
57 REGISTER_METHOD(DownloadManagerResume);
58 REGISTER_METHOD(DownloadManagerGetState);
60 #undef REGISTER_METHOD
63 std::lock_guard<std::mutex> lock(instances_mutex_);
64 instances_.push_back(this);
67 DownloadInstance::~DownloadInstance() {
71 std::lock_guard<std::mutex> lock(instances_mutex_);
73 for (DownloadCallbackMap::iterator it = download_callbacks.begin();
74 it != download_callbacks.end(); ++it) {
75 DownloadInfoPtr di_ptr = it->second->instance->di_map[it->second->download_id];
76 SLoggerD("~DownloadInstance() for callbackID %d Called", it->second->download_id);
79 ret = download_unset_state_changed_cb(di_ptr->native_download_id);
80 if (ret != DOWNLOAD_ERROR_NONE)
81 LoggerE("download_unset_state_changed_cb() is failed. (%s)", get_error_message(ret));
83 ret = download_unset_progress_cb(di_ptr->native_download_id);
84 if (ret != DOWNLOAD_ERROR_NONE)
85 LoggerE("download_unset_progress_cb() is failed. (%s)", get_error_message(ret));
87 ret = download_cancel(di_ptr->native_download_id);
88 if (ret != DOWNLOAD_ERROR_NONE)
89 LoggerE("download_cancel() is failed. (%s)", get_error_message(ret));
91 ret = download_destroy(di_ptr->native_download_id);
92 if (ret != DOWNLOAD_ERROR_NONE)
93 LoggerE("download_destroy() is failed. (%s)", get_error_message(ret));
95 LoggerD("di_ptr is nullptr");
101 for (auto it = instances_.begin(); it != instances_.end(); it++) {
103 instances_.erase(it);
109 bool DownloadInstance::CheckInstance(DownloadInstance* instance) {
111 for (auto vec_instance : instances_) {
112 if (vec_instance == instance) {
120 common::PlatformResult DownloadInstance::convertError(int err, const std::string& message) {
121 char* error = nullptr;
122 if (message.empty()) {
123 error = get_error_message(err);
125 error = (char*)message.c_str();
129 case DOWNLOAD_ERROR_INVALID_PARAMETER:
130 return common::PlatformResult(common::ErrorCode::INVALID_VALUES_ERR, error);
131 case DOWNLOAD_ERROR_OUT_OF_MEMORY:
132 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
133 case DOWNLOAD_ERROR_NETWORK_UNREACHABLE:
134 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
135 case DOWNLOAD_ERROR_CONNECTION_TIMED_OUT:
136 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
137 case DOWNLOAD_ERROR_NO_SPACE:
138 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
139 case DOWNLOAD_ERROR_PERMISSION_DENIED:
140 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
141 case DOWNLOAD_ERROR_NOT_SUPPORTED:
142 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
143 case DOWNLOAD_ERROR_INVALID_STATE:
144 return common::PlatformResult(common::ErrorCode::INVALID_VALUES_ERR, error);
145 case DOWNLOAD_ERROR_CONNECTION_FAILED:
146 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
147 case DOWNLOAD_ERROR_INVALID_URL:
148 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
149 case DOWNLOAD_ERROR_INVALID_DESTINATION:
150 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
151 case DOWNLOAD_ERROR_TOO_MANY_DOWNLOADS:
152 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
153 case DOWNLOAD_ERROR_QUEUE_FULL:
154 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
155 case DOWNLOAD_ERROR_ALREADY_COMPLETED:
156 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
157 case DOWNLOAD_ERROR_FILE_ALREADY_EXISTS:
158 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
159 case DOWNLOAD_ERROR_CANNOT_RESUME:
160 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
161 case DOWNLOAD_ERROR_FIELD_NOT_FOUND:
162 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
163 case DOWNLOAD_ERROR_TOO_MANY_REDIRECTS:
164 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
165 case DOWNLOAD_ERROR_UNHANDLED_HTTP_CODE:
166 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
167 case DOWNLOAD_ERROR_REQUEST_TIMEOUT:
168 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
169 case DOWNLOAD_ERROR_RESPONSE_TIMEOUT:
170 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
171 case DOWNLOAD_ERROR_SYSTEM_DOWN:
172 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
173 case DOWNLOAD_ERROR_ID_NOT_FOUND:
174 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
175 case DOWNLOAD_ERROR_INVALID_NETWORK_TYPE:
176 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
177 case DOWNLOAD_ERROR_NO_DATA:
178 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
179 case DOWNLOAD_ERROR_IO_ERROR:
180 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
182 return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, "Unknown error.");
186 #define CHECK_EXIST(args, name, out) \
187 if (!args.contains(name)) { \
188 LogAndReportError(common::PlatformResult(common::ErrorCode::TYPE_MISMATCH_ERR, \
189 name " is required argument"), \
194 void DownloadInstance::OnStateChanged(int download_id, download_state_e state, void* user_data) {
196 CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
198 // Prevent to call finished, cancelled or failed function more than once
199 if (DOWNLOAD_STATE_COMPLETED == down_cb_ptr->state ||
200 DOWNLOAD_STATE_CANCELED == down_cb_ptr->state ||
201 DOWNLOAD_STATE_FAILED == down_cb_ptr->state) {
202 LoggerD("Already finished job, not calling callback for %d state", down_cb_ptr->state);
206 down_cb_ptr->state = state;
207 down_cb_ptr->native_download_id = download_id;
209 SLoggerD("State for callbackId %d changed to %d", down_cb_ptr->download_id,
210 static_cast<int>(state));
213 case DOWNLOAD_STATE_NONE:
215 case DOWNLOAD_STATE_DOWNLOADING:
216 OnStart(download_id, user_data);
218 case DOWNLOAD_STATE_PAUSED:
219 if (!g_idle_add(OnPaused, down_cb_ptr)) {
220 LoggerE("g_idle_add failed");
223 case DOWNLOAD_STATE_COMPLETED:
224 if (!g_idle_add(OnFinished, down_cb_ptr)) {
225 LoggerE("g_idle_add failed");
228 case DOWNLOAD_STATE_CANCELED:
229 if (!g_idle_add(OnCanceled, down_cb_ptr)) {
230 LoggerE("g_idle_add failed");
233 case DOWNLOAD_STATE_FAILED:
234 if (!g_idle_add(OnFailed, down_cb_ptr)) {
235 LoggerE("g_idle_add failed");
239 LoggerD("Unexpected download state: %d", state);
244 gboolean DownloadInstance::OnProgressChanged(void* user_data) {
246 CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
247 std::lock_guard<std::mutex> lock(instances_mutex_);
248 if (!CheckInstance(down_cb_ptr->instance)) {
252 DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[down_cb_ptr->download_id];
254 LoggerW("Download handle does not exist for callback id %d", down_cb_ptr->download_id);
258 picojson::value::object out;
259 out["status"] = picojson::value("progress");
260 out["downloadId"] = picojson::value(static_cast<double>(down_cb_ptr->download_id));
261 out["receivedSize"] = picojson::value(static_cast<double>(down_cb_ptr->received));
262 out["totalSize"] = picojson::value(static_cast<double>(di_ptr->file_size));
263 out["listenerId"] = picojson::value(kDownloadManagerListenerId);
265 LoggerD("OnProgressChanged for callbackId %d Called: Received: %llu", down_cb_ptr->download_id,
266 down_cb_ptr->received);
268 picojson::value v = picojson::value(out);
269 Instance::PostMessage(down_cb_ptr->instance, v.serialize().c_str());
274 void DownloadInstance::OnStart(int download_id, void* user_data) {
276 unsigned long long totalSize;
278 CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
279 std::lock_guard<std::mutex> lock(instances_mutex_);
280 if (!CheckInstance(down_cb_ptr->instance)) {
284 SLoggerD("OnStart for callbackId %d Called", down_cb_ptr->download_id);
286 DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[down_cb_ptr->download_id];
288 LoggerW("Download handle does not exist for callback id %d", down_cb_ptr->download_id);
292 download_get_content_size(download_id, &totalSize);
294 di_ptr->file_size = totalSize;
297 gboolean DownloadInstance::OnFinished(void* user_data) {
299 char* fullPath = NULL;
301 CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
302 std::lock_guard<std::mutex> lock(instances_mutex_);
303 if (!CheckInstance(down_cb_ptr->instance)) {
307 int download_id = down_cb_ptr->download_id;
308 DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[download_id];
310 LoggerW("Download handle does not exist for callback id %d", down_cb_ptr->download_id);
314 LoggerD("OnFinished for callbackID %d Called", download_id);
316 picojson::value::object out;
318 int ret = download_get_downloaded_file_path(down_cb_ptr->native_download_id, &fullPath);
319 if (ret != DOWNLOAD_ERROR_NONE) {
320 LogAndReportError(convertError(ret), &out, ("download_get_downloaded_file_path error: %d (%s)",
321 ret, get_error_message(ret)));
323 ret = download_unset_state_changed_cb(di_ptr->native_download_id);
324 if (ret != DOWNLOAD_ERROR_NONE) {
325 LoggerW("%s", get_error_message(ret));
327 ret = download_unset_progress_cb(di_ptr->native_download_id);
328 if (ret != DOWNLOAD_ERROR_NONE) {
329 LoggerW("%s", get_error_message(ret));
331 ret = download_destroy(di_ptr->native_download_id);
332 if (ret != DOWNLOAD_ERROR_NONE) {
333 LoggerW("%s", get_error_message(ret));
335 out["status"] = picojson::value("completed");
337 picojson::value(common::FilesystemProvider::Create().GetVirtualPath(fullPath));
339 out["downloadId"] = picojson::value(static_cast<double>(download_id));
341 out["listenerId"] = picojson::value(kDownloadManagerListenerId);
342 Instance::PostMessage(down_cb_ptr->instance, picojson::value(out).serialize().c_str());
343 // down_cb_ptr is freed in destructor, it prevent from crash if OnFinished state
344 // was called after OnCanceled or OnFailed
350 gboolean DownloadInstance::OnPaused(void* user_data) {
352 CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
353 std::lock_guard<std::mutex> lock(instances_mutex_);
354 if (!CheckInstance(down_cb_ptr->instance)) {
358 int download_id = down_cb_ptr->download_id;
359 DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[download_id];
361 LoggerW("Download handle does not exist for callback id %d", down_cb_ptr->download_id);
365 LoggerD("OnPaused for callbackID %d Called", download_id);
367 picojson::value::object out;
368 out["status"] = picojson::value("paused");
369 out["downloadId"] = picojson::value(static_cast<double>(download_id));
370 out["listenerId"] = picojson::value(kDownloadManagerListenerId);
372 Instance::PostMessage(down_cb_ptr->instance, picojson::value(out).serialize().c_str());
376 gboolean DownloadInstance::OnCanceled(void* user_data) {
378 CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
379 std::lock_guard<std::mutex> lock(instances_mutex_);
380 if (!CheckInstance(down_cb_ptr->instance)) {
384 int download_id = down_cb_ptr->download_id;
385 DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[download_id];
387 LoggerW("Download handle does not exist for callback id %d", download_id);
391 LoggerD("OnCanceled for callbackID %d Called", download_id);
393 int ret = download_unset_state_changed_cb(di_ptr->native_download_id);
394 if (ret != DOWNLOAD_ERROR_NONE) {
395 LoggerE("%s", get_error_message(ret));
398 ret = download_unset_progress_cb(di_ptr->native_download_id);
399 if (ret != DOWNLOAD_ERROR_NONE) {
400 LoggerE("%s", get_error_message(ret));
403 picojson::value::object out;
404 out["status"] = picojson::value("canceled");
405 out["downloadId"] = picojson::value(static_cast<double>(download_id));
406 out["listenerId"] = picojson::value(kDownloadManagerListenerId);
408 Instance::PostMessage(down_cb_ptr->instance, picojson::value(out).serialize().c_str());
409 // down_cb_ptr is freed in destructor, it prevent from crash if OnFinished state
410 // was called after OnFinished or OnFailed
414 gboolean DownloadInstance::OnFailed(void* user_data) {
416 download_error_e error;
417 picojson::object out;
419 CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
420 std::lock_guard<std::mutex> lock(instances_mutex_);
421 if (!CheckInstance(down_cb_ptr->instance)) {
425 int download_id = down_cb_ptr->download_id;
426 DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[download_id];
428 LoggerW("Download handle does not exist for callback id %d", download_id);
432 LoggerD("OnFailed for callbackID %d called", download_id);
434 download_get_error(down_cb_ptr->native_download_id, &error);
435 if (DOWNLOAD_ERROR_NONE != error) {
437 int ret = download_get_http_status(down_cb_ptr->native_download_id, &http_status);
438 std::string error_message;
439 if (DOWNLOAD_ERROR_NONE != ret) {
440 LoggerE("Gathering HTTP status failed, default error message will be used");
442 LoggerD("HTTP status is: %d", http_status);
443 error_message = "Error with HTTP status: " + std::to_string(http_status);
445 LogAndReportError(convertError(error, error_message), &out,
446 ("download_get_error error: %d (%s)", error, get_error_message(error)));
449 int ret = download_unset_state_changed_cb(di_ptr->native_download_id);
450 if (ret != DOWNLOAD_ERROR_NONE) {
451 LoggerE("%s", get_error_message(ret));
454 ret = download_unset_progress_cb(di_ptr->native_download_id);
455 if (ret != DOWNLOAD_ERROR_NONE) {
456 LoggerE("%s", get_error_message(ret));
459 out["downloadId"] = picojson::value(static_cast<double>(down_cb_ptr->download_id));
460 out["listenerId"] = picojson::value(kDownloadManagerListenerId);
462 Instance::PostMessage(down_cb_ptr->instance, picojson::value(out).serialize().c_str());
463 // down_cb_ptr is freed in destructor, it prevent from crash if OnFinished state
464 // was called after OnFinished or OnCanceled
468 void DownloadInstance::progress_changed_cb(int download_id, long long unsigned received,
471 CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
472 down_cb_ptr->received = received;
473 down_cb_ptr->native_download_id = download_id;
475 if (!g_idle_add(OnProgressChanged, down_cb_ptr)) {
476 LoggerE("g_idle_add failed");
480 #define CHECK_CONNECTION_ERROR(ret) \
482 case CONNECTION_ERROR_NONE: \
484 case CONNECTION_ERROR_NOT_SUPPORTED: \
485 return LogAndCreateResult( \
486 common::ErrorCode::NOT_SUPPORTED_ERR, \
487 "The networkType of the given DownloadRequest is not supported", \
488 ("The networkType of the given DownloadRequest is not supported")); \
490 return LogAndCreateResult(common::ErrorCode::UNKNOWN_ERR, "Connection problem occurred", \
491 ("Connection problem occurred")); \
494 common::PlatformResult DownloadInstance::CheckNetworkConnection(const std::string& network_type,
495 bool& network_support,
496 bool& network_available,
497 DownloadInfoPtr di_ptr) {
498 connection_h connection = nullptr;
499 int ret = connection_create(&connection);
500 CHECK_CONNECTION_ERROR(ret)
502 connection_destroy(connection);
505 connection_type_e connection_type = CONNECTION_TYPE_DISCONNECTED;
506 ret = connection_get_type(connection, &connection_type);
507 CHECK_CONNECTION_ERROR(ret)
509 if (CONNECTION_TYPE_DISCONNECTED == connection_type) {
510 return LogAndCreateResult(common::ErrorCode::UNKNOWN_ERR, "Connection problem occurred",
511 ("Connection type is disconnected"));
514 if ("CELLULAR" == network_type) {
515 // check if connection type is supported
516 bool cell_support = false;
517 system_info_get_platform_bool("http://tizen.org/feature/network.telephony", &cell_support);
519 // check if connection is available
520 connection_cellular_state_e cell_state = CONNECTION_CELLULAR_STATE_OUT_OF_SERVICE;
521 ret = connection_get_cellular_state(connection, &cell_state);
522 CHECK_CONNECTION_ERROR(ret)
523 bool cell_available = (CONNECTION_CELLULAR_STATE_CONNECTED == cell_state);
525 // setup download parameters using cellular network
526 network_support = cell_support;
527 network_available = cell_available;
528 di_ptr->network_type = DOWNLOAD_NETWORK_DATA_NETWORK;
529 } else if ("WIFI" == network_type) {
530 // check if connection type is supported
531 bool wifi_support = false;
532 system_info_get_platform_bool("http://tizen.org/feature/network.wifi", &wifi_support);
534 // check if connection is available
535 connection_wifi_state_e wifi_state = CONNECTION_WIFI_STATE_DEACTIVATED;
536 ret = connection_get_wifi_state(connection, &wifi_state);
537 CHECK_CONNECTION_ERROR(ret)
538 bool wifi_available = (CONNECTION_WIFI_STATE_CONNECTED == wifi_state);
540 // setup download parameters using wifi network
541 network_support = wifi_support;
542 network_available = wifi_available;
543 di_ptr->network_type = DOWNLOAD_NETWORK_WIFI;
544 } else if (("ALL" == network_type) && (CONNECTION_TYPE_DISCONNECTED != connection_type)) {
545 // setup download parameters using 'all' network
546 network_support = true;
547 network_available = true;
548 di_ptr->network_type = DOWNLOAD_NETWORK_ALL;
550 return LogAndCreateResult(
551 common::ErrorCode::INVALID_VALUES_ERR,
552 "The input parameter contains an invalid network type.",
553 ("The input parameter contains an invalid network type: %s", network_type.c_str()));
555 return common::PlatformResult(common::ErrorCode::NO_ERROR);
557 #undef CHECK_CONNECTION_ERROR
559 void DownloadInstance::DownloadManagerStart(const picojson::value& args, picojson::object& out) {
561 CHECK_PRIVILEGE_ACCESS(kPrivilegeDownload, &out);
562 CHECK_EXIST(args, "downloadId", out)
563 CHECK_EXIST(args, "url", out)
566 std::string network_type;
568 DownloadInfoPtr di_ptr(new DownloadInfo);
570 di_ptr->download_id = static_cast<int>(args.get("downloadId").get<double>());
571 di_ptr->url = args.get("url").is<std::string>() ? args.get("url").get<std::string>() : "";
573 if (!args.get("destination").is<picojson::null>()) {
574 if (args.get("destination").is<std::string>() &&
575 args.get("destination").get<std::string>() != "") {
576 di_ptr->destination = args.get("destination").get<std::string>();
577 di_ptr->destination = common::FilesystemProvider::Create().GetRealPath(di_ptr->destination);
581 CHECK_STORAGE_ACCESS(di_ptr->destination.empty()
582 ? common::FilesystemProvider::Create().GetRealPath("downloads")
583 : di_ptr->destination,
586 if (!args.get("fileName").is<picojson::null>()) {
587 if (args.get("fileName").is<std::string>() && args.get("fileName").get<std::string>() != "") {
588 di_ptr->file_name = args.get("fileName").get<std::string>();
592 if (!args.get("networkType").is<picojson::null>()) {
593 network_type = args.get("networkType").is<std::string>()
594 ? args.get("networkType").get<std::string>()
598 bool network_support = false;
599 bool network_available = false;
601 common::PlatformResult result =
602 CheckNetworkConnection(network_type, network_support, network_available, di_ptr);
604 LogAndReportError(result, &out);
609 * There is no relevant feature for network_type == "ALL".
611 if (!network_support && ("ALL" != network_type)) {
612 LogAndReportError(common::PlatformResult(common::ErrorCode::NOT_SUPPORTED_ERR,
613 "The networkType of the given DownloadRequest "
614 "is not supported on this device."),
616 ("Requested network type (%s) is not supported.", network_type.c_str()));
620 if (!network_available) {
621 LogAndReportError(common::PlatformResult(common::ErrorCode::NETWORK_ERR,
622 "The networkType of the given DownloadRequest "
623 "is currently not available on this device."),
625 ("Requested network type (%s) is not available.", network_type.c_str()));
629 CallbackPtr down_cb_ptr(new DownloadCallback);
631 down_cb_ptr->download_id = di_ptr->download_id;
632 down_cb_ptr->instance = this;
634 download_callbacks[down_cb_ptr->download_id] = down_cb_ptr;
636 ret = download_create(&di_ptr->native_download_id);
637 if (ret != DOWNLOAD_ERROR_NONE) {
638 LogAndReportError(convertError(ret), &out,
639 ("download_create error: %d (%s)", ret, get_error_message(ret)));
643 ret = download_set_state_changed_cb(di_ptr->native_download_id, OnStateChanged,
644 static_cast<void*>(down_cb_ptr));
645 if (ret != DOWNLOAD_ERROR_NONE) {
646 LogAndReportError(convertError(ret), &out, ("download_set_state_changed_cb error: %d (%s)", ret,
647 get_error_message(ret)));
651 ret = download_set_progress_cb(di_ptr->native_download_id, progress_changed_cb,
652 static_cast<void*>(down_cb_ptr));
653 if (ret != DOWNLOAD_ERROR_NONE) {
654 LogAndReportError(convertError(ret), &out,
655 ("download_set_progress_cb error: %d (%s)", ret, get_error_message(ret)));
659 ret = download_set_url(di_ptr->native_download_id, di_ptr->url.c_str());
660 if (ret != DOWNLOAD_ERROR_NONE) {
661 LogAndReportError(convertError(ret), &out,
662 ("download_set_url error: %d (%s)", ret, get_error_message(ret)));
666 if (di_ptr->destination.size() != 0) {
667 ret = download_set_destination(di_ptr->native_download_id, di_ptr->destination.c_str());
668 if (ret != DOWNLOAD_ERROR_NONE) {
669 LogAndReportError(convertError(ret), &out,
670 ("download_set_destination error: %d (%s)", ret, get_error_message(ret)));
675 if (!di_ptr->file_name.empty()) {
676 ret = download_set_file_name(di_ptr->native_download_id, di_ptr->file_name.c_str());
677 if (ret != DOWNLOAD_ERROR_NONE) {
678 LogAndReportError(convertError(ret), &out,
679 ("download_set_file_name error: %d (%s)", ret, get_error_message(ret)));
684 ret = download_set_network_type(di_ptr->native_download_id, di_ptr->network_type);
686 if (args.get("httpHeader").is<picojson::object>()) {
687 picojson::object obj = args.get("httpHeader").get<picojson::object>();
688 for (picojson::object::const_iterator it = obj.begin(); it != obj.end(); ++it) {
689 download_add_http_header_field(di_ptr->native_download_id, it->first.c_str(),
690 it->second.to_str().c_str());
694 di_map[down_cb_ptr->download_id] = di_ptr;
696 ret = download_start(di_ptr->native_download_id);
698 if (ret == DOWNLOAD_ERROR_NONE) {
701 LogAndReportError(convertError(ret), &out,
702 ("download_start error: %d (%s)", ret, get_error_message(ret)));
706 void DownloadInstance::DownloadManagerCancel(const picojson::value& args, picojson::object& out) {
708 CHECK_EXIST(args, "downloadId", out)
711 int callbackId = static_cast<int>(args.get("downloadId").get<double>());
713 if (!GetDownloadID(callbackId, downloadId)) {
715 common::PlatformResult(common::ErrorCode::UNKNOWN_ERR,
716 "The identifier does not match any download operation in progress"),
717 &out, ("downloadId: %d, found in WEB Api but missing in native API", callbackId));
721 ret = download_cancel(downloadId);
723 if (ret == DOWNLOAD_ERROR_NONE) {
726 LogAndReportError(convertError(ret), &out,
727 ("download_cancel error: %d (%s)", ret, get_error_message(ret)));
731 void DownloadInstance::DownloadManagerPause(const picojson::value& args, picojson::object& out) {
733 CHECK_EXIST(args, "downloadId", out)
736 int callbackId = static_cast<int>(args.get("downloadId").get<double>());
738 if (!GetDownloadID(callbackId, downloadId)) {
740 common::PlatformResult(common::ErrorCode::UNKNOWN_ERR,
741 "The identifier does not match any download operation in progress"),
742 &out, ("downloadId: %d, found in WEB Api but missing in native API", downloadId));
746 ret = download_pause(downloadId);
748 if (ret == DOWNLOAD_ERROR_NONE) {
751 LogAndReportError(convertError(ret), &out,
752 ("download_pause error: %d (%s)", ret, get_error_message(ret)));
756 void DownloadInstance::DownloadManagerAbandon(const picojson::value& args, picojson::object& out) {
758 CHECK_EXIST(args, "downloadId", out)
759 int callbackId, nativeDownloadId, ret;
760 callbackId = static_cast<int>(args.get("downloadId").get<double>());
762 if (!GetDownloadID(callbackId, nativeDownloadId)) {
764 common::PlatformResult(common::ErrorCode::UNKNOWN_ERR,
765 "The identifier does not match any download operation in progress"),
766 &out, ("downloadId: %d, found in WEB Api but missing in native API", callbackId));
770 ret = download_destroy(nativeDownloadId);
771 if (ret == DOWNLOAD_ERROR_NONE) {
772 if (di_map.find(callbackId) != di_map.end()) {
773 di_map.find(callbackId)->second->abandoned = true;
777 LogAndReportError(convertError(ret), &out,
778 ("download_destroy error: %d (%s)", ret, get_error_message(ret)));
782 void DownloadInstance::DownloadManagerResume(const picojson::value& args, picojson::object& out) {
784 CHECK_EXIST(args, "downloadId", out)
785 int nativeDownloadId, ret;
787 int callbackId = static_cast<int>(args.get("downloadId").get<double>());
789 if ((di_map.end() != di_map.find(callbackId)) && (di_map.find(callbackId)->second->abandoned)) {
791 common::PlatformResult(common::ErrorCode::INVALID_VALUES_ERR,
792 "The download operation with given identifier has been abandoned "
793 "and can not be resumed"),
795 ("The download operation with identifier: %d has been abandoned and can not be resumed",
800 if (!GetDownloadID(callbackId, nativeDownloadId)) {
802 common::PlatformResult(common::ErrorCode::UNKNOWN_ERR,
803 "The identifier does not match any download operation in progress"),
804 &out, ("downloadId: %d, found in WEB Api but missing in native API", callbackId));
808 download_state_e state;
809 ret = download_get_state(nativeDownloadId, &state);
811 if (ret == DOWNLOAD_ERROR_NONE) {
813 case DOWNLOAD_STATE_QUEUED:
814 case DOWNLOAD_STATE_DOWNLOADING:
815 case DOWNLOAD_STATE_COMPLETED:
819 LoggerD("Download state: %d", state);
823 ret = download_set_state_changed_cb(nativeDownloadId, OnStateChanged,
824 static_cast<void*>(download_callbacks[callbackId]));
825 if (ret != DOWNLOAD_ERROR_NONE) {
826 LogAndReportError(convertError(ret), &out, ("download_set_state_changed_cb error: %d (%s)", ret,
827 get_error_message(ret)));
831 ret = download_set_progress_cb(nativeDownloadId, progress_changed_cb,
832 static_cast<void*>(download_callbacks[callbackId]));
833 if (ret != DOWNLOAD_ERROR_NONE) {
834 LogAndReportError(convertError(ret), &out,
835 ("download_set_progress_cb error: %d (%s)", ret, get_error_message(ret)));
839 ret = download_start(nativeDownloadId);
841 if (ret == DOWNLOAD_ERROR_NONE) {
844 LogAndReportError(convertError(ret), &out,
845 ("download_start error: %d (%s)", ret, get_error_message(ret)));
849 void DownloadInstance::DownloadManagerGetState(const picojson::value& args, picojson::object& out) {
851 CHECK_EXIST(args, "downloadId", out)
853 std::string stateValue;
854 download_state_e state;
856 int callbackId = static_cast<int>(args.get("downloadId").get<double>());
858 if (di_map.find(callbackId)->second->abandoned) {
859 stateValue = "ABANDONED";
860 ReportSuccess(picojson::value(stateValue), out);
864 if (!GetDownloadID(callbackId, downloadId)) {
866 common::PlatformResult(common::ErrorCode::NOT_FOUND_ERR,
867 "The identifier does not match any download operation in progress"),
868 &out, ("The identifier %d does not match any download operation in progress", downloadId));
872 ret = download_get_state(downloadId, &state);
874 if (ret == DOWNLOAD_ERROR_NONE) {
876 case DOWNLOAD_STATE_NONE:
878 case DOWNLOAD_STATE_QUEUED:
879 stateValue = "QUEUED";
881 case DOWNLOAD_STATE_DOWNLOADING:
882 stateValue = "DOWNLOADING";
884 case DOWNLOAD_STATE_PAUSED:
885 stateValue = "PAUSED";
887 case DOWNLOAD_STATE_COMPLETED:
888 stateValue = "COMPLETED";
890 case DOWNLOAD_STATE_FAILED:
891 stateValue = "FAILED";
893 case DOWNLOAD_STATE_CANCELED:
894 stateValue = "CANCELED";
897 LoggerD("Unexpected download state: %d", state);
901 ReportSuccess(picojson::value(stateValue), out);
903 LogAndReportError(convertError(ret), &out,
904 ("download_get_state error: %d (%s)", ret, get_error_message(ret)));
908 void DownloadInstance::DownloadManagerGetMimeType(const picojson::value& args,
909 picojson::object& out) {
911 CHECK_EXIST(args, "downloadId", out)
914 char* mimetype = NULL;
916 int callbackId = static_cast<int>(args.get("downloadId").get<double>());
918 if (!GetDownloadID(callbackId, downloadId)) {
920 common::PlatformResult(common::ErrorCode::NOT_FOUND_ERR,
921 "The identifier does not match any download operation in progress"),
922 &out, ("The identifier %d does not match any download operation in progress", downloadId));
926 ret = download_get_mime_type(downloadId, &mimetype);
928 if (ret == DOWNLOAD_ERROR_NONE) {
929 ReportSuccess(picojson::value(mimetype), out);
931 LogAndReportError(convertError(ret), &out,
932 ("download_get_mime_type error: %d (%s)", ret, get_error_message(ret)));
937 bool DownloadInstance::GetDownloadID(const int download_id, int& native_download_id) {
939 if (di_map.find(download_id) != di_map.end()) {
940 native_download_id = di_map.find(download_id)->second->native_download_id;
949 } // namespace download
950 } // namespace extension