Skip to content

Commit

Permalink
Added new fetch method getDownloadBlocks(downloadId: Int, func: Func<…
Browse files Browse the repository at this point in the history
…List<DownloadBlock>>): Fetch
  • Loading branch information
tonyofrancis committed Jul 1, 2018
1 parent 600825c commit d50c996
Show file tree
Hide file tree
Showing 13 changed files with 250 additions and 115 deletions.
11 changes: 11 additions & 0 deletions fetch2/src/main/java/com/tonyodev/fetch2/Fetch.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.tonyodev.fetch2.util.DEFAULT_ENABLE_LISTENER_NOTIFY_ON_ATTACHED
import com.tonyodev.fetch2.util.DEFAULT_INSTANCE_NAMESPACE
import com.tonyodev.fetch2core.GLOBAL_FETCH_CONFIGURATION_NOT_SET
import com.tonyodev.fetch2.util.createConfigWithNewNamespace
import com.tonyodev.fetch2core.DownloadBlock
import com.tonyodev.fetch2core.Func
import com.tonyodev.fetch2core.Func2

Expand Down Expand Up @@ -340,6 +341,16 @@ interface Fetch {
* */
fun addCompletedDownloads(completedDownloads: List<CompletedDownload>, func: Func<List<Download>>? = null, func2: Func<Error>? = null): Fetch

/**
* Gets the list of download blocks belonging to a download. List may be empty if
* blocks could not be found for the download id or download has never been processed.
* @param downloadId: Download ID
* @param func Callback the results will be returned on
* @throws FetchException if this instance of Fetch has been closed.
* @return Instance
* */
fun getDownloadBlocks(downloadId: Int, func: Func<List<DownloadBlock>>): Fetch

/**
* Enable or disable logging.
* @param enabled Enable or disable logging.
Expand Down
17 changes: 17 additions & 0 deletions fetch2/src/main/java/com/tonyodev/fetch2/FetchExtentions.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.tonyodev.fetch2

import com.tonyodev.fetch2.exception.FetchException
import com.tonyodev.fetch2core.DownloadBlock
import com.tonyodev.fetch2core.Func
import com.tonyodev.fetch2core.Func2

Expand Down Expand Up @@ -230,4 +231,20 @@ fun Fetch.addCompletedDownload(completedDownloads: List<CompletedDownload>, func
})
}

/**
* Gets the list of download blocks belonging to a download. List may be empty if
* blocks could not be found for the download id or download has never been processed.
* @param downloadId: Download ID
* @param func Callback the results will be returned on
* @throws FetchException if this instance of Fetch has been closed.
* @return Instance
* */
fun Fetch.getDownloadBlocks(downloadId: Int, func: (List<DownloadBlock>) -> Unit): Fetch {
return getDownloadBlocks(downloadId, object : Func<List<DownloadBlock>> {
override fun call(t: List<DownloadBlock>) {
func(t)
}
})
}


Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ interface DownloadManager : Closeable {
fun getDownloads(): List<Download>
fun getNewFileDownloaderForDownload(download: Download): FileDownloader?
fun getFileDownloaderDelegate(): FileDownloader.Delegate
fun getDownloadFileTempDir(download: Download): String
}
Original file line number Diff line number Diff line change
Expand Up @@ -239,4 +239,15 @@ class DownloadManagerImpl(private val httpDownloader: Downloader,
downloadBlockHandlerWrapper = downloadBlockHandlerWrapper)
}

