2 // Tizen Web Device API
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
23 #include <FilesystemUtils.h>
25 #include "DownloadManager.h"
30 static std::string _get_download_error(int err)
36 case DOWNLOAD_ERROR_INVALID_PARAMETER:
37 msg = "Invalid parameter";
39 case DOWNLOAD_ERROR_OUT_OF_MEMORY:
40 msg = "Out of memory";
42 case DOWNLOAD_ERROR_NETWORK_UNREACHABLE:
43 msg = "Network is unreachable";
45 case DOWNLOAD_ERROR_CONNECTION_TIMED_OUT:
46 msg = "Http session time-out";
48 case DOWNLOAD_ERROR_NO_SPACE:
49 msg = "No space left on device";
51 case DOWNLOAD_ERROR_FIELD_NOT_FOUND:
52 msg = "Specified field not found";
54 case DOWNLOAD_ERROR_INVALID_STATE:
55 msg = "Invalid state";
57 case DOWNLOAD_ERROR_CONNECTION_FAILED:
58 msg = "Connection failed";
60 case DOWNLOAD_ERROR_INVALID_URL:
63 case DOWNLOAD_ERROR_INVALID_DESTINATION:
64 msg = "Invalid destination";
66 case DOWNLOAD_ERROR_TOO_MANY_DOWNLOADS:
67 msg = "Full of available simultaneous downloads";
69 case DOWNLOAD_ERROR_QUEUE_FULL:
70 msg = "Full of available downloading items from server";
72 case DOWNLOAD_ERROR_ALREADY_COMPLETED:
73 msg = "The download is already completed";
75 case DOWNLOAD_ERROR_FILE_ALREADY_EXISTS:
76 msg = "It is failed to rename the downloaded file";
78 case DOWNLOAD_ERROR_CANNOT_RESUME:
79 msg = "It cannot resume";
81 case DOWNLOAD_ERROR_TOO_MANY_REDIRECTS:
82 msg = "In case of too may redirects from http response header";
84 case DOWNLOAD_ERROR_UNHANDLED_HTTP_CODE:
85 msg = "The download cannot handle the http status value";
87 case DOWNLOAD_ERROR_REQUEST_TIMEOUT:
88 msg = "There are no action after client create a download id";
90 case DOWNLOAD_ERROR_RESPONSE_TIMEOUT:
91 msg = "It does not call start API in some time although the download is created";
93 case DOWNLOAD_ERROR_SYSTEM_DOWN:
94 msg = "There are no response from client after rebooting download daemon";
96 case DOWNLOAD_ERROR_ID_NOT_FOUND:
97 msg = "The download id is not existed in download service module";
99 case DOWNLOAD_ERROR_NO_DATA:
100 msg = "No data because the set API is not called";
102 case DOWNLOAD_ERROR_IO_ERROR:
103 msg = "Internal I/O error";
105 case DOWNLOAD_ERROR_NONE:
109 msg = "Unknown error";
113 LogError("Platform error %d <%s>", err, msg.c_str());
122 download_state_e state;
123 unsigned long long received;
125 } DOWNLOAD_EVENT_DATA_T;
128 static gboolean downloadEventCB(void *data) {
131 DOWNLOAD_EVENT_DATA_T *fnData = static_cast<DOWNLOAD_EVENT_DATA_T*>(data);
134 long downloadId = (long)fnData->downloadId;
136 DownloadManager *thisObj = (DownloadManager*)fnData->user_data;
138 throw UnknownException("UserData is NULL.");
141 DownloadCallback *callback = thisObj->getCallbackFromMap(downloadId);
143 throw UnknownException("Callback could not found.");
146 switch(fnData->state) {
147 case DOWNLOAD_STATE_QUEUED:
149 callback->onprogress(downloadId, 0, 0);
152 case DOWNLOAD_STATE_PAUSED:
154 callback->onpaused(downloadId);
157 case DOWNLOAD_STATE_DOWNLOADING:
159 unsigned long long totalSize = 0;
160 ret = download_get_content_size(downloadId, &totalSize);
161 if (ret != DOWNLOAD_ERROR_NONE) {
162 throw UnknownException(("Platform error while getting total file size. " + _get_download_error(ret)).c_str());
165 callback->onprogress(downloadId, fnData->received, totalSize);
168 case DOWNLOAD_STATE_COMPLETED:
170 ret = download_unset_state_changed_cb(downloadId);
171 if (ret != DOWNLOAD_ERROR_NONE) {
172 throw UnknownException(("Platform error while unsetting state changed callback. " + _get_download_error(ret)).c_str());
175 ret = download_unset_progress_cb(downloadId);
176 if (ret != DOWNLOAD_ERROR_NONE) {
177 throw UnknownException(("Platform error while unsetting progress callback. " + _get_download_error(ret)).c_str());
180 char *fullPath = NULL;
181 ret = download_get_downloaded_file_path(downloadId, &fullPath);
182 if (ret != DOWNLOAD_ERROR_NONE || !fullPath) {
183 throw UnknownException(("Platform error while getting downloaded full path. " + _get_download_error(ret)).c_str());
186 std::string virtualPath;
188 virtualPath = DeviceAPI::Filesystem::Utils::toVirtualPath(NULL, fullPath);
190 LogWarning("Platform error while converting fullPath.");
191 virtualPath = fullPath;
194 callback->oncompleted(downloadId, virtualPath);
197 thisObj->removeCallbackFromMap(downloadId);
200 case DOWNLOAD_STATE_FAILED:
202 ret = download_unset_state_changed_cb(downloadId);
203 if (ret != DOWNLOAD_ERROR_NONE) {
204 throw UnknownException(("Platform error while unsetting state changed callback. " + _get_download_error(ret)).c_str());
207 ret = download_unset_progress_cb(downloadId);
208 if (ret != DOWNLOAD_ERROR_NONE) {
209 throw UnknownException(("Platform error while unsetting progress callback. " + _get_download_error(ret)).c_str());
212 int err = DOWNLOAD_ERROR_NONE;
213 std::string errMessage;
214 ret = download_get_error(downloadId, (download_error_e*)&err);
215 if (ret != DOWNLOAD_ERROR_NONE) {
216 LogWarning("Platform error while getting download error. ");
218 errMessage = _get_download_error(err);
221 UnknownException error(errMessage.c_str());
222 callback->onfailed(downloadId, error);
223 thisObj->removeCallbackFromMap(downloadId);
226 case DOWNLOAD_STATE_CANCELED:
228 ret = download_unset_state_changed_cb(downloadId);
229 if (ret != DOWNLOAD_ERROR_NONE) {
230 throw UnknownException(("Platform error while unsetting state changed callback. " + _get_download_error(ret)).c_str());
233 ret = download_unset_progress_cb(downloadId);
234 if (ret != DOWNLOAD_ERROR_NONE) {
235 throw UnknownException(("Platform error while unsetting progress callback. " + _get_download_error(ret)).c_str());
238 callback->oncanceled(downloadId);
239 thisObj->removeCallbackFromMap(downloadId);
243 LogWarning("State changed is ignored.");
246 } catch (const BasePlatformException &err) {
247 LogError("download_state_changed_cb: %s", err.getMessage().c_str());
254 static void download_state_changed_cb(int downloadId, download_state_e state, void *user_data)
256 LogDebug("download_state_changed_cb, downloadId=%d, state=%d", downloadId, (int)state);
257 DOWNLOAD_EVENT_DATA_T *data = new DOWNLOAD_EVENT_DATA_T;
258 data->downloadId = downloadId;
261 data->user_data = user_data;
263 // download core f/w calls this callback function in another thread.
264 // so we should use g_idle_add() to switch context to main thread.
265 g_idle_add(downloadEventCB, static_cast<void*>(data));
268 static void download_progress_cb(int downloadId, unsigned long long received, void *user_data)
270 LogDebug("download_progress_cb, downloadId=%d, received=%ld", downloadId, received);
271 DOWNLOAD_EVENT_DATA_T *data = new DOWNLOAD_EVENT_DATA_T;
272 data->downloadId = downloadId;
273 data->state = DOWNLOAD_STATE_DOWNLOADING;
274 data->received = received;
275 data->user_data = user_data;
277 // download core f/w calls this callback function in another thread.
278 // so we should use g_idle_add() to switch context to main thread.
279 g_idle_add(downloadEventCB, static_cast<void*>(data));
282 DownloadManager::DownloadManager()
286 DownloadManager::~DownloadManager()
290 void DownloadManager::setCallbackToMap(long downloadId, DownloadCallback *callback)
292 DownloadCallback *value = mDownloadCallbacks[downloadId];
296 mDownloadCallbacks[downloadId] = callback;
299 DownloadCallback* DownloadManager::getCallbackFromMap(long downloadId)
301 return mDownloadCallbacks[downloadId];
304 void DownloadManager::removeCallbackFromMap(long downloadId) {
305 DownloadCallback *value = mDownloadCallbacks[downloadId];
306 mDownloadCallbacks.erase(downloadId);
312 long DownloadManager::start(DownloadRequest *request, DownloadCallback *downloadCallback)
321 throw TypeMismatchException("request is NULL.");
324 std::string url = request->getUrl();
325 std::string destination = request->getDestination();
326 std::string fileName = request->getFileName();
328 LogDebug("url <%s>, destination <%s>, fileName <%s>", url.c_str(), destination.c_str(), fileName.c_str());
331 throw InvalidValuesException("Invalid DownloadRequest.url.");
334 ret = download_create(&downloadId);
335 if (ret != DOWNLOAD_ERROR_NONE) {
336 throw UnknownException(("Platform error while creating download. " + _get_download_error(ret)).c_str());
339 ret = download_set_url(downloadId, url.c_str());
340 if (ret != DOWNLOAD_ERROR_NONE) {
341 throw UnknownException(("Platform error while setting url. " + _get_download_error(ret)).c_str());
344 if (!destination.empty()) {
345 std::string fullPath;
347 DeviceAPI::Filesystem::IPathPtr path = DeviceAPI::Filesystem::Utils::fromVirtualPath(NULL, destination);
348 fullPath = path->getFullPath();
350 LogWarning("Converting virtual path is failed. [%s]", destination.c_str());
351 fullPath = destination;
353 LogDebug("Converted FullPath = <%s>", fullPath.c_str());
354 ret = download_set_destination(downloadId, fullPath.c_str());
355 if (ret != DOWNLOAD_ERROR_NONE) {
356 throw UnknownException(("Platform error while setting destination. " + _get_download_error(ret)).c_str());
360 if (!fileName.empty()) {
361 ret = download_set_file_name(downloadId, fileName.c_str());
362 if (ret != DOWNLOAD_ERROR_NONE) {
363 throw UnknownException(("Platform error while setting fileName. " + _get_download_error(ret)).c_str());
367 ret = download_set_state_changed_cb(downloadId, download_state_changed_cb, this);
368 if (ret != DOWNLOAD_ERROR_NONE) {
369 throw UnknownException(("Platform error while setting state changed callback. " + _get_download_error(ret)).c_str());
372 ret = download_set_progress_cb(downloadId, download_progress_cb, this);
373 if (ret != DOWNLOAD_ERROR_NONE) {
374 throw UnknownException(("Platform error while setting progress callback. " + _get_download_error(ret)).c_str());
377 ret = download_start(downloadId);
378 if (ret != DOWNLOAD_ERROR_NONE) {
379 throw UnknownException(("Platform error while starting download. " + _get_download_error(ret)).c_str());
382 LogDebug("downloadId: %d", downloadId);
384 setCallbackToMap(downloadId, downloadCallback);
389 void DownloadManager::cancel(long downloadId)
393 LogDebug("entered. downloadId = %d", downloadId);
395 ret = download_cancel(downloadId);
396 if (ret != DOWNLOAD_ERROR_NONE) {
397 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
398 throw NotFoundException("download id could not found.");
399 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
400 throw InvalidValuesException("download id is not valid.");
402 throw UnknownException(("Platform error while canceling download. " + _get_download_error(ret)).c_str());
406 void DownloadManager::pause(long downloadId)
410 LogDebug("entered. downloadId = %d", downloadId);
412 ret = download_pause(downloadId);
413 if (ret != DOWNLOAD_ERROR_NONE) {
414 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
415 throw NotFoundException("download id could not found.");
416 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
417 throw InvalidValuesException("download id is not valid.");
419 throw UnknownException(("Platform error while pausing download. " + _get_download_error(ret)).c_str());
423 void DownloadManager::resume(long downloadId)
427 LogDebug("entered. downloadId = %d", downloadId);
429 ret = download_start(downloadId);
430 if (ret != DOWNLOAD_ERROR_NONE) {
431 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
432 throw NotFoundException("download id could not found.");
433 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
434 throw InvalidValuesException("download id is not valid.");
436 throw UnknownException(("Platform error while resuming download. " + _get_download_error(ret)).c_str());
440 std::string DownloadManager::getState(long downloadId)
443 download_state_e state;
446 LogDebug("entered. downloadId = %d", downloadId);
448 ret = download_get_state(downloadId, &state);
449 if (ret != DOWNLOAD_ERROR_NONE) {
450 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
451 throw NotFoundException("download id could not found.");
452 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
453 throw InvalidValuesException("download id is not valid.");
455 throw UnknownException(("Platform error while getting state. " + _get_download_error(ret)).c_str());
459 case DOWNLOAD_STATE_READY:
460 case DOWNLOAD_STATE_QUEUED:
461 result = TIZEN_ENUM_DOWNLOAD_STATE_QUEUED;
463 case DOWNLOAD_STATE_DOWNLOADING:
464 result = TIZEN_ENUM_DOWNLOAD_STATE_DOWNLOADING;
466 case DOWNLOAD_STATE_PAUSED:
467 result = TIZEN_ENUM_DOWNLOAD_STATE_PAUSED;
469 case DOWNLOAD_STATE_COMPLETED:
470 result = TIZEN_ENUM_DOWNLOAD_STATE_COMPLETED;
472 case DOWNLOAD_STATE_FAILED:
473 result = TIZEN_ENUM_DOWNLOAD_STATE_FAILED;
475 case DOWNLOAD_STATE_CANCELED:
476 result = TIZEN_ENUM_DOWNLOAD_STATE_CANCELED;
479 result = "undefined";
480 LogWarning("Unknown DownloadState was returned.");
487 DownloadRequest* DownloadManager::getDownloadRequest(long downloadId)
492 char *destination = NULL;
493 char *fileName = NULL;
495 LogDebug("entered. downloadId = %d", downloadId);
497 ret = download_get_url(downloadId, &url);
498 if (ret != DOWNLOAD_ERROR_NONE) {
499 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
500 throw NotFoundException("download id could not found.");
501 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
502 throw InvalidValuesException("download id is not valid.");
504 throw UnknownException(("Platform error while getting url. " + _get_download_error(ret)).c_str());
507 ret = download_get_destination(downloadId, &destination);
508 if (ret != DOWNLOAD_ERROR_NONE && ret != DOWNLOAD_ERROR_NO_DATA) {
509 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
510 throw NotFoundException("download id could not found.");
511 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
512 throw InvalidValuesException("download id is not valid.");
514 throw UnknownException(("Platform error while getting destination. " + _get_download_error(ret)).c_str());
517 ret = download_get_file_name(downloadId, &fileName);
518 if (ret != DOWNLOAD_ERROR_NONE && ret != DOWNLOAD_ERROR_NO_DATA) {
519 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
520 throw NotFoundException("download id could not found.");
521 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
522 throw InvalidValuesException("download id is not valid.");
524 throw UnknownException(("Platform error while getting fileName. " + _get_download_error(ret)).c_str());
527 DownloadRequest *request = new DownloadRequest();
530 request->setUrl(url);
535 std::string virtualPath;
537 virtualPath = DeviceAPI::Filesystem::Utils::toVirtualPath(NULL, destination);
539 LogWarning("Platform error while converting destination path.");
540 virtualPath = destination;
542 request->setDestination(virtualPath);
547 request->setFileName(fileName);
554 std::string DownloadManager::getMIMEType(long downloadId)
557 char *mimeType = NULL;
558 std::string result("");
560 LogDebug("entered. downloadId = %d", downloadId);
562 ret = download_get_mime_type(downloadId, &mimeType);
563 if (ret != DOWNLOAD_ERROR_NONE) {
564 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
565 throw NotFoundException("download id could not found.");
566 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
567 throw InvalidValuesException("download id is not valid.");
568 } else if (ret == DOWNLOAD_ERROR_NO_DATA) {
571 throw UnknownException(("Platform error while getting MIME type. " + _get_download_error(ret)).c_str());
584 void DownloadManager::setListener(long downloadId, DownloadCallback *downloadCallback)
588 LogDebug("entered. downloadId = %d", downloadId);
590 ret = download_set_state_changed_cb(downloadId, download_state_changed_cb, this);
591 if (ret != DOWNLOAD_ERROR_NONE) {
592 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
593 throw NotFoundException("download id could not found.");
594 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
595 throw InvalidValuesException("download id is not valid.");
597 throw UnknownException(("Platform error while setting state changed callback. " + _get_download_error(ret)).c_str());
600 ret = download_set_progress_cb(downloadId, download_progress_cb, this);
601 if (ret != DOWNLOAD_ERROR_NONE) {
602 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
603 throw NotFoundException("download id could not found.");
604 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
605 throw InvalidValuesException("download id is not valid.");
607 throw UnknownException(("Platform error while setting progress callback. " + _get_download_error(ret)).c_str());
610 setCallbackToMap(downloadId, downloadCallback);