diff --git a/Http/src/main/java/com/arialyy/aria/http/HttpUtil.kt b/Http/src/main/java/com/arialyy/aria/http/HttpUtil.kt index 2702b4b3..bcaef28d 100644 --- a/Http/src/main/java/com/arialyy/aria/http/HttpUtil.kt +++ b/Http/src/main/java/com/arialyy/aria/http/HttpUtil.kt @@ -95,6 +95,10 @@ object HttpUtil { Timber.e("invalid uri, ${option.savePathUri}") return false } + if (!FileUtils.uriIsDir(option.savePathUri!!)){ + Timber.e("invalid uri, that path not a dir") + return false + } return true } } \ No newline at end of file diff --git a/Http/src/main/java/com/arialyy/aria/http/download/HttpBlockThreadInterceptor.kt b/Http/src/main/java/com/arialyy/aria/http/download/HttpBlockThreadInterceptor.kt index 11fcecc7..c5c7a4c4 100644 --- a/Http/src/main/java/com/arialyy/aria/http/download/HttpBlockThreadInterceptor.kt +++ b/Http/src/main/java/com/arialyy/aria/http/download/HttpBlockThreadInterceptor.kt @@ -17,7 +17,6 @@ package com.arialyy.aria.http.download import com.arialyy.aria.core.DuaContext import com.arialyy.aria.core.inf.IBlockManager -import com.arialyy.aria.core.task.BlockManager import com.arialyy.aria.core.task.ITaskInterceptor import com.arialyy.aria.core.task.IThreadTask import com.arialyy.aria.core.task.TaskChain @@ -39,7 +38,7 @@ class HttpBlockThreadInterceptor : ITaskInterceptor { blockManager = chain.blockManager as IBlockManager val unfinishedBlockList = blockManager.unfinishedBlockList if (unfinishedBlockList.isEmpty()) { - return TaskResp(TaskResp.CODE_BLOCK_QUEUE_NULL) + return TaskResp(TaskResp.CODE_INTERRUPT) } createThreadTask(unfinishedBlockList, chain) return TaskResp(TaskResp.CODE_SUCCESS) diff --git a/Http/src/main/java/com/arialyy/aria/http/download/HttpDBlockInterceptor.kt b/Http/src/main/java/com/arialyy/aria/http/download/HttpDBlockInterceptor.kt index 71e19959..cf53dc09 100644 --- a/Http/src/main/java/com/arialyy/aria/http/download/HttpDBlockInterceptor.kt +++ b/Http/src/main/java/com/arialyy/aria/http/download/HttpDBlockInterceptor.kt @@ -20,7 +20,6 @@ import com.arialyy.aria.core.inf.IBlockManager import com.arialyy.aria.core.inf.ITaskManager import com.arialyy.aria.core.task.ITask import com.arialyy.aria.core.task.ITaskInterceptor -import com.arialyy.aria.core.task.TaskCachePool import com.arialyy.aria.core.task.TaskChain import com.arialyy.aria.core.task.TaskResp import com.arialyy.aria.http.HttpTaskOption @@ -51,13 +50,13 @@ internal class HttpDBlockInterceptor : ITaskInterceptor { option = task.getTaskOption(HttpTaskOption::class.java) if (task.taskState.fileSize < 0) { Timber.e("file size < 0") - return TaskResp(TaskResp.CODE_GET_FILE_INFO_FAIL) + return TaskResp(TaskResp.CODE_INTERRUPT) } val savePath = FileUri.getPathByUri(task.getTaskOption(HttpTaskOption::class.java).savePathUri) if (savePath.isNullOrEmpty()) { Timber.e("saveUri is null") - return TaskResp(TaskResp.CODE_SAVE_URI_NULL) + return TaskResp(TaskResp.CODE_INTERRUPT) } // if task not support resume, don't save record @@ -95,7 +94,7 @@ internal class HttpDBlockInterceptor : ITaskInterceptor { */ private suspend fun checkRecord(): Int { val recordDao = DuaContext.getServiceManager().getDbService().getDuaDb().getRecordDao() - val recordWrapper = recordDao.getTaskRecordByKey(task.filePath) + val recordWrapper = recordDao.queryTaskRecordByKey(task.filePath) if (recordWrapper == null) { Timber.i("record not found, create record") diff --git a/Http/src/main/java/com/arialyy/aria/http/download/HttpDCheckInterceptor.kt b/Http/src/main/java/com/arialyy/aria/http/download/HttpDCheckInterceptor.kt index a4d0b747..52fb165e 100644 --- a/Http/src/main/java/com/arialyy/aria/http/download/HttpDCheckInterceptor.kt +++ b/Http/src/main/java/com/arialyy/aria/http/download/HttpDCheckInterceptor.kt @@ -36,7 +36,7 @@ class HttpDCheckInterceptor : ITaskInterceptor { private suspend fun findDEntityBySavePath(option: HttpTaskOption): DEntity { val savePath = option.savePathUri val dao = DuaContext.getServiceManager().getDbService().getDuaDb().getDEntityDao() - val de = dao.getDEntityBySavePath(savePath.toString()) + val de = dao.queryDEntityBySavePath(savePath.toString()) if (de != null) { return de } diff --git a/Http/src/main/java/com/arialyy/aria/http/download/HttpDHeaderInterceptor.kt b/Http/src/main/java/com/arialyy/aria/http/download/HttpDHeaderInterceptor.kt index ffef524b..cf64da86 100644 --- a/Http/src/main/java/com/arialyy/aria/http/download/HttpDHeaderInterceptor.kt +++ b/Http/src/main/java/com/arialyy/aria/http/download/HttpDHeaderInterceptor.kt @@ -29,6 +29,8 @@ import com.arialyy.aria.http.HttpTaskOption import com.arialyy.aria.http.HttpUtil import com.arialyy.aria.http.request.IRequest import com.arialyy.aria.orm.entity.BlockRecord +import com.arialyy.aria.orm.entity.DEntity +import com.arialyy.aria.util.DuaUtil import com.arialyy.aria.util.FileUtils import timber.log.Timber import java.io.BufferedReader @@ -45,6 +47,7 @@ import java.util.UUID internal class HttpDHeaderInterceptor : ITaskInterceptor { private lateinit var task: ITask private lateinit var taskOption: HttpTaskOption + private var disposition: String? = null companion object { private val CODE_30X = listOf( @@ -75,6 +78,12 @@ internal class HttpDHeaderInterceptor : ITaskInterceptor { getOptionAdapter().isSupportResume = fileSize != 0L getOptionAdapter().isSupportBlock = getOptionAdapter().isSupportResume && fileSize > BlockRecord.BLOCK_SIZE + val fileName = + getFileName(if (taskOption.redirectUrl.isNullOrEmpty()) taskOption.sourUrl!! else taskOption.redirectUrl!!) + (task.taskState.entity as DEntity?)?.let { + it.fileName = fileName + it.update() + } return chain.proceed(task) } } catch (e: IOException) { @@ -83,7 +92,7 @@ internal class HttpDHeaderInterceptor : ITaskInterceptor { chain.getTask().getTaskOption(HttpTaskOption::class.java).sourUrl }" ) - return TaskResp(TaskResp.CODE_GET_FILE_INFO_FAIL) + return TaskResp(TaskResp.CODE_INTERRUPT) } Timber.e("can't get fileSize") return TaskResp(TaskResp.CODE_INTERRUPT) @@ -102,10 +111,51 @@ internal class HttpDHeaderInterceptor : ITaskInterceptor { return handleConnect(conn) } + /** + * get file name + * if already set file name, use it. + * if no file name set, will try to get the file name + */ + private fun getFileName(url: String): String { + if (getOptionAdapter().fileName?.isNotEmpty() == true) { + return getOptionAdapter().fileName!! + } + // step1, get file name from header + if (!disposition.isNullOrEmpty()) { + val tempName = getFileNameFromContentDisposition(disposition!!) + if (!tempName.isNullOrEmpty()) { + Timber.d("get file name from disposition") + return tempName + } + } + + // step2. get file name from url + val fileName = FileUtils.getFileNameFromUrl(url) + if (!fileName.isNullOrEmpty()) { + Timber.d("get file name from url") + return fileName + } + + // step3. get file name from md5 + val md5Name = DuaUtil.getMD5Hash(url) + Timber.d("use the md5 code of the url to get the file name, $md5Name") + return md5Name + } + + /** + * [RFC6266](https://httpwg.org/specs/rfc6266.html#rfc.section.4) + */ + private fun getFileNameFromContentDisposition(contentDisposition: String): String? { + val regex = Regex("filename=\"(.+?)\"") + val matchResult = regex.find(contentDisposition) + return matchResult?.groupValues?.getOrNull(1) + } + @Throws(IOException::class) private fun handleConnect(conn: HttpURLConnection): Long { val code = conn.responseCode + disposition = conn.getHeaderField("Content-Disposition") when { code == HttpURLConnection.HTTP_PARTIAL -> return getFileSizeFromHeader(conn.headerFields) code == HttpURLConnection.HTTP_OK -> { diff --git a/Http/src/main/java/com/arialyy/aria/http/download/HttpDOptionAdapter.kt b/Http/src/main/java/com/arialyy/aria/http/download/HttpDOptionAdapter.kt index 89e96343..c5707529 100644 --- a/Http/src/main/java/com/arialyy/aria/http/download/HttpDOptionAdapter.kt +++ b/Http/src/main/java/com/arialyy/aria/http/download/HttpDOptionAdapter.kt @@ -39,4 +39,6 @@ class HttpDOptionAdapter : IHttpTaskOptionAdapter { */ var isSupportBlock = true + var fileName: String? = null + } \ No newline at end of file diff --git a/Http/src/main/java/com/arialyy/aria/http/download/HttpDStartController.kt b/Http/src/main/java/com/arialyy/aria/http/download/HttpDStartController.kt index 8eedfd26..f9dd4c75 100644 --- a/Http/src/main/java/com/arialyy/aria/http/download/HttpDStartController.kt +++ b/Http/src/main/java/com/arialyy/aria/http/download/HttpDStartController.kt @@ -37,11 +37,11 @@ import java.net.HttpURLConnection * @Date 12:38 PM 2023/1/22 **/ class HttpDStartController(target: Any, val url: String) : HttpBaseStartController(target) { - private val taskOptionSupport = HttpDOptionAdapter() + private val taskOptionAdapter = HttpDOptionAdapter() init { httpTaskOption.sourUrl = url - httpTaskOption.taskOptionAdapter = taskOptionSupport + httpTaskOption.taskOptionAdapter = taskOptionAdapter } override fun setTaskInterceptor(taskInterceptor: ITaskInterceptor): HttpDStartController { @@ -60,7 +60,7 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseStartControll * Maybe the server has special rules, you need set [IHttpFileLenAdapter] to get the file length from [HttpURLConnection.getHeaderFields] */ fun setHttpFileLenAdapter(adapter: IHttpFileLenAdapter): HttpDStartController { - taskOptionSupport.fileSizeAdapter = adapter + taskOptionAdapter.fileSizeAdapter = adapter return this } @@ -73,7 +73,19 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseStartControll } /** - * set file save path, eg: /mnt/sdcard/Downloads/test.zip + * set file name + */ + fun setFileName(fileName: String): HttpDStartController { + taskOptionAdapter.fileName = fileName + return this + } + + /** + * set file save path, if you don't set the [setFileName], + * it will automatically try to get the file name, and if it fails, + * the md5 code of the url will be used + * eg: /mnt/sdcard/Downloads/ + * */ fun setSavePath(savePath: Uri): HttpDStartController { httpTaskOption.savePathUri = savePath @@ -84,7 +96,7 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseStartControll if (HttpUtil.checkHttpDParams(httpTaskOption)) { throw IllegalArgumentException("invalid params") } - val tempTask = TaskCachePool.getTaskByUrl(url) + val tempTask = TaskCachePool.getTaskByKey(url) if (tempTask != null) { return tempTask as DownloadTask } diff --git a/Http/src/main/java/com/arialyy/aria/http/download/HttpDStopController.kt b/Http/src/main/java/com/arialyy/aria/http/download/HttpDStopController.kt index 9db5d876..66a1f06a 100644 --- a/Http/src/main/java/com/arialyy/aria/http/download/HttpDStopController.kt +++ b/Http/src/main/java/com/arialyy/aria/http/download/HttpDStopController.kt @@ -56,7 +56,7 @@ class HttpDStopController(val taskId: Int) { Timber.e("task not found, taskId: $taskId") return } - val util = TaskCachePool.getTaskAdapter(Uri.parse(task.filePath)) + val util = task.adapter if (util == null) { Timber.e("resume fail, please restart task, taskId: $taskId") return diff --git a/Http/src/main/java/com/arialyy/aria/http/download/HttpDTaskAdapter.kt b/Http/src/main/java/com/arialyy/aria/http/download/HttpDTaskAdapter.kt index d42dfdb9..0097745b 100644 --- a/Http/src/main/java/com/arialyy/aria/http/download/HttpDTaskAdapter.kt +++ b/Http/src/main/java/com/arialyy/aria/http/download/HttpDTaskAdapter.kt @@ -99,29 +99,4 @@ internal class HttpDTaskAdapter : AbsTaskAdapter() { Looper.loop() } } - - override fun resume() { - getTask().getTaskOption(HttpTaskOption::class.java).taskInterceptor.let { - if (it.isNotEmpty()) { - addInterceptors(it) - } - } - DuaContext.duaScope.launch(Dispatchers.IO) { - Looper.prepare() - blockManager?.setLooper() - addCoreInterceptor(TimerInterceptor()) - addCoreInterceptor(HttpDBlockInterceptor()) - addCoreInterceptor(HttpBlockThreadInterceptor()) - val resp = interceptor() - if (resp == null || resp.code != TaskResp.CODE_SUCCESS) { - getTask().getTaskOption(HttpTaskOption::class.java).eventListener.onFail( - false, - AriaException("start task fail, task interrupt, code: ${resp?.code ?: TaskResp.CODE_INTERRUPT}") - ) - blockManager?.stop() - return@launch - } - Looper.loop() - } - } } \ No newline at end of file diff --git a/HttpGroup/src/main/java/com/arialyy/dua/group/HttpDGCheckInterceptor.kt b/HttpGroup/src/main/java/com/arialyy/dua/group/HttpDGCheckInterceptor.kt index 10674b18..ea2111dc 100644 --- a/HttpGroup/src/main/java/com/arialyy/dua/group/HttpDGCheckInterceptor.kt +++ b/HttpGroup/src/main/java/com/arialyy/dua/group/HttpDGCheckInterceptor.kt @@ -15,11 +15,20 @@ */ package com.arialyy.dua.group +import android.net.Uri +import com.arialyy.aria.core.DuaContext +import com.arialyy.aria.core.task.ITask import com.arialyy.aria.core.task.ITaskInterceptor import com.arialyy.aria.core.task.TaskChain import com.arialyy.aria.core.task.TaskResp +import com.arialyy.aria.http.HttpTaskOption +import com.arialyy.aria.orm.entity.DEntity +import com.arialyy.aria.orm.entity.DGEntity import com.arialyy.aria.util.CheckUtil +import com.arialyy.aria.util.FileUri +import com.arialyy.aria.util.FileUtils import timber.log.Timber +import java.io.File /** * 1. Check if the save path is valid @@ -30,18 +39,117 @@ import timber.log.Timber **/ internal class HttpDGCheckInterceptor : ITaskInterceptor { + private lateinit var task: ITask + private lateinit var optionAdapter: HttpDGOptionAdapter + private lateinit var taskOption: HttpTaskOption + private val dgDao by lazy { + DuaContext.getServiceManager().getDbService().getDuaDb().getDGEntityDao() + } + override suspend fun interceptor(chain: TaskChain): TaskResp { - // if (optionAdapter.subUrl.isEmpty()){ - // Timber.e("sub-task list is empty") - // return -1 - // } - // - // optionAdapter.subUrl.forEach { - // if (!CheckUtil.checkUrl(it)){ - // Timber.e("invalid url: $it") - // return -1 - // } - // } + task = chain.getTask() + taskOption = task.getTaskOption(HttpTaskOption::class.java) + optionAdapter = taskOption.getOptionAdapter(HttpDGOptionAdapter::class.java) + + if (checkParams(taskOption.savePathUri)) { + return TaskResp(TaskResp.CODE_INTERRUPT) + } + + if (checkRecord()) { + return TaskResp(TaskResp.CODE_INTERRUPT) + } + return chain.proceed(task) + } + + /** + * @return false interrupt task + */ + private suspend fun checkRecord(): Boolean { + val savePath = taskOption.savePathUri + val dgE = dgDao.queryDGEntityByPath(savePath.toString()) + if (dgE == null) { + createNewEntity() + return true + } + + val dir = File(FileUri.getPathByUri(savePath)!!) + if (dir.exists()) { + val subUrl = mutableListOf() + dgE.subList.forEach { subUrl.add(it.sourceUrl) } + val diffUrl = subUrl.subtract(dgE.subList.toSet()) + if (diffUrl.isNotEmpty()) { + Timber.e("invalid savePath, the path existed: $savePath, \ndiffUrl: $diffUrl") + return false + } + } + + return true + } + + /** + * save new record + */ + private suspend fun createNewEntity(): Boolean { + Timber.d("create new task") + // create sub task record + val dgEntity = DGEntity( + savePath = taskOption.savePathUri!!, + urls = optionAdapter.subUrlList.toList(), + subNameList = optionAdapter.subNameList + ) + + val subTask = mutableListOf() + val dir = File(FileUri.getPathByUri(taskOption.savePathUri)!!) + optionAdapter.subUrlList.forEachIndexed { index, it -> + val subName = if (optionAdapter.subNameList.isNotEmpty()) { + optionAdapter.subNameList[index] + } else { + FileUtils.getFileNameFromUrl(it) ?: "subTask_${index}" + } + val subFile = File( + dir.path, + subName + ) + subTask.add( + DEntity( + sourceUrl = it, + savePath = Uri.parse(subFile.toString()), + fileName = subName + ) + ) + } + dgEntity.subList.addAll(subTask) + + dgDao.insert(dgEntity) + return true + } + + /** + * check option + * @return false interrupt task + */ + private fun checkParams(savePath: Uri?): Boolean { + if (savePath == null) { + Timber.d("save path is null") + return false + } + if (optionAdapter.subUrlList.isEmpty()) { + Timber.e("sub list is null") + return false + } + + optionAdapter.subUrlList.forEach { + if (!CheckUtil.checkUrl(it)) { + Timber.e("invalid url: $it") + return false + } + } + + if (optionAdapter.subNameList.isNotEmpty() && optionAdapter.subNameList.size != optionAdapter.subUrlList.size) { + Timber.e("subNameList.size must be consistent subUrlList.size") + return false + } + return true } } \ No newline at end of file diff --git a/HttpGroup/src/main/java/com/arialyy/dua/group/HttpDGStartController.kt b/HttpGroup/src/main/java/com/arialyy/dua/group/HttpDGStartController.kt index 50b04120..1083234e 100644 --- a/HttpGroup/src/main/java/com/arialyy/dua/group/HttpDGStartController.kt +++ b/HttpGroup/src/main/java/com/arialyy/dua/group/HttpDGStartController.kt @@ -16,16 +16,15 @@ package com.arialyy.dua.group import android.net.Uri +import com.arialyy.aria.core.command.StartCmd import com.arialyy.aria.core.task.DownloadGroupTask import com.arialyy.aria.core.task.ITaskInterceptor import com.arialyy.aria.core.task.TaskCachePool import com.arialyy.aria.http.HttpBaseStartController import com.arialyy.aria.http.HttpOption import com.arialyy.aria.http.HttpUtil -import com.arialyy.aria.util.FileUri import com.arialyy.aria.util.FileUtils import timber.log.Timber -import java.io.File /** * @Author laoyuyu @@ -69,10 +68,14 @@ class HttpDGStartController(target: Any, val savePath: Uri) : HttpBaseStartContr return this } - private fun createTask(): DownloadGroupTask { + private fun getTask(createNewTask: Boolean = true): DownloadGroupTask { if (HttpUtil.checkHttpDParams(httpTaskOption)) { throw IllegalArgumentException("invalid params") } + val temp = TaskCachePool.getTaskByKey(savePath.toString()) + if (temp != null) { + return temp as DownloadGroupTask + } val task = DownloadGroupTask(httpTaskOption) task.adapter = HttpDGroupAdapter() TaskCachePool.putTask(task) @@ -88,15 +91,9 @@ class HttpDGStartController(target: Any, val savePath: Uri) : HttpBaseStartContr Timber.e("invalid savePath: $savePath") return -1 } - val dir = File(FileUri.getPathByUri(savePath)!!) - if (dir.exists()) { - Timber.e("invalid savePath, the path existed: $savePath") - return -1 - } - if (optionAdapter.subNameList.isNotEmpty() && optionAdapter.subNameList.size != optionAdapter.subUrlList.size) { - Timber.e("subNameList.size must be consistent subUrlList.size") - return -1 - } - return createTask().taskId + + val task = getTask() + val resp = StartCmd(task).executeCmd() + return if (resp.isInterrupt()) -1 else task.taskId } } \ No newline at end of file diff --git a/HttpGroup/src/main/java/com/arialyy/dua/group/HttpDGSubTaskInterceptor.kt b/HttpGroup/src/main/java/com/arialyy/dua/group/HttpDGSubTaskInterceptor.kt deleted file mode 100644 index 5143e2fb..00000000 --- a/HttpGroup/src/main/java/com/arialyy/dua/group/HttpDGSubTaskInterceptor.kt +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.arialyy.dua.group - -import android.net.Uri -import com.arialyy.aria.core.DuaContext -import com.arialyy.aria.core.task.ITask -import com.arialyy.aria.core.task.ITaskInterceptor -import com.arialyy.aria.core.task.TaskChain -import com.arialyy.aria.core.task.TaskResp -import com.arialyy.aria.http.HttpTaskOption -import com.arialyy.aria.orm.entity.DEntity -import com.arialyy.aria.orm.entity.DGEntity -import com.arialyy.aria.util.FileUri -import timber.log.Timber -import java.io.File - -/** - * @Author laoyuyu - * @Description - * @Date 7:27 PM 2023/3/8 - **/ -internal class HttpDGSubTaskInterceptor : ITaskInterceptor { - - private val dgDao by lazy { - DuaContext.getServiceManager().getDbService().getDuaDb().getDGEntityDao() - } - - private lateinit var task: ITask - private lateinit var option: HttpTaskOption - private lateinit var dgOption: HttpDGOptionAdapter - - override suspend fun interceptor(chain: TaskChain): TaskResp { - task = chain.getTask() - option = task.getTaskOption(HttpTaskOption::class.java) - dgOption = option.getOptionAdapter(HttpDGOptionAdapter::class.java) - if (!checkRecord()) { - return TaskResp(TaskResp.CODE_INTERRUPT) - } - - - } - - /** - * check dg task record, if dfEntiry exist, return false - * otherwise, save new record - */ - private suspend fun checkRecord(): Boolean { - val entity = dgDao.getDGEntityByPath(option.savePathUri.toString()) - if (entity != null) { - Timber.e("task already exist, filePath: ${option.savePathUri}") - return false - } - // create sub task record - val dgEntity = DGEntity( - savePath = option.savePathUri!!, - urls = dgOption.subUrlList.toList(), - subNameList = dgOption.subNameList - ) - - val subTask = mutableListOf() - val dir = File(FileUri.getPathByUri(option.savePathUri)!!) - dgOption.subUrlList.forEachIndexed { index, it -> - val subFile = File( - dir.path, - if (dgOption.subNameList.isNotEmpty()) dgOption.subNameList[index] else "dgTask${index}" - ) - subTask.add( - DEntity( - sourceUrl = it, - savePath = Uri.parse(subFile.toString()), - ) - ) - } - dgEntity.subList.addAll(subTask) - - dgDao.insert(dgEntity) - return true - } -} \ No newline at end of file diff --git a/HttpGroup/src/main/java/com/arialyy/dua/group/HttpDGroupAdapter.kt b/HttpGroup/src/main/java/com/arialyy/dua/group/HttpDGroupAdapter.kt index a381bfb4..8e1d7bca 100644 --- a/HttpGroup/src/main/java/com/arialyy/dua/group/HttpDGroupAdapter.kt +++ b/HttpGroup/src/main/java/com/arialyy/dua/group/HttpDGroupAdapter.kt @@ -76,9 +76,10 @@ internal class HttpDGroupAdapter : AbsTaskAdapter() { DuaContext.duaScope.launch(Dispatchers.IO) { Looper.prepare() taskManager.setLooper() - addCoreInterceptor(HttpDCheckInterceptor()) + addCoreInterceptor(HttpDGCheckInterceptor()) addCoreInterceptor(TimerInterceptor()) - addCoreInterceptor(HttpBlockThreadInterceptor()) + addCoreInterceptor() + val resp = interceptor() if (resp == null || resp.code != TaskResp.CODE_SUCCESS) { getTask().getTaskOption(HttpTaskOption::class.java).eventListener.onFail( diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/inf/ITaskAdapter.java b/PublicComponent/src/main/java/com/arialyy/aria/core/inf/ITaskAdapter.java index a8a840ec..4aac52f5 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/inf/ITaskAdapter.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/inf/ITaskAdapter.java @@ -49,6 +49,4 @@ public interface ITaskAdapter { * 开始 */ void start(); - - void resume(); } \ No newline at end of file diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/task/DownloadGroupTask.java b/PublicComponent/src/main/java/com/arialyy/aria/core/task/DownloadGroupTask.java index 1317155a..127e880e 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/task/DownloadGroupTask.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/task/DownloadGroupTask.java @@ -33,6 +33,14 @@ public class DownloadGroupTask extends AbsTask { return DOWNLOAD_GROUP; } + /** + * @return Always return null + */ + @Deprecated + @Override public String getUrl() { + return ""; + } + @Override public String getFilePath() { return Objects.requireNonNull(getTaskOption(TaskOption.class).getSavePathUri()).toString(); } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/task/TaskCachePool.kt b/PublicComponent/src/main/java/com/arialyy/aria/core/task/TaskCachePool.kt index cfdcdc07..97a7a613 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/task/TaskCachePool.kt +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/task/TaskCachePool.kt @@ -18,7 +18,6 @@ package com.arialyy.aria.core.task import android.net.Uri import com.arialyy.aria.core.inf.BaseEntity import com.arialyy.aria.core.inf.IEntity -import com.arialyy.aria.core.inf.ITaskAdapter import timber.log.Timber import java.util.concurrent.ConcurrentHashMap @@ -32,29 +31,38 @@ object TaskCachePool { * key: taskId */ private val entityMap = ConcurrentHashMap() - private val taskAdapterMap = ConcurrentHashMap() /** - * task cache map; key: url + * task cache map; key: if task is [DownloadGroupTask], it's filePath else it's service url */ private val taskMap = ConcurrentHashMap() - fun removeTask(url: String) { - taskMap.remove(url) + /** + * @param key if task is [DownloadGroupTask], it's filePath else it's service url + */ + fun removeTask(key: String) { + taskMap.remove(key) } /** * if task is completed, stopped, canceled, return null + * @param key if task is [DownloadGroupTask], it's filePath else it's service url */ - fun getTaskByUrl(url: String) = taskMap[url] + fun getTaskByKey(key: String) = taskMap[key] fun getTaskById(taskId: Int): ITask? { return taskMap.values.find { it.taskId == taskId } } fun putTask(task: ITask) { - taskMap[task.url] = task - taskAdapterMap[Uri.parse(task.filePath)] = task.adapter + when (task) { + is DownloadTask -> { + taskMap[task.url] = task + } + is DownloadGroupTask -> { + taskMap[task.filePath] = task + } + } } /** @@ -69,21 +77,6 @@ object TaskCachePool { return null } -// /** -// * @param filePath task unique identifier, like: savePath, sourceUrl -// */ -// fun putTaskUtil(filePath: Uri, taskUtil: ITaskAdapter) { -// taskAdapterMap[filePath] = taskUtil -// taskUtil.stop() -// } - - /** - * @param filePath unique identifier, like: savePath, sourceUrl - */ - fun getTaskAdapter(filePath: Uri): ITaskAdapter? { - return taskAdapterMap[filePath] - } - fun putEntity(taskId: Int, entity: BaseEntity) { if (taskId <= 0) { Timber.e("invalid taskId: $taskId") diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/task/TaskResp.kt b/PublicComponent/src/main/java/com/arialyy/aria/core/task/TaskResp.kt index 8dfb69df..37dbada5 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/task/TaskResp.kt +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/task/TaskResp.kt @@ -10,9 +10,6 @@ class TaskResp(val code: Int = CODE_DEF) { const val CODE_SUCCESS = 1 const val CODE_INTERRUPT = 999 const val CODE_DEF = 0 - const val CODE_SAVE_URI_NULL = 3 - const val CODE_GET_FILE_INFO_FAIL = 2 - const val CODE_BLOCK_QUEUE_NULL = 4 } var fileSize: Long = 0 diff --git a/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/DEntityDao.kt b/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/DEntityDao.kt index 29404438..b2691f24 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/DEntityDao.kt +++ b/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/DEntityDao.kt @@ -33,16 +33,16 @@ interface DEntityDao { @Transaction @Query("SELECT * FROM DEntity") - suspend fun getDEntityList(): List + suspend fun queryDEntityList(): List @Query("SELECT * FROM DEntity WHERE :savePath=savePath") - suspend fun getDEntityBySavePath(savePath: String): DEntity? + suspend fun queryDEntityBySavePath(savePath: String): DEntity? @Query("SELECT * FROM DEntity WHERE :dId=dId") - suspend fun getDEntityById(did: String): DEntity? + suspend fun queryDEntityById(did: String): DEntity? @Query("SELECT * FROM DEntity WHERE :sourceUrl=sourceUrl") - suspend fun getDEntityBySource(sourceUrl: String): DEntity? + suspend fun queryDEntityBySource(sourceUrl: String): DEntity? @Insert suspend fun insert(dEntity: DEntity) diff --git a/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/DGEntityDao.kt b/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/DGEntityDao.kt index b727f998..3a14541f 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/DGEntityDao.kt +++ b/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/DGEntityDao.kt @@ -35,19 +35,19 @@ interface DGEntityDao { @Transaction @Query("SELECT * FROM DGEntity") - suspend fun getDGEntityList(): List + suspend fun queryDGEntityList(): List @Transaction @Query("SELECT * FROM DGEntity WHERE :path=savePath") - suspend fun getDGEntityByPath(path: String): DGSubRelation? + suspend fun queryDGEntityByPath(path: String): DGSubRelation? @Transaction @Query("SELECT * FROM DGEntity WHERE :gid=gid") - suspend fun getDGEntityByGid(gid: Int): DGSubRelation + suspend fun queryDGEntityByGid(gid: Int): DGSubRelation @Transaction @Query("SELECT * FROM DGEntity WHERE :gid=gid") - suspend fun getDGList(): List + suspend fun queryDGList(): List @Insert suspend fun insertSubList(subList: List) diff --git a/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/MEntityDao.kt b/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/MEntityDao.kt index bb29b31a..ec9ea03c 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/MEntityDao.kt +++ b/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/MEntityDao.kt @@ -32,7 +32,7 @@ import com.arialyy.aria.orm.entity.MKeyInfo interface MEntityDao { @Query("SELECT * FROM MEntity WHERE :savePath=savePath") - suspend fun getMEntityByPath(savePath: String): MEntity + suspend fun queryMEntityByPath(savePath: String): MEntity @Update suspend fun update(entity: MEntity) diff --git a/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/RecordDao.kt b/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/RecordDao.kt index 834fe58d..4078f2f2 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/RecordDao.kt +++ b/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/RecordDao.kt @@ -35,7 +35,7 @@ interface RecordDao { @Transaction @Query("SELECT * FROM TaskRecord WHERE :key=taskKey") - suspend fun getTaskRecordByKey(key: String): RecordRelation? + suspend fun queryTaskRecordByKey(key: String): RecordRelation? @Insert @Deprecated( diff --git a/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/UEntityDao.kt b/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/UEntityDao.kt index 80a26e6d..7c5a020f 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/UEntityDao.kt +++ b/PublicComponent/src/main/java/com/arialyy/aria/orm/dao/UEntityDao.kt @@ -33,13 +33,13 @@ interface UEntityDao { @Transaction @Query("SELECT * FROM DEntity") - suspend fun getUEntityList(): List + suspend fun queryUEntityList(): List @Query("SELECT * FROM DEntity WHERE :uId=uId") - suspend fun getUEntityById(uId: String): UEntity + suspend fun queryUEntityById(uId: String): UEntity @Query("SELECT * FROM UEntity WHERE :filePath=filePath") - suspend fun getUEntityBySource(filePath: String): UEntity + suspend fun queryUEntityBySource(filePath: String): UEntity @Insert suspend fun insert(uEntity: UEntity) diff --git a/PublicComponent/src/main/java/com/arialyy/aria/orm/entity/DEntity.kt b/PublicComponent/src/main/java/com/arialyy/aria/orm/entity/DEntity.kt index 8b0b51e7..27f081b8 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/orm/entity/DEntity.kt +++ b/PublicComponent/src/main/java/com/arialyy/aria/orm/entity/DEntity.kt @@ -22,9 +22,11 @@ import androidx.room.PrimaryKey import androidx.room.TypeConverters import com.arialyy.aria.core.DuaContext import com.arialyy.aria.core.inf.BaseEntity +import com.arialyy.aria.util.FileUri import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize +import java.io.File /** * Download Entity @@ -44,11 +46,22 @@ data class DEntity( /** * file save path, it's uri + * eg: /mnt/Sdcard/Download/ */ - val savePath: Uri, + private val savePath: Uri, + + var fileName: String = "", val isSub: Boolean = false ) : BaseEntity() { + private var dirFile: File? = null + + fun getFilePath(): String { + if (dirFile == null) { + dirFile = File(FileUri.getPathByUri(savePath)!!) + } + return File(dirFile, fileName).path + } override fun update() { updateTime = System.currentTimeMillis() diff --git a/PublicComponent/src/main/java/com/arialyy/aria/util/DuaUtil.kt b/PublicComponent/src/main/java/com/arialyy/aria/util/DuaUtil.kt new file mode 100644 index 00000000..71af1a30 --- /dev/null +++ b/PublicComponent/src/main/java/com/arialyy/aria/util/DuaUtil.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.arialyy.aria.util + +import java.security.MessageDigest + +/** + * @Author laoyuyu + * @Description + * @Date 21:38 2023/3/11 + **/ +object DuaUtil { + fun getMD5Hash(str: String): String { + val md = MessageDigest.getInstance("MD5") + val messageDigest = md.digest(str.toByteArray()) + val no = messageDigest.toBigInteger() // 使用 Kotlin 扩展函数将字节数组转换为 BigInteger + var hashText = no.toString(16) + while (hashText.length < 32) { + hashText = "0$hashText" + } + return hashText + } + +} diff --git a/PublicComponent/src/main/java/com/arialyy/aria/util/Ext.kt b/PublicComponent/src/main/java/com/arialyy/aria/util/Ext.kt index 57d32357..8e8f0925 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/util/Ext.kt +++ b/PublicComponent/src/main/java/com/arialyy/aria/util/Ext.kt @@ -20,9 +20,14 @@ import android.content.pm.PackageManager import android.net.Uri import com.arialyy.aria.core.DuaContext import timber.log.Timber +import java.math.BigInteger internal const val AUTHORITY = ".andoFileProvider" +fun ByteArray.toBigInteger(): BigInteger { + return BigInteger(1, this) +} + /** * @return 传入的Uri是否已具备访问权限 (Whether the incoming Uri has access permission) */ diff --git a/PublicComponent/src/main/java/com/arialyy/aria/util/FileUtils.kt b/PublicComponent/src/main/java/com/arialyy/aria/util/FileUtils.kt index 33bb924e..bf02dcb8 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/util/FileUtils.kt +++ b/PublicComponent/src/main/java/com/arialyy/aria/util/FileUtils.kt @@ -34,6 +34,28 @@ object FileUtils { RegexOption.IGNORE_CASE ) + /** + * Check if uri is a folder + * @return true it's folder + */ + fun uriIsDir(uri: Uri): Boolean { + val path = FileUri.getPathByUri(uri) + if (path.isNullOrBlank()) { + throw IllegalArgumentException("invalid uri: ${uri}") + } + return File(path).isDirectory + } + + /** + * get file name from url + */ + fun getFileNameFromUrl(url: String?): String? { + if (url == null) return null + val fn = getFileNameFromPath(url) ?: return null + if (!fn.contains(".")) return null + return fn + } + /** * 创建文件 当文件不存在的时候就创建一个文件。 如果文件存在,先删除原文件,然后重新创建一个新文件 *