Skip to content

Commit

Permalink
Fixed and Added new Request Options
Browse files Browse the repository at this point in the history
  • Loading branch information
tonyofrancis committed Apr 30, 2018
1 parent b9e721c commit c692c0e
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 114 deletions.
8 changes: 1 addition & 7 deletions fetch2/src/main/java/com/tonyodev/fetch2/Error.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand All @@ -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
}
}
Expand Down
2 changes: 0 additions & 2 deletions fetch2/src/main/java/com/tonyodev/fetch2/FetchErrorUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
12 changes: 6 additions & 6 deletions fetch2/src/main/java/com/tonyodev/fetch2/RequestOptions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

}
185 changes: 92 additions & 93 deletions fetch2/src/main/java/com/tonyodev/fetch2/fetch/FetchHandlerImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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.*
Expand Down Expand Up @@ -37,56 +35,89 @@ 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) {
updateFileForDownloadInfoIfNeeded(listOf(downloadInfo))
}

private fun updateFileForDownloadInfoIfNeeded(downloadInfoList: List<DownloadInfo>) {
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)
Expand All @@ -100,71 +131,39 @@ class FetchHandlerImpl(private val namespace: String,
}

override fun enqueue(requests: List<Request>): List<Download> {
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<Download>()
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<DownloadInfo>): List<Pair<Download, Boolean>> {
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<Request>): List<Request> {
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<Download> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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."
const val READ_TIME_OUT = "Read timed out at"
4 changes: 2 additions & 2 deletions sampleApp/src/main/java/com/tonyodev/fetchapp/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand All @@ -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;
Expand Down

0 comments on commit c692c0e

Please sign in to comment.