From c692c0e8d7b4c6ceade4ef3f40a79bf2735ff238 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Mon, 30 Apr 2018 15:05:18 -0400 Subject: [PATCH] Fixed and Added new Request Options --- .../main/java/com/tonyodev/fetch2/Error.kt | 8 +- .../com/tonyodev/fetch2/FetchErrorUtils.kt | 2 - .../com/tonyodev/fetch2/RequestOptions.kt | 12 +- .../fetch2/exception/FetchException.kt | 3 +- .../tonyodev/fetch2/fetch/FetchHandlerImpl.kt | 185 +++++++++--------- .../com/tonyodev/fetch2/util/ErrorStrings.kt | 3 +- .../main/java/com/tonyodev/fetchapp/App.java | 4 +- 7 files changed, 103 insertions(+), 114 deletions(-) diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/Error.kt b/fetch2/src/main/java/com/tonyodev/fetch2/Error.kt index 30694ba0..132acb50 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/Error.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/Error.kt @@ -83,12 +83,7 @@ enum class Error constructor( /** Indicates that the file belonging to the request has been deleted. The file * could have been deleted by an external source.*/ - FILE_NOT_FOUND(17), - - /** Indicates that multiple requests with the same ID requested to be enqueued. - * @see com.tonyodev.fetch2.Request for more information. - * */ - MULTI_REQUESTS_WITH_IDENTICAL_ID(18); + FILE_NOT_FOUND(17); companion object { @@ -114,7 +109,6 @@ enum class Error constructor( 15 -> REQUEST_NOT_SUCCESSFUL 16 -> UNKNOWN_IO_ERROR 17 -> FILE_NOT_FOUND - 18 -> MULTI_REQUESTS_WITH_IDENTICAL_ID else -> UNKNOWN } } diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/FetchErrorUtils.kt b/fetch2/src/main/java/com/tonyodev/fetch2/FetchErrorUtils.kt index b1b22f71..5b135daa 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/FetchErrorUtils.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/FetchErrorUtils.kt @@ -54,8 +54,6 @@ fun getErrorFromMessage(message: String?): Error { Error.FETCH_ALREADY_EXIST } else if (message.contains(RESPONSE_NOT_SUCCESSFUL, true) || message.contains(FAILED_TO_CONNECT, true)) { Error.REQUEST_NOT_SUCCESSFUL - } else if (message.equals(MULTI_REQUESTS_WITH_IDENTICAL_ID, true)) { - Error.MULTI_REQUESTS_WITH_IDENTICAL_ID } else { Error.UNKNOWN } diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/RequestOptions.kt b/fetch2/src/main/java/com/tonyodev/fetch2/RequestOptions.kt index 65207c02..53faed2d 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/RequestOptions.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/RequestOptions.kt @@ -22,22 +22,22 @@ enum class RequestOptions { * The file is deleted if it exists.*/ AUTO_REMOVE_ON_COMPLETED_DELETE_FILE, - /** Fetch will auto replace an existing request where the id matches on enqueue. + /** Fetch will auto replace an existing request in the database where the id matches on enqueue. * If the old request has started the download process, this new request will continue where * it left off.*/ - REPLACE_ON_ENQUEUE, + REPLACE_ON_ENQUEUE_ID, - /** Fetch will auto replace an existing request where the id matches on enqueue. + /** Fetch will auto replace an existing request in the database where the id matches on enqueue. * If the old request has started the download process, this new request will force * downloading from the beginning.*/ - REPLACE_ON_ENQUEUE_FRESH, + REPLACE_ON_ENQUEUE_FRESH_ID, - /** Fetch will remove any existing requests on enqueue that matches the new request's id or file. + /** Fetch will remove any existing requests in the database on enqueue that matches the new request's id or file. * If an old request has started the download process, this new request will continue where * it left off.*/ REPLACE_ALL_ON_ENQUEUE_WHERE_UNIQUE, - /** Fetch will remove any existing requests on enqueue that matches the new request's id or file. + /** Fetch will remove any existing requests in the database on enqueue that matches the new request's id or file. * If the old request has started the download process, this new request will force * downloading from the beginning.*/ REPLACE_ALL_ON_ENQUEUE_WHERE_UNIQUE_FRESH, diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/exception/FetchException.kt b/fetch2/src/main/java/com/tonyodev/fetch2/exception/FetchException.kt index fce5ce83..c4d68730 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/exception/FetchException.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/exception/FetchException.kt @@ -16,8 +16,7 @@ open class FetchException constructor(message: String, LOGGER, ILLEGAL_CONCURRENT_INSERT, INVALID_STATUS, - DOWNLOAD_NOT_FOUND, - MULTI_REQUESTS_WITH_IDENTICAL_ID; + DOWNLOAD_NOT_FOUND } } \ No newline at end of file diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/fetch/FetchHandlerImpl.kt b/fetch2/src/main/java/com/tonyodev/fetch2/fetch/FetchHandlerImpl.kt index e760059b..eca619c6 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/fetch/FetchHandlerImpl.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/fetch/FetchHandlerImpl.kt @@ -6,8 +6,6 @@ import com.tonyodev.fetch2.* import com.tonyodev.fetch2.database.DatabaseManager import com.tonyodev.fetch2.database.DownloadInfo import com.tonyodev.fetch2.downloader.DownloadManager -import com.tonyodev.fetch2.exception.FetchException -import com.tonyodev.fetch2.exception.FetchImplementationException import com.tonyodev.fetch2.provider.ListenerProvider import com.tonyodev.fetch2.helper.PriorityListProcessor import com.tonyodev.fetch2.util.* @@ -37,48 +35,80 @@ class FetchHandlerImpl(private val namespace: String, } override fun enqueue(request: Request): Download { - startPriorityQueueIfNotStarted() val downloadInfo = request.toDownloadInfo() downloadInfo.namespace = namespace downloadInfo.status = Status.QUEUED - return enqueue(downloadInfo) - } - - private fun enqueue(downloadInfo: DownloadInfo): Download { - return when { - requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE) || - requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE_FRESH) -> { - var existingDownloadInfo = databaseManager.get(downloadInfo.id) - if (existingDownloadInfo == null) { - updateFileForDownloadInfoIfNeeded(downloadInfo) - databaseManager.insert(downloadInfo) - startPriorityQueueIfNotStarted() - downloadInfo - } else { - cancelDownload(existingDownloadInfo.id) - existingDownloadInfo = databaseManager.get(downloadInfo.id) - if (existingDownloadInfo != null) { - if (requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE)) { - downloadInfo.downloaded = existingDownloadInfo.downloaded - downloadInfo.total = existingDownloadInfo.total - if (existingDownloadInfo.status == Status.COMPLETED) { - downloadInfo.status = existingDownloadInfo.status - } + prepareDownloadInfoForEnqueue(downloadInfo) + databaseManager.insert(downloadInfo) + startPriorityQueueIfNotStarted() + return downloadInfo + } + + private fun prepareDownloadInfoForEnqueue(downloadInfo: DownloadInfo) { + var doAutoIncrementFileNameCheck = true + when { + //Jump in here if any request options pertain to enqueuing a request + requestOptions.contains(RequestOptions.REPLACE_ALL_ON_ENQUEUE_WHERE_UNIQUE) + || requestOptions.contains(RequestOptions.REPLACE_ALL_ON_ENQUEUE_WHERE_UNIQUE_FRESH) + || requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE_ID) + || requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE_FRESH_ID) + || requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE_FILE) + || requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE_FRESH_FILE) -> { + //If any options pertain to id, do a database query based on id. If match found cancel download. + var existingDownloadInfoWithId: DownloadInfo? = null + if (requestOptions.contains(RequestOptions.REPLACE_ALL_ON_ENQUEUE_WHERE_UNIQUE) + || requestOptions.contains(RequestOptions.REPLACE_ALL_ON_ENQUEUE_WHERE_UNIQUE_FRESH) + || requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE_ID) + || requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE_FRESH_ID)) { + existingDownloadInfoWithId = databaseManager.get(downloadInfo.id) + if (existingDownloadInfoWithId != null) { + cancelDownload(existingDownloadInfoWithId.id) + existingDownloadInfoWithId = databaseManager.get(downloadInfo.id) + } + } + //If any options pertain to file, do a database query based on file. If match found cancel download. + var existingDownloadInfoWithFile: DownloadInfo? = null + if (requestOptions.contains(RequestOptions.REPLACE_ALL_ON_ENQUEUE_WHERE_UNIQUE) + || requestOptions.contains(RequestOptions.REPLACE_ALL_ON_ENQUEUE_WHERE_UNIQUE_FRESH) + || requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE_FILE) + || requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE_FRESH_FILE)) { + existingDownloadInfoWithFile = databaseManager.getByFile(downloadInfo.file) + if (existingDownloadInfoWithFile != null) { + cancelDownload(existingDownloadInfoWithFile.id) + existingDownloadInfoWithFile = databaseManager.getByFile(downloadInfo.file) + } + } + //If less damaging(do not delete existing file) option exist jump in here + if (requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE_ID) + || requestOptions.contains(RequestOptions.REPLACE_ALL_ON_ENQUEUE_WHERE_UNIQUE) + || requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE_FILE)) { + val download: DownloadInfo? = existingDownloadInfoWithFile + ?: existingDownloadInfoWithId + if (download != null) { + downloadInfo.downloaded = download.downloaded + downloadInfo.total = download.total + if (download.status == Status.COMPLETED) { + downloadInfo.status = download.status } - databaseManager.delete(existingDownloadInfo) + doAutoIncrementFileNameCheck = false + } else { + doAutoIncrementFileNameCheck = true } - databaseManager.insert(downloadInfo) - startPriorityQueueIfNotStarted() - downloadInfo + } else { + doAutoIncrementFileNameCheck = true + } + //Delete found records if they exist + if (existingDownloadInfoWithFile != null) { + databaseManager.delete(existingDownloadInfoWithFile) + } + if (existingDownloadInfoWithId != null) { + databaseManager.delete(existingDownloadInfoWithId) } - } - else -> { - updateFileForDownloadInfoIfNeeded(downloadInfo) - databaseManager.insert(downloadInfo) - startPriorityQueueIfNotStarted() - downloadInfo } } + if (doAutoIncrementFileNameCheck) { + updateFileForDownloadInfoIfNeeded(downloadInfo) + } } private fun updateFileForDownloadInfoIfNeeded(downloadInfo: DownloadInfo) { @@ -86,7 +116,8 @@ class FetchHandlerImpl(private val namespace: String, } private fun updateFileForDownloadInfoIfNeeded(downloadInfoList: List) { - if (requestOptions.contains(RequestOptions.ADD_AUTO_INCREMENT_TO_FILE_ON_ENQUEUE)) { + if (requestOptions.contains(RequestOptions.ADD_AUTO_INCREMENT_TO_FILE_ON_ENQUEUE) + || requestOptions.contains(RequestOptions.REPLACE_ALL_ON_ENQUEUE_WHERE_UNIQUE)) { downloadInfoList.forEach { downloadInfo -> val file = getIncrementedFileIfOriginalExists(downloadInfo.file) val generatedId = getUniqueId(downloadInfo.url, downloadInfo.file) @@ -100,71 +131,39 @@ class FetchHandlerImpl(private val namespace: String, } override fun enqueue(requests: List): List { - startPriorityQueueIfNotStarted() - val distinctCount = requests.distinctBy { it.id }.count() - if (distinctCount != requests.size) { - throw FetchException(MULTI_REQUESTS_WITH_IDENTICAL_ID, FetchException.Code.MULTI_REQUESTS_WITH_IDENTICAL_ID) - } - val downloadInfoList = requests.map { + val requestsList = prepareRequestListForEnqueue(requests) + val downloadInfoList = requestsList.map { val downloadInfo = it.toDownloadInfo() downloadInfo.namespace = namespace downloadInfo.status = Status.QUEUED + prepareDownloadInfoForEnqueue(downloadInfo) downloadInfo } - val results = mutableListOf() - val insertedList = enqueueList(downloadInfoList) - insertedList.forEach { - if (it.second) { - logger.d("Enqueued download ${it.first}") - results.add(it.first) - } - } + val results = databaseManager.insert(downloadInfoList) + .filter { it.second } + .map { + logger.d("Enqueued download ${it.first}") + it.first + } + startPriorityQueueIfNotStarted() return results } - private fun enqueueList(downloadInfoList: List): List> { - return when { - requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE) || - requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE_FRESH) -> { - val ids = downloadInfoList.map { it.id } - var existingDownloadInfoList = databaseManager.get(ids).filterNotNull() - if (existingDownloadInfoList.isEmpty()) { - updateFileForDownloadInfoIfNeeded(downloadInfoList) - val downloads = databaseManager.insert(downloadInfoList) - startPriorityQueueIfNotStarted() - downloads - } else { - existingDownloadInfoList.forEach { - cancelDownload(it.id) - } - existingDownloadInfoList = databaseManager.get(downloadInfoList.map { it.id }).filterNotNull() - if (requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE)) { - downloadInfoList.forEach { - val existingDownloadInfo = existingDownloadInfoList.find { downloadInfo -> - it.id == downloadInfo.id - } - if (existingDownloadInfo != null) { - it.downloaded = existingDownloadInfo.downloaded - it.total = existingDownloadInfo.total - if (existingDownloadInfo.status == Status.COMPLETED) { - it.status = existingDownloadInfo.status - } - } - } - } - databaseManager.delete(downloadInfoList) - val downloads = databaseManager.insert(downloadInfoList) - startPriorityQueueIfNotStarted() - downloads - } - } - else -> { - updateFileForDownloadInfoIfNeeded(downloadInfoList) - val downloads = databaseManager.insert(downloadInfoList) - startPriorityQueueIfNotStarted() - downloads - } + private fun prepareRequestListForEnqueue(requests: List): List { + var sequence = requests.asSequence() + if (requestOptions.contains(RequestOptions.REPLACE_ALL_ON_ENQUEUE_WHERE_UNIQUE) + || requestOptions.contains(RequestOptions.REPLACE_ALL_ON_ENQUEUE_WHERE_UNIQUE_FRESH) + || requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE_ID) + || requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE_FRESH_ID)) { + sequence = sequence.distinctBy { it.id } + } + if (requestOptions.contains(RequestOptions.REPLACE_ALL_ON_ENQUEUE_WHERE_UNIQUE) + || requestOptions.contains(RequestOptions.REPLACE_ALL_ON_ENQUEUE_WHERE_UNIQUE_FRESH) + || requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE_FILE) + || requestOptions.contains(RequestOptions.REPLACE_ON_ENQUEUE_FRESH_FILE)) { + sequence = sequence.distinctBy { it.file } } + return sequence.toList() } override fun pause(ids: IntArray): List { diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/util/ErrorStrings.kt b/fetch2/src/main/java/com/tonyodev/fetch2/util/ErrorStrings.kt index 3ddaf78b..19ffad92 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/util/ErrorStrings.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/util/ErrorStrings.kt @@ -24,5 +24,4 @@ const val UNIQUE_ID_DATABASE = "UNIQUE constraint failed: requests._id" const val UNIQUE_FILE_PATH_DATABASE = "UNIQUE constraint failed: requests._file" const val FAILED_TO_CONNECT = "Failed to connect" const val SOFTWARE_ABORT_CONNECTION = "Software caused connection abort" -const val READ_TIME_OUT = "Read timed out at" -const val MULTI_REQUESTS_WITH_IDENTICAL_ID = "Cannot enqueue multiple requests with same id." \ No newline at end of file +const val READ_TIME_OUT = "Read timed out at" \ No newline at end of file diff --git a/sampleApp/src/main/java/com/tonyodev/fetchapp/App.java b/sampleApp/src/main/java/com/tonyodev/fetchapp/App.java index ae55dc8d..88eae913 100644 --- a/sampleApp/src/main/java/com/tonyodev/fetchapp/App.java +++ b/sampleApp/src/main/java/com/tonyodev/fetchapp/App.java @@ -57,7 +57,7 @@ public Fetch getNewFetchInstance(@NonNull final String namespace) { .setDownloadConcurrentLimit(4) .enableLogging(true) .enableRetryOnNetworkGain(true) - .addRequestOptions(RequestOptions.REPLACE_ON_ENQUEUE) + .addRequestOptions(RequestOptions.REPLACE_ALL_ON_ENQUEUE_WHERE_UNIQUE) .build(); } @@ -69,7 +69,7 @@ public RxFetch getRxFetch() { .setDownloader(new OkHttpOutputStreamDownloader(client)) .setDownloadConcurrentLimit(1) .enableLogging(true) - .addRequestOptions(RequestOptions.REPLACE_ON_ENQUEUE_FRESH) + .addRequestOptions(RequestOptions.REPLACE_ALL_ON_ENQUEUE_WHERE_UNIQUE_FRESH) .build(); } return rxFetch;