http file info

v4
lyy 2 years ago
parent 3fd103d616
commit b378d9e3f2
  1. 42
      Http/src/main/java/com/arialyy/aria/http/download/HttpDHeaderInterceptor.kt
  2. 28
      Http/src/main/java/com/arialyy/aria/http/download/HttpDStartController.kt
  3. 8
      Http/src/main/java/com/arialyy/aria/http/download/HttpDTaskOption.kt
  4. 17
      Http/src/main/java/com/arialyy/aria/http/download/HttpDTaskUtil.kt
  5. 10
      PublicComponent/src/main/java/com/arialyy/aria/core/task/AbsTaskUtil.kt

@ -40,7 +40,7 @@ import java.util.UUID
* @Description * @Description
* @Date 2:27 PM 2023/1/28 * @Date 2:27 PM 2023/1/28
**/ **/
internal class HttpHeaderInterceptor : ITaskInterceptor { internal class HttpDHeaderInterceptor : ITaskInterceptor {
private lateinit var task: ITask private lateinit var task: ITask
private lateinit var taskOption: HttpDTaskOption private lateinit var taskOption: HttpDTaskOption
@ -53,22 +53,27 @@ internal class HttpHeaderInterceptor : ITaskInterceptor {
override fun interceptor(chain: TaskChain): TaskResp { override fun interceptor(chain: TaskChain): TaskResp {
if (Looper.myLooper() == Looper.getMainLooper()) { if (Looper.myLooper() == Looper.getMainLooper()) {
throw IllegalThreadStateException("Io operations cannot be in the main thread") throw IllegalThreadStateException("io operations cannot be in the main thread")
} }
Timber.i("step 1. get file info")
task = chain.getTask() task = chain.getTask()
taskOption = task.getTaskOption(HttpDTaskOption::class.java) taskOption = task.getTaskOption(HttpDTaskOption::class.java)
return try { try {
val fileSize = getFileSize() val fileSize = getFileSize()
if (fileSize >= 0) {
chain.proceed(task) task.taskState.fileSize = fileSize
return chain.proceed(task)
}
} catch (e: IOException) { } catch (e: IOException) {
Timber.e( Timber.e(
"download fail, url: ${ "download fail, url: ${
chain.getTask().getTaskOption(HttpDTaskOption::class.java).sourUrl chain.getTask().getTaskOption(HttpDTaskOption::class.java).sourUrl
}" }"
) )
TaskResp(TaskResp.CODE_GET_FILE_INFO_FAIL) return TaskResp(TaskResp.CODE_GET_FILE_INFO_FAIL)
} }
Timber.e("can't get fileSize")
return TaskResp(TaskResp.CODE_INTERRUPT)
} }
@Throws(IOException::class) @Throws(IOException::class)
@ -78,8 +83,8 @@ internal class HttpHeaderInterceptor : ITaskInterceptor {
val conn: HttpURLConnection = IRequest.getRequest(taskOption.httpOption!!) val conn: HttpURLConnection = IRequest.getRequest(taskOption.httpOption!!)
.getDConnection(taskOption.sourUrl!!, taskOption.httpOption!!) .getDConnection(taskOption.sourUrl!!, taskOption.httpOption!!)
// https://httpwg.org/specs/rfc9110.html#byte.ranges // https://httpwg.org/specs/rfc9110.html#byte.ranges
// conn.setRequestProperty("Range", "bytes=" + 0 + "-") conn.setRequestProperty("Range", "bytes=0-")
conn.setRequestProperty("Range", "bytes=0-1") // 尝试获取1个字节 // conn.setRequestProperty("Range", "bytes=0-1") // 尝试获取1个字节
conn.connect() conn.connect()
return handleConnect(conn) return handleConnect(conn)
} }
@ -109,9 +114,17 @@ internal class HttpHeaderInterceptor : ITaskInterceptor {
reader.close() reader.close()
return handleUrlReTurn(conn, HttpUtil.getWindowReplaceUrl(sb.toString())) return handleUrlReTurn(conn, HttpUtil.getWindowReplaceUrl(sb.toString()))
} }
val chunkSize = checkChunkFileSize(conn)
if (chunkSize > -1) {
Timber.d("the url is chunk task, ${conn.url}")
return chunkSize
}
// code is 200, but file size cannot be obtained. // code is 200, but file size cannot be obtained.
return -1 return -1
} }
code == 416 -> {
return getFileSizeFromHeader(conn.headerFields, taskOption)
}
code in CODE_30X -> { code in CODE_30X -> {
Timber.d("handle 30x turn, code: $code") Timber.d("handle 30x turn, code: $code")
return handleUrlReTurn(conn, conn.getHeaderField("Location")) return handleUrlReTurn(conn, conn.getHeaderField("Location"))
@ -126,6 +139,19 @@ internal class HttpHeaderInterceptor : ITaskInterceptor {
} }
} }
/**
* if headers has [rfc9112 Transfer-Encoding](https://httpwg.org/specs/rfc9112.html#chunked.trailer.section)
* the url is chunk task
*/
private fun checkChunkFileSize(conn: HttpURLConnection): Long {
val chunkHead = conn.headerFields["Transfer-Encoding"]
if (chunkHead.isNullOrEmpty()) {
return -1
}
taskOption.isChunkTask = true
return 0
}
@Throws(IOException::class) private fun handleUrlReTurn( @Throws(IOException::class) private fun handleUrlReTurn(
oldConn: HttpURLConnection, oldConn: HttpURLConnection,
newUrl: String? newUrl: String?

@ -22,12 +22,14 @@ import com.arialyy.aria.core.command.StartCmd
import com.arialyy.aria.core.inf.IStartController import com.arialyy.aria.core.inf.IStartController
import com.arialyy.aria.core.processor.IHttpFileLenAdapter import com.arialyy.aria.core.processor.IHttpFileLenAdapter
import com.arialyy.aria.core.task.DownloadTask import com.arialyy.aria.core.task.DownloadTask
import com.arialyy.aria.core.task.ITaskInterceptor
import com.arialyy.aria.core.task.TaskCachePool import com.arialyy.aria.core.task.TaskCachePool
import com.arialyy.aria.http.HttpBaseController import com.arialyy.aria.http.HttpBaseController
import com.arialyy.aria.http.HttpOption import com.arialyy.aria.http.HttpOption
import com.arialyy.aria.http.HttpUtil import com.arialyy.aria.http.HttpUtil
import com.arialyy.aria.orm.entity.DEntity import com.arialyy.aria.orm.entity.DEntity
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber
import java.net.HttpURLConnection import java.net.HttpURLConnection
/** /**
@ -44,6 +46,19 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseController(ta
httpDTaskOption.sourUrl = url httpDTaskOption.sourUrl = url
} }
/**
* use multi-threaded download file, if file size <= 5m, this setting is not valid
* @param threadNum range [1 - 32]
*/
fun setThreadNum(threadNum: Long): HttpDStartController {
if (threadNum !in 1..32) {
Timber.e("set thread num fail, only 0 < threadNum < 33, threadNum: $threadNum")
return this
}
httpDTaskOption.threadNum = threadNum
return this
}
/** /**
* set http params, link Header * set http params, link Header
*/ */
@ -56,11 +71,22 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseController(ta
* Maybe the server has special rules, you need set [IHttpFileLenAdapter] to get the file length from [HttpURLConnection.getHeaderFields] * Maybe the server has special rules, you need set [IHttpFileLenAdapter] to get the file length from [HttpURLConnection.getHeaderFields]
*/ */
fun setHttpFileLenAdapter(adapter: IHttpFileLenAdapter): HttpDStartController { fun setHttpFileLenAdapter(adapter: IHttpFileLenAdapter): HttpDStartController {
httpDTaskOption.fileSizeAdapter = adapter httpDTaskOption.fileSizeAdapter = adapter
return this return this
} }
/**
* if you want to do something before the task is executed, you can set up a task interceptor
* eg: determine the network status before task execution
*/
fun setTaskInterceptor(taskInterceptor: ITaskInterceptor): HttpDStartController {
httpDTaskOption.taskInterceptor.add(taskInterceptor)
return this
}
/**
* set download listener
*/
fun setListener(listener: HttpDownloadListener): HttpDStartController { fun setListener(listener: HttpDownloadListener): HttpDStartController {
DuaContext.getLifeManager().addCustomListener(target, listener) DuaContext.getLifeManager().addCustomListener(target, listener)
return this return this

@ -17,6 +17,7 @@ package com.arialyy.aria.http.download
import com.arialyy.aria.core.download.DTaskOption import com.arialyy.aria.core.download.DTaskOption
import com.arialyy.aria.core.processor.IHttpFileLenAdapter import com.arialyy.aria.core.processor.IHttpFileLenAdapter
import com.arialyy.aria.core.task.ITaskInterceptor
import com.arialyy.aria.http.HttpOption import com.arialyy.aria.http.HttpOption
/** /**
@ -26,6 +27,13 @@ import com.arialyy.aria.http.HttpOption
**/ **/
class HttpDTaskOption : DTaskOption() { class HttpDTaskOption : DTaskOption() {
companion object {
const val BLOCK_SIZE = 1024 * 1024 * 5
}
var httpOption: HttpOption? = null var httpOption: HttpOption? = null
var fileSizeAdapter: IHttpFileLenAdapter? = null var fileSizeAdapter: IHttpFileLenAdapter? = null
var taskInterceptor = mutableListOf<ITaskInterceptor>()
var isChunkTask = false
var threadNum: Long = 1L
} }

@ -1,6 +1,9 @@
package com.arialyy.aria.http.download package com.arialyy.aria.http.download
import com.arialyy.aria.core.DuaContext
import com.arialyy.aria.core.task.AbsTaskUtil import com.arialyy.aria.core.task.AbsTaskUtil
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
/** /**
* @Author laoyuyu * @Author laoyuyu
@ -9,10 +12,6 @@ import com.arialyy.aria.core.task.AbsTaskUtil
**/ **/
internal class HttpDTaskUtil : AbsTaskUtil() { internal class HttpDTaskUtil : AbsTaskUtil() {
init {
}
override fun isRunning(): Boolean { override fun isRunning(): Boolean {
TODO("Not yet implemented") TODO("Not yet implemented")
} }
@ -26,6 +25,14 @@ internal class HttpDTaskUtil : AbsTaskUtil() {
} }
override fun start() { override fun start() {
getTask().getTaskOption(HttpDTaskOption::class.java).taskInterceptor.let {
if (it.isNotEmpty()) {
addInterceptors(it)
}
}
addCoreInterceptor(HttpDHeaderInterceptor())
DuaContext.duaScope.launch(Dispatchers.IO) {
val resp = interceptor()
}
} }
} }

@ -25,8 +25,8 @@ import com.arialyy.aria.core.task.ITaskInterceptor.IChain
* @Date 1:12 PM 2023/1/28 * @Date 1:12 PM 2023/1/28
**/ **/
abstract class AbsTaskUtil : ITaskUtil { abstract class AbsTaskUtil : ITaskUtil {
protected lateinit var mTask: ITask private lateinit var mTask: ITask
protected lateinit var mEventListener: IEventListener private lateinit var mEventListener: IEventListener
private val mUserInterceptor = mutableListOf<ITaskInterceptor>() private val mUserInterceptor = mutableListOf<ITaskInterceptor>()
private val mCoreInterceptor = mutableListOf<ITaskInterceptor>() private val mCoreInterceptor = mutableListOf<ITaskInterceptor>()
@ -36,14 +36,16 @@ abstract class AbsTaskUtil : ITaskUtil {
mEventListener = listener mEventListener = listener
} }
protected fun getTask() = mTask
/** /**
* add user interceptor * add user interceptor
*/ */
open fun setInterceptors(userInterceptors: List<ITaskInterceptor>) { protected fun addInterceptors(userInterceptors: List<ITaskInterceptor>) {
mUserInterceptor.addAll(userInterceptors) mUserInterceptor.addAll(userInterceptors)
} }
protected open fun addCoreInterceptor(interceptor: ITaskInterceptor) { protected fun addCoreInterceptor(interceptor: ITaskInterceptor) {
mCoreInterceptor.add(interceptor) mCoreInterceptor.add(interceptor)
} }

Loading…
Cancel
Save