override fun getDownloadFileTempDir(download: Download): String {
val request = getRequestForDownload(download)
return if (fileServerDownloader != null && isFetchFileServerUrl(request.url)) {
fileServerDownloader.getDirectoryForFileDownloaderTypeParallel(request)
?: fileTempDir
} else {
httpDownloader.getDirectoryForFileDownloaderTypeParallel(request)
?: fileTempDir
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ class ParallelFileDownloaderImpl(private val initialDownload: Download,
}
throwExceptionIfFound()
completedDownload = true
deleteAllTempFiles()
if (md5CheckingEnabled) {
if (downloader.verifyContentMD5(openingResponse.request, openingResponse.md5)) {
delegate?.onProgress(
Expand Down Expand Up @@ -233,13 +232,13 @@ class ParallelFileDownloaderImpl(private val initialDownload: Download,
if (!file.exists()) {
deleteAllTempFiles()
}
val previousSliceSize = getPreviousSliceCount(downloadInfo.id)
val previousSliceSize = getPreviousSliceCount(downloadInfo.id, fileTempDir)
return if (acceptsRanges) {
val fileSliceInfo = getChuckInfo(request)
if (previousSliceSize != fileSliceInfo.slicingCount) {
deleteAllTempFiles()
}
saveCurrentSliceCount(downloadInfo.id, fileSliceInfo.slicingCount)
saveCurrentSliceCount(downloadInfo.id, fileSliceInfo.slicingCount, fileTempDir)
var counterBytes = 0L
val fileSlices = mutableListOf<FileSlice>()
for (position in 1..fileSliceInfo.slicingCount) {
Expand All @@ -256,7 +255,7 @@ class ParallelFileDownloaderImpl(private val initialDownload: Download,
position = position,
startBytes = startBytes,
endBytes = endBytes,
downloaded = getSavedDownloadedInfo(downloadInfo.id, position)
downloaded = getSavedDownloadedInfo(downloadInfo.id, position, fileTempDir)
)
downloaded += fileSlice.downloaded
fileSlices.add(fileSlice)
Expand All @@ -269,101 +268,22 @@ class ParallelFileDownloaderImpl(private val initialDownload: Download,
if (previousSliceSize != 1) {
deleteAllTempFiles()
}
saveCurrentSliceCount(downloadInfo.id, 1)
saveCurrentSliceCount(downloadInfo.id, 1, fileTempDir)
val fileSlice = FileSlice(
id = downloadInfo.id,
position = 1,
startBytes = 0,
endBytes = total,
downloaded = getSavedDownloadedInfo(downloadInfo.id, 1))
downloaded = getSavedDownloadedInfo(downloadInfo.id, 1, fileTempDir))
downloaded += fileSlice.downloaded
listOf(fileSlice)
}
}

private fun getPreviousSliceCount(id: Int): Int {
var sliceCount = -1
try {
sliceCount = getSingleLineTextFromFile(getMetaFilePath(id))?.toInt() ?: -1
} catch (e: Exception) {
}
return sliceCount
}

private fun saveCurrentSliceCount(id: Int, SliceCount: Int) {
try {
writeTextToFile(getMetaFilePath(id), SliceCount.toString())
} catch (e: Exception) {
}
}

private fun getMetaFilePath(id: Int): String {
return "$fileTempDir/$id.meta.txt"
}

private fun getChuckInfo(request: Downloader.ServerRequest): FileSliceInfo {
val fileSliceSize = downloader.getFileSlicingCount(request, total)
?: DEFAULT_FILE_SLICE_NO_LIMIT_SET
return if (fileSliceSize == DEFAULT_FILE_SLICE_NO_LIMIT_SET) {
val fileSizeInMb = total.toFloat() / 1024F * 1024F
val fileSizeInGb = total.toFloat() / 1024F * 1024F * 1024F
when {
fileSizeInGb >= 1F -> {
val slices = 6
val bytesPerSlice = ceil((total.toFloat() / slices.toFloat())).toLong()
FileSliceInfo(slices, bytesPerSlice)
}
fileSizeInMb >= 1F -> {
val slices = 4
val bytesPerSlice = ceil((total.toFloat() / slices.toFloat())).toLong()
FileSliceInfo(slices, bytesPerSlice)
}
else -> FileSliceInfo(2, total)
}
} else {
val bytesPerSlice = ceil((total.toFloat() / fileSliceSize.toFloat())).toLong()
return FileSliceInfo(fileSliceSize, bytesPerSlice)
}
}

private fun getDownloadedInfoFilePath(id: Int, position: Int): String {
return "$fileTempDir/$id.$position.txt"
}

private fun deleteTempFile(id: Int, position: Int) {
try {
val textFile = getFile(getDownloadedInfoFilePath(id, position))
if (textFile.exists()) {
textFile.delete()
}
} catch (e: Exception) {
}
}

private fun deleteMetaFile(id: Int) {
try {
val textFile = getFile(getMetaFilePath(id))
if (textFile.exists()) {
textFile.delete()
}
} catch (e: Exception) {
}
}

private fun getSavedDownloadedInfo(id: Int, position: Int): Long {
var downloaded = 0L
try {
downloaded = getSingleLineTextFromFile(getDownloadedInfoFilePath(id, position))?.toLong() ?: 0L
} catch (e: Exception) {
}
return downloaded
}

private fun saveDownloadedInfo(id: Int, position: Int, downloaded: Long) {
try {
writeTextToFile(getDownloadedInfoFilePath(id, position), downloaded.toString())
} catch (e: Exception) {
}
return getFileSliceInfo(fileSliceSize, total)
}

private fun getAverageDownloadedBytesPerSecond(): Long {
Expand Down Expand Up @@ -478,7 +398,7 @@ class ParallelFileDownloaderImpl(private val initialDownload: Download,
val hasReportingTimeElapsed = hasIntervalTimeElapsed(reportingStartTime,
reportingStopTime, DEFAULT_DOWNLOAD_SPEED_REPORTING_INTERVAL_IN_MILLISECONDS)
if (hasReportingTimeElapsed) {
saveDownloadedInfo(fileSlice.id, fileSlice.position, fileSlice.downloaded)
saveDownloadedInfo(fileSlice.id, fileSlice.position, fileSlice.downloaded, fileTempDir)
downloadBlock.downloadedBytes = fileSlice.downloaded
delegate?.onDownloadBlockUpdated(downloadInfo, downloadBlock, totalDownloadBlocks)
reportingStartTime = System.nanoTime()
Expand All @@ -489,7 +409,7 @@ class ParallelFileDownloaderImpl(private val initialDownload: Download,
}
}
}
saveDownloadedInfo(fileSlice.id, fileSlice.position, fileSlice.downloaded)
saveDownloadedInfo(fileSlice.id, fileSlice.position, fileSlice.downloaded, fileTempDir)
downloadBlock.downloadedBytes = fileSlice.downloaded
delegate?.onDownloadBlockUpdated(downloadInfo, downloadBlock, totalDownloadBlocks)
} else if (downloadResponse == null && !interrupted && !terminated) {
Expand Down Expand Up @@ -522,9 +442,9 @@ class ParallelFileDownloaderImpl(private val initialDownload: Download,
private fun deleteAllTempFiles() {
try {
for (fileSlice in fileSlices) {
deleteTempFile(fileSlice.id, fileSlice.position)
deleteTempFile(fileSlice.id, fileSlice.position, fileTempDir)
}
deleteMetaFile(downloadInfo.id)
deleteMetaFile(downloadInfo.id, fileTempDir)
} catch (e: Exception) {
}
}
Expand All @@ -549,18 +469,4 @@ class ParallelFileDownloaderImpl(private val initialDownload: Download,
}
}

data class FileSliceInfo(val slicingCount: Int, val bytesPerFileSlice: Long)

data class FileSlice(val id: Int = 0,
val position: Int = 0,
val startBytes: Long = 0L,
val endBytes: Long = 0L,
var downloaded: Long = 0L) {

val isDownloaded: Boolean
get() {
return startBytes + downloaded == endBytes
}
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.tonyodev.fetch2.fetch

import com.tonyodev.fetch2.*
import com.tonyodev.fetch2core.DownloadBlock
import java.io.Closeable

/**
Expand Down Expand Up @@ -45,5 +46,6 @@ interface FetchHandler : Closeable {
fun removeListener(listener: FetchListener)
fun isDownloading(id: Int): Boolean
fun cancelDownload(id: Int): Boolean
fun getDownloadBlocks(downloadId: Int): List<DownloadBlock>

}
44 changes: 44 additions & 0 deletions fetch2/src/main/java/com/tonyodev/fetch2/fetch/FetchHandlerImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,50 @@ class FetchHandlerImpl(private val namespace: String,
return databaseManager.getDownloadsByRequestIdentifier(identifier)
}

override fun getDownloadBlocks(downloadId: Int): List<DownloadBlock> {
startPriorityQueueIfNotStarted()
val download = databaseManager.get(downloadId)
return if (download != null) {
val fileTempDir = downloadManager.getDownloadFileTempDir(download)
val fileSliceInfo = getFileSliceInfo(getPreviousSliceCount(download.id, fileTempDir), download.total)
when {
download.total < 1 -> listOf()
fileSliceInfo.slicingCount < 2 -> {
val downloadBlockInfo = DownloadBlockInfo()
downloadBlockInfo.downloadId = download.id
downloadBlockInfo.blockPosition = 1
downloadBlockInfo.startByte = 0
downloadBlockInfo.endByte = download.total
downloadBlockInfo.downloadedBytes = download.downloaded
listOf(downloadBlockInfo)
}
else -> {
var counterBytes = 0L
val downloadBlocksList = mutableListOf<DownloadBlockInfo>()
for (position in 1..fileSliceInfo.slicingCount) {
val startBytes = counterBytes
val endBytes = if (fileSliceInfo.slicingCount == position) {
download.total
} else {
counterBytes + fileSliceInfo.bytesPerFileSlice
}
counterBytes = endBytes
val downloadBlockInfo = DownloadBlockInfo()
downloadBlockInfo.downloadId = download.id
downloadBlockInfo.blockPosition = position
downloadBlockInfo.startByte = startBytes
downloadBlockInfo.endByte = endBytes
downloadBlockInfo.downloadedBytes = getSavedDownloadedInfo(download.id, position, fileTempDir)
downloadBlocksList.add(downloadBlockInfo)
}
downloadBlocksList
}
}
} else {
listOf()
}
}

override fun close() {
if (isTerminating) {
return
Expand Down
22 changes: 18 additions & 4 deletions fetch2/src/main/java/com/tonyodev/fetch2/fetch/FetchImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ import com.tonyodev.fetch2.exception.FetchException
import com.tonyodev.fetch2.getErrorFromMessage
import com.tonyodev.fetch2.fetch.FetchModulesBuilder.Modules
import com.tonyodev.fetch2.util.DEFAULT_ENABLE_LISTENER_NOTIFY_ON_ATTACHED
import com.tonyodev.fetch2core.Func
import com.tonyodev.fetch2core.Func2
import com.tonyodev.fetch2core.HandlerWrapper
import com.tonyodev.fetch2core.Logger
import com.tonyodev.fetch2core.*

open class FetchImpl constructor(override val namespace: String,
protected val handlerWrapper: HandlerWrapper,
Expand Down Expand Up @@ -686,6 +683,23 @@ open class FetchImpl constructor(override val namespace: String,
}
}

override fun getDownloadBlocks(downloadId: Int, func: Func<List<DownloadBlock>>): Fetch {
synchronized(lock) {
throwExceptionIfClosed()
handlerWrapper.post {
try {
val downloadBlocksList = fetchHandler.getDownloadBlocks(downloadId)
uiHandler.post {
func.call(downloadBlocksList)
}
} catch (e: FetchException) {
logger.e("Fetch with namespace $namespace error", e)
}
}
return this
}
}

override fun setGlobalNetworkType(networkType: NetworkType): Fetch {
synchronized(lock) {
throwExceptionIfClosed()
Expand Down
Loading

0 comments on commit d50c996

Please sign in to comment.