From e80f2904e1091b1cb2e735ba3c3059bdc42621b9 Mon Sep 17 00:00:00 2001 From: laoyuyu <511455842@qq.com> Date: Sun, 19 Feb 2023 21:24:57 +0800 Subject: [PATCH] Perfect the stop controller for http download --- .../com/arialyy/aria/http/ConnectionHelp.java | 20 - ...ntroller.kt => HttpBaseStartController.kt} | 4 +- .../com/arialyy/aria/http/HttpComponent.kt | 6 - .../java/com/arialyy/aria/http/HttpUtil.kt | 14 + .../download/HttpBlockThreadInterceptor.kt | 2 +- ...pDTTaskAdapter.kt => HttpDBTaskAdapter.kt} | 5 +- .../http/download/HttpDBlockInterceptor.kt | 4 +- .../aria/http/download/HttpDCTTaskAdapter.kt | 3 +- .../aria/http/download/HttpDEventListener.kt | 2 + .../aria/http/download/HttpDFileInfoTask.java | 434 ------------------ .../aria/http/download/HttpDLoaderUtil.java | 51 -- ...roller.kt => HttpDStartStartController.kt} | 19 +- .../aria/http/download/HttpDStopController.kt | 47 ++ .../http/download/HttpDStopController2.kt | 65 +++ .../http/download/HttpDTTBuilderAdapter.java | 61 --- .../aria/http/download/HttpDownloader.kt | 26 +- .../com/arialyy/aria/core/inf/IEntity.java | 3 +- .../arialyy/aria/core/inf/IStopController.kt | 46 ++ .../aria/core/listener/AbsEventListener.java | 5 +- .../com/arialyy/aria/core/task/AbsTask.java | 4 +- .../arialyy/aria/core/task/DownloadTask.java | 2 +- .../com/arialyy/aria/core/task/ITask.java | 9 +- .../arialyy/aria/core/task/TaskCachePool.kt | 36 +- .../com/arialyy/aria/orm/entity/DEntity.kt | 37 ++ .../com/arialyy/aria/queue/AbsTaskQueue.java | 16 +- .../aria/schedulers/TaskSchedulers.java | 68 +-- 26 files changed, 319 insertions(+), 670 deletions(-) rename Http/src/main/java/com/arialyy/aria/http/{HttpBaseController.kt => HttpBaseStartController.kt} (87%) rename Http/src/main/java/com/arialyy/aria/http/download/{HttpDTTaskAdapter.kt => HttpDBTaskAdapter.kt} (94%) delete mode 100644 Http/src/main/java/com/arialyy/aria/http/download/HttpDFileInfoTask.java delete mode 100644 Http/src/main/java/com/arialyy/aria/http/download/HttpDLoaderUtil.java rename Http/src/main/java/com/arialyy/aria/http/download/{HttpDStartController.kt => HttpDStartStartController.kt} (88%) create mode 100644 Http/src/main/java/com/arialyy/aria/http/download/HttpDStopController.kt create mode 100644 Http/src/main/java/com/arialyy/aria/http/download/HttpDStopController2.kt delete mode 100644 Http/src/main/java/com/arialyy/aria/http/download/HttpDTTBuilderAdapter.java create mode 100644 PublicComponent/src/main/java/com/arialyy/aria/core/inf/IStopController.kt diff --git a/Http/src/main/java/com/arialyy/aria/http/ConnectionHelp.java b/Http/src/main/java/com/arialyy/aria/http/ConnectionHelp.java index dd3da4b4..81b7f8ee 100644 --- a/Http/src/main/java/com/arialyy/aria/http/ConnectionHelp.java +++ b/Http/src/main/java/com/arialyy/aria/http/ConnectionHelp.java @@ -77,26 +77,6 @@ public final class ConnectionHelp { } } - /** - * 转换HttpUrlConnect的inputStream流 - * - * @return {@link GZIPInputStream}、{@link InflaterInputStream} - * @throws IOException - */ - public static InputStream convertInputStream(HttpURLConnection connection) throws IOException { - String encoding = connection.getHeaderField("Content-Encoding"); - if (TextUtils.isEmpty(encoding)) { - return connection.getInputStream(); - } - if (encoding.contains("gzip")) { - return new GZIPInputStream(connection.getInputStream()); - } else if (encoding.contains("deflate")) { - return new InflaterInputStream(connection.getInputStream()); - } else { - return connection.getInputStream(); - } - } - /** * 处理链接 * diff --git a/Http/src/main/java/com/arialyy/aria/http/HttpBaseController.kt b/Http/src/main/java/com/arialyy/aria/http/HttpBaseStartController.kt similarity index 87% rename from Http/src/main/java/com/arialyy/aria/http/HttpBaseController.kt rename to Http/src/main/java/com/arialyy/aria/http/HttpBaseStartController.kt index f087f06b..f36ed5bf 100644 --- a/Http/src/main/java/com/arialyy/aria/http/HttpBaseController.kt +++ b/Http/src/main/java/com/arialyy/aria/http/HttpBaseStartController.kt @@ -15,13 +15,11 @@ */ package com.arialyy.aria.http -import com.arialyy.aria.http.download.HttpDownloader - /** * @Author laoyuyu * @Description * @Date 12:40 PM 2023/1/22 **/ -open class HttpBaseController(val target: Any) { +open class HttpBaseStartController(val target: Any) { } \ No newline at end of file diff --git a/Http/src/main/java/com/arialyy/aria/http/HttpComponent.kt b/Http/src/main/java/com/arialyy/aria/http/HttpComponent.kt index 69939fed..9f49cd6c 100644 --- a/Http/src/main/java/com/arialyy/aria/http/HttpComponent.kt +++ b/Http/src/main/java/com/arialyy/aria/http/HttpComponent.kt @@ -1,10 +1,7 @@ package com.arialyy.aria.http import android.content.Context -import com.arialyy.aria.core.DuaContext import com.arialyy.aria.core.inf.IComponentInit -import com.arialyy.aria.queue.DTaskQueue -import com.arialyy.aria.queue.UTaskQueue /** * @Author laoyuyu @@ -13,8 +10,5 @@ import com.arialyy.aria.queue.UTaskQueue **/ class HttpComponent : IComponentInit { override fun init(context: Context) { - DuaContext.getServiceManager().registerService(DuaContext.D_QUEUE, com.arialyy.aria.queue.DTaskQueue.getInstance()) - DuaContext.getServiceManager().registerService(DuaContext.U_QUEUE, com.arialyy.aria.queue.UTaskQueue.getInstance()) - } } \ No newline at end of file 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 5b63679e..f48d015c 100644 --- a/Http/src/main/java/com/arialyy/aria/http/HttpUtil.kt +++ b/Http/src/main/java/com/arialyy/aria/http/HttpUtil.kt @@ -15,8 +15,12 @@ */ package com.arialyy.aria.http +import android.net.Uri import android.text.TextUtils +import com.arialyy.aria.core.inf.ITaskUtil +import com.arialyy.aria.core.task.TaskCachePool import com.arialyy.aria.http.download.HttpDTaskOption +import com.arialyy.aria.http.download.HttpDTaskUtil import com.arialyy.aria.util.FileUtils import com.arialyy.aria.util.Regular import timber.log.Timber @@ -33,6 +37,16 @@ import java.util.zip.InflaterInputStream * @Date 12:40 PM 2023/1/22 **/ internal object HttpUtil { + + fun getDTaskUtil(filePath: Uri): ITaskUtil { + var util = TaskCachePool.getTaskUtil(filePath) + if (util == null) { + util = HttpDTaskUtil() + TaskCachePool.putTaskUtil(filePath, util) + } + return util + } + /** * 拦截window.location.replace数据 * 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 ef821e19..0da2c718 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 @@ -48,7 +48,7 @@ class HttpBlockThreadInterceptor : ITaskInterceptor { val threadConfig = ThreadConfig(it, option, DuaContext.getDConfig().maxSpeed) threadTaskList.add( ThreadTask2( - adapter = if (option.isChunkTask) HttpDCTTaskAdapter(threadConfig) else HttpDThreadTaskAdapter( + adapter = if (option.isChunkTask) HttpDCTTaskAdapter(threadConfig) else HttpDBTaskAdapter( threadConfig ), handler = chain.blockManager.handler, diff --git a/Http/src/main/java/com/arialyy/aria/http/download/HttpDTTaskAdapter.kt b/Http/src/main/java/com/arialyy/aria/http/download/HttpDBTaskAdapter.kt similarity index 94% rename from Http/src/main/java/com/arialyy/aria/http/download/HttpDTTaskAdapter.kt rename to Http/src/main/java/com/arialyy/aria/http/download/HttpDBTaskAdapter.kt index 8b2f4422..29d221df 100644 --- a/Http/src/main/java/com/arialyy/aria/http/download/HttpDTTaskAdapter.kt +++ b/Http/src/main/java/com/arialyy/aria/http/download/HttpDBTaskAdapter.kt @@ -18,6 +18,7 @@ package com.arialyy.aria.http.download import com.arialyy.aria.core.task.AbsThreadTaskAdapter import com.arialyy.aria.core.task.ThreadConfig import com.arialyy.aria.http.ConnectionHelp +import com.arialyy.aria.http.HttpUtil import com.arialyy.aria.http.request.IRequest.Companion.getRequest import timber.log.Timber import java.io.BufferedInputStream @@ -32,7 +33,7 @@ import java.nio.channels.Channels * @Description * @Date 23:07 PM 2023/2/8 **/ -class HttpDTTaskAdapter(threadConfig: ThreadConfig) : AbsThreadTaskAdapter(threadConfig) { +class HttpDBTaskAdapter(threadConfig: ThreadConfig) : AbsThreadTaskAdapter(threadConfig) { private fun getTaskOption(): HttpDTaskOption { return threadConfig.option as HttpDTaskOption @@ -54,7 +55,7 @@ class HttpDTTaskAdapter(threadConfig: ThreadConfig) : AbsThreadTaskAdapter(threa } conn.connect() - BufferedInputStream(ConnectionHelp.convertInputStream(conn)).use { + BufferedInputStream(HttpUtil.convertInputStream(conn)).use { readBytes(it) } } 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 469e8294..9bb98982 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 @@ -92,13 +92,13 @@ internal class HttpDBlockInterceptor : ITaskInterceptor { */ private suspend fun checkRecord(): Int { val recordDao = DuaContext.getServiceManager().getDbService().getDuaDb().getRecordDao() - val recordWrapper = recordDao.getTaskRecordByKey(task.taskKey) + val recordWrapper = recordDao.getTaskRecordByKey(task.filePath) if (recordWrapper == null) { Timber.i("record not found, create record") val blockNumInfo = BlockUtil.getBlockNum(task.taskState.fileSize) val taskRecord = TaskRecord( - taskKey = task.taskKey, + taskKey = task.filePath, filePath = option.savePathUri!!, taskType = ITask.DOWNLOAD, fileLen = task.taskState.fileSize, diff --git a/Http/src/main/java/com/arialyy/aria/http/download/HttpDCTTaskAdapter.kt b/Http/src/main/java/com/arialyy/aria/http/download/HttpDCTTaskAdapter.kt index 78b1d5b5..b50e07e8 100644 --- a/Http/src/main/java/com/arialyy/aria/http/download/HttpDCTTaskAdapter.kt +++ b/Http/src/main/java/com/arialyy/aria/http/download/HttpDCTTaskAdapter.kt @@ -18,6 +18,7 @@ package com.arialyy.aria.http.download import com.arialyy.aria.core.task.AbsThreadTaskAdapter import com.arialyy.aria.core.task.ThreadConfig import com.arialyy.aria.http.ConnectionHelp +import com.arialyy.aria.http.HttpUtil import com.arialyy.aria.http.request.IRequest.Companion.getRequest import java.io.BufferedInputStream import java.io.FileOutputStream @@ -45,7 +46,7 @@ class HttpDCTTaskAdapter(threadConfig: ThreadConfig) : AbsThreadTaskAdapter(thre conn.setChunkedStreamingMode(0) conn.connect() - BufferedInputStream(ConnectionHelp.convertInputStream(conn)).use { + BufferedInputStream(HttpUtil.convertInputStream(conn)).use { readBytes(it) } } diff --git a/Http/src/main/java/com/arialyy/aria/http/download/HttpDEventListener.kt b/Http/src/main/java/com/arialyy/aria/http/download/HttpDEventListener.kt index d3c20d8c..e44cb4bc 100644 --- a/Http/src/main/java/com/arialyy/aria/http/download/HttpDEventListener.kt +++ b/Http/src/main/java/com/arialyy/aria/http/download/HttpDEventListener.kt @@ -16,6 +16,7 @@ package com.arialyy.aria.http.download import com.arialyy.aria.core.DuaContext +import com.arialyy.aria.core.inf.IEntity import com.arialyy.aria.core.listener.AbsEventListener import com.arialyy.aria.core.listener.ISchedulers import com.arialyy.aria.core.task.DownloadTask @@ -45,6 +46,7 @@ class HttpDEventListener(task: DownloadTask) : AbsEventListener(task) { } handleSpeed(0) sendInState2Target(ISchedulers.COMPLETE) + saveData(IEntity.STATE_COMPLETE, task.taskState.fileSize) } /** diff --git a/Http/src/main/java/com/arialyy/aria/http/download/HttpDFileInfoTask.java b/Http/src/main/java/com/arialyy/aria/http/download/HttpDFileInfoTask.java deleted file mode 100644 index 2f166f99..00000000 --- a/Http/src/main/java/com/arialyy/aria/http/download/HttpDFileInfoTask.java +++ /dev/null @@ -1,434 +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.aria.http.download; - -import android.net.TrafficStats; -import android.net.Uri; -import android.os.Process; -import android.text.TextUtils; -import com.arialyy.aria.core.AriaConfig; -import com.arialyy.aria.core.common.CompleteInfo; -import com.arialyy.aria.core.common.RequestEnum; -import com.arialyy.aria.core.download.DTaskWrapper; -import com.arialyy.aria.core.download.DownloadEntity; -import com.arialyy.aria.core.loader.IInfoTask; -import com.arialyy.aria.core.loader.ILoaderVisitor; -import com.arialyy.aria.core.processor.IHttpFileLenAdapter; -import com.arialyy.aria.exception.AriaHTTPException; -import com.arialyy.aria.http.ConnectionHelp; -import com.arialyy.aria.http.HttpTaskOption; -import com.arialyy.aria.util.ALog; -import com.arialyy.aria.util.FileUtils; -import com.arialyy.aria.util.CommonUtil; -import com.arialyy.aria.util.FileUtil; -import com.arialyy.aria.util.RecordUtil; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.UnsupportedEncodingException; -import java.net.CookieManager; -import java.net.HttpCookie; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -/** - * 下载文件信息获取 - */ -final class HttpDFileInfoTask implements IInfoTask, Runnable { - private static final String TAG = "HttpDFileInfoTask"; - private DownloadEntity mEntity; - private DTaskWrapper mTaskWrapper; - private int mConnectTimeOut; - private Callback callback; - private HttpTaskOption taskOption; - private boolean isStop = false, isCancel = false; - - HttpDFileInfoTask(DTaskWrapper taskWrapper) { - this.mTaskWrapper = taskWrapper; - mEntity = taskWrapper.getEntity(); - mConnectTimeOut = AriaConfig.getInstance().getDConfig().getConnectTimeOut(); - taskOption = (HttpTaskOption) taskWrapper.getTaskOption(); - } - - @Override public void run() { - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - TrafficStats.setThreadStatsTag(UUID.randomUUID().toString().hashCode()); - HttpURLConnection conn = null; - try { - URL url = ConnectionHelp.handleUrl(mEntity.getUrl(), taskOption); - conn = ConnectionHelp.handleConnection(url, taskOption); - ConnectionHelp.setConnectParam(taskOption, conn); - conn.setRequestProperty("Range", "bytes=" + 0 + "-"); - if (AriaConfig.getInstance().getDConfig().isUseHeadRequest()) { - ALog.d(TAG, "head请求"); - conn.setRequestMethod("HEAD"); - } - conn.setConnectTimeout(mConnectTimeOut); - conn.connect(); - handleConnect(conn); - } catch (IOException e) { - failDownload(new AriaHTTPException( - String.format("下载失败,filePath: %s, url: %s", mEntity.getFilePath(), mEntity.getUrl()), - e), true); - } finally { - if (conn != null) { - try { - InputStream is = conn.getInputStream(); - if (is != null) { - is.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - conn.disconnect(); - } - } - } - - @Override public void setCallback(Callback callback) { - this.callback = callback; - } - - @Override public void stop() { - isStop = true; - } - - @Override public void cancel() { - isCancel = true; - } - - private void handleConnect(HttpURLConnection conn) throws IOException { - if (taskOption.getRequestEnum() == RequestEnum.POST) { - Map params = taskOption.getParams(); - if (params != null) { - OutputStreamWriter dos = new OutputStreamWriter(conn.getOutputStream()); - Set keys = params.keySet(); - StringBuilder sb = new StringBuilder(); - for (String key : keys) { - sb.append(key).append("=").append(URLEncoder.encode(params.get(key))).append("&"); - } - String url = sb.toString(); - url = url.substring(0, url.length() - 1); - dos.write(url); - dos.flush(); - dos.close(); - } - } - - IHttpFileLenAdapter lenAdapter = taskOption.getFileLenAdapter(); - if (lenAdapter == null) { - lenAdapter = new FileLenAdapter(); - } else { - ALog.d(TAG, "使用自定义adapter"); - } - long len = lenAdapter.handleFileLen(conn.getHeaderFields()); - - if (!FileUtil.checkMemorySpace(mEntity.getFilePath(), len)) { - failDownload(new AriaHTTPException( - String.format("下载失败,内存空间不足;filePath: %s, url: %s", mEntity.getFilePath(), - mEntity.getUrl())), false); - return; - } - - int code = conn.getResponseCode(); - boolean end = false; - if (TextUtils.isEmpty(mEntity.getMd5Code())) { - String md5Code = conn.getHeaderField("Content-MD5"); - mEntity.setMd5Code(md5Code); - } - - boolean isChunked = false; - final String str = conn.getHeaderField("Transfer-Encoding"); - if (!TextUtils.isEmpty(str) && str.equals("chunked")) { - isChunked = true; - } - Map> headers = conn.getHeaderFields(); - String disposition = conn.getHeaderField("Content-Disposition"); - - if (taskOption.isUseServerFileName()) { - if (!TextUtils.isEmpty(disposition)) { - mEntity.setDisposition(CommonUtil.encryptBASE64(disposition)); - handleContentDisposition(disposition); - } else { - if (taskOption.getFileNameAdapter() != null) { - String newName = - taskOption.getFileNameAdapter().handleFileName(headers, mEntity.getKey()); - mEntity.setServerFileName(newName); - renameFile(newName); - } - } - } - - CookieManager msCookieManager = new CookieManager(); - List cookiesHeader = headers.get("Set-Cookie"); - - if (cookiesHeader != null) { - for (String cookie : cookiesHeader) { - msCookieManager.getCookieStore().add(null, HttpCookie.parse(cookie).get(0)); - } - taskOption.setCookieManager(msCookieManager); - } - - mTaskWrapper.setCode(code); - if (code == HttpURLConnection.HTTP_PARTIAL) { - if (!checkLen(len) && !isChunked) { - if (len < 0) { - failDownload( - new AriaHTTPException(String.format("任务下载失败,文件长度小于0, url: %s", mEntity.getUrl())), - false); - } - return; - } - mEntity.setFileSize(len); - mTaskWrapper.setSupportBP(true); - end = true; - } else if (code == HttpURLConnection.HTTP_OK) { - String contentType = conn.getHeaderField("Content-Type"); - if (TextUtils.isEmpty(contentType)) { - if (!checkLen(len) && !isChunked) { - if (len < 0) { - failDownload( - new AriaHTTPException(String.format("任务下载失败,文件长度小于0, url: %s", mEntity.getUrl())), - false); - } - return; - } - mEntity.setFileSize(len); - mTaskWrapper.setSupportBP(true); - doNext(code, isChunked); - return; - } - if (contentType.equals("text/html")) { - BufferedReader reader = - new BufferedReader(new InputStreamReader(ConnectionHelp.convertInputStream(conn))); - StringBuilder sb = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - sb.append(line); - } - reader.close(); - handleUrlReTurn(conn, CommonUtil.getWindowReplaceUrl(sb.toString())); - return; - } else if (!checkLen(len) && !isChunked) { - if (len < 0) { - failDownload( - new AriaHTTPException( - String.format("任务下载失败,文件长度小于0, url: %s", mEntity.getUrl())), - false); - } - ALog.d(TAG, "len < 0"); - return; - } - mEntity.setFileSize(len); - mTaskWrapper.setNewTask(true); - mTaskWrapper.setSupportBP(false); - end = true; - } else if (code == HttpURLConnection.HTTP_MOVED_TEMP - || code == HttpURLConnection.HTTP_MOVED_PERM - || code == HttpURLConnection.HTTP_SEE_OTHER - || code == HttpURLConnection.HTTP_CREATED // 201 跳转 - || code == 307) { - handleUrlReTurn(conn, conn.getHeaderField("Location")); - } else if (code == 416) { // 处理0k长度的文件的情况 - ALog.w(TAG, "文件长度为0,不支持断点"); - mTaskWrapper.setSupportBP(false); - mTaskWrapper.setNewTask(true); - end = true; - } else if (code >= HttpURLConnection.HTTP_BAD_REQUEST) { - failDownload(new AriaHTTPException( - String.format("任务下载失败,errorCode:%s, url: %s", code, mEntity.getUrl())), false); - } else { - failDownload(new AriaHTTPException( - String.format("任务下载失败,errorCode:%s, errorMsg: %s, url: %s", code, - conn.getResponseMessage(), mEntity.getUrl())), !FileUtils.httpIsBadRequest(code)); - } - if (end) { - doNext(code, isChunked); - } - } - - private void doNext(int code, boolean isChunked) { - if (isStop || isCancel) { - return; - } - taskOption.setChunked(isChunked); - CompleteInfo info = new CompleteInfo(code, mTaskWrapper); - callback.onSucceed(mEntity.getUrl(), info); - mEntity.update(); - } - - /** - * 处理"Content-Disposition"参数 - * Content-Disposition - * - * @throws UnsupportedEncodingException - */ - private void handleContentDisposition(String disposition) throws UnsupportedEncodingException { - if (disposition.contains(";")) { - String[] infos = disposition.split(";"); - if (infos[0].equals("attachment")) { - for (String info : infos) { - if (info.startsWith("filename") && info.contains("=")) { - String[] temp = info.split("="); - if (temp.length > 1) { - String newName = URLDecoder.decode(temp[1], "utf-8").replaceAll("\"", ""); - mEntity.setServerFileName(newName); - renameFile(newName); - break; - } - } - } - } else if (infos[0].equals("form-data") && infos.length > 2) { - String[] temp = infos[2].split("="); - if (temp.length > 1) { - String newName = URLDecoder.decode(temp[1], "utf-8").replaceAll("\"", ""); - mEntity.setServerFileName(newName); - renameFile(newName); - } - } else { - ALog.w(TAG, "不识别的Content-Disposition参数"); - } - } - } - - /** - * 重命名文件 - */ - private void renameFile(String newName) { - if (TextUtils.isEmpty(newName)) { - ALog.w(TAG, "重命名失败【服务器返回的文件名为空】"); - return; - } - ALog.d(TAG, String.format("文件重命名为:%s", newName)); - File oldFile = new File(mEntity.getFilePath()); - String newPath = oldFile.getParent() + "/" + newName; - if (!FileUtils.checkDPathConflicts(false, newPath, mTaskWrapper.getRequestType())) { - ALog.e(TAG, "文件重命名失败"); - return; - } - if (oldFile.exists()) { - boolean b = oldFile.renameTo(new File(newPath)); - ALog.d(TAG, String.format("文件重命名%s", b ? "成功" : "失败")); - } - mEntity.setFileName(newName); - mEntity.setFilePath(newPath); - RecordUtil.modifyTaskRecord(oldFile.getPath(), newPath, mEntity.getTaskType()); - } - - /** - * 处理30x跳转 - */ - private void handleUrlReTurn(HttpURLConnection conn, String newUrl) throws IOException { - ALog.d(TAG, "30x跳转,新url为【" + newUrl + "】"); - if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null")) { - if (callback != null) { - callback.onFail(mEntity, new AriaHTTPException("获取重定向链接失败"), false); - } - return; - } - if (newUrl.startsWith("/")) { - Uri uri = Uri.parse(mEntity.getUrl()); - newUrl = uri.getHost() + newUrl; - } - - if (!FileUtils.checkUrl(newUrl)) { - failDownload(new AriaHTTPException("下载失败,重定向url错误"), false); - return; - } - taskOption.setRedirectUrl(newUrl); - mEntity.setRedirect(true); - mEntity.setRedirectUrl(newUrl); - String cookies = conn.getHeaderField("Set-Cookie"); - conn.disconnect(); - URL url = ConnectionHelp.handleUrl(newUrl, taskOption); - conn = ConnectionHelp.handleConnection(url, taskOption); - ConnectionHelp.setConnectParam(taskOption, conn); - conn.setRequestProperty("Cookie", cookies); - conn.setRequestProperty("Range", "bytes=" + 0 + "-"); - if (AriaConfig.getInstance().getDConfig().isUseHeadRequest()) { - conn.setRequestMethod("HEAD"); - } - conn.setConnectTimeout(mConnectTimeOut); - conn.connect(); - handleConnect(conn); - conn.disconnect(); - } - - /** - * 检查长度是否合法,并且检查新获取的文件长度是否和数据库的文件长度一直,如果不一致,则表示该任务为新任务 - * - * @param len 从服务器获取的文件长度 - * @return {@code true}合法 - */ - private boolean checkLen(long len) { - if (len != mEntity.getFileSize()) { - ALog.d(TAG, "长度不一致,任务为新任务"); - mTaskWrapper.setNewTask(true); - } - return true; - } - - private void failDownload(AriaHTTPException e, boolean needRetry) { - if (isStop || isCancel) { - return; - } - if (callback != null) { - callback.onFail(mEntity, e, needRetry); - } - } - - @Override public void accept(ILoaderVisitor visitor) { - visitor.addComponent(this); - } - - private static class FileLenAdapter implements IHttpFileLenAdapter { - - @Override public long handleFileLen(Map> headers) { - if (headers == null || headers.isEmpty()) { - ALog.e(TAG, "header为空,获取文件长度失败"); - return -1; - } - List sLength = headers.get("Content-Length"); - if (sLength == null || sLength.isEmpty()) { - return -1; - } - String temp = sLength.get(0); - long len = TextUtils.isEmpty(temp) ? -1 : Long.parseLong(temp); - // 某些服务,如果设置了conn.setRequestProperty("Range", "bytes=" + 0 + "-"); - // 会返回 Content-Range: bytes 0-225427911/225427913 - if (len < 0) { - List sRange = headers.get("Content-Range"); - if (sRange == null || sRange.isEmpty()) { - len = -1; - } else { - int start = temp.indexOf("/"); - len = Long.parseLong(temp.substring(start + 1)); - } - } - - return len; - } - } -} \ No newline at end of file diff --git a/Http/src/main/java/com/arialyy/aria/http/download/HttpDLoaderUtil.java b/Http/src/main/java/com/arialyy/aria/http/download/HttpDLoaderUtil.java deleted file mode 100644 index 1281eb52..00000000 --- a/Http/src/main/java/com/arialyy/aria/http/download/HttpDLoaderUtil.java +++ /dev/null @@ -1,51 +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.aria.http.download; - -import com.arialyy.aria.core.download.DTaskWrapper; -import com.arialyy.aria.core.loader.AbsNormalLoader; -import com.arialyy.aria.core.loader.AbsNormalLoaderUtil; -import com.arialyy.aria.core.loader.LoaderStructure; -import com.arialyy.aria.core.loader.NormalLoader; -import com.arialyy.aria.core.loader.NormalTTBuilder; -import com.arialyy.aria.core.loader.TaskThreadStateManager; -import com.arialyy.aria.http.HttpRecordHandler; -import com.arialyy.aria.http.HttpTaskOption; - -/** - * @author lyy - * Date: 2019-09-21 - */ -public final class HttpDLoaderUtil extends AbsNormalLoaderUtil { - - @Override public AbsNormalLoader getLoader() { - if (mLoader == null){ - getTaskWrapper().generateTaskOption(HttpTaskOption.class); - mLoader = new NormalLoader(getTaskWrapper(), getListener()); - } - return mLoader; - } - - public LoaderStructure BuildLoaderStructure() { - LoaderStructure structure = new LoaderStructure(); - structure.addComponent(new HttpRecordHandler(getTaskWrapper())) - .addComponent(new TaskThreadStateManager(getListener())) - .addComponent(new HttpDFileInfoTask((DTaskWrapper) getTaskWrapper())) - .addComponent(new NormalTTBuilder(getTaskWrapper(), new HttpDTTBuilderAdapter())); - structure.accept(getLoader()); - return structure; - } -} diff --git a/Http/src/main/java/com/arialyy/aria/http/download/HttpDStartController.kt b/Http/src/main/java/com/arialyy/aria/http/download/HttpDStartStartController.kt similarity index 88% rename from Http/src/main/java/com/arialyy/aria/http/download/HttpDStartController.kt rename to Http/src/main/java/com/arialyy/aria/http/download/HttpDStartStartController.kt index d098d256..39a48b43 100644 --- a/Http/src/main/java/com/arialyy/aria/http/download/HttpDStartController.kt +++ b/Http/src/main/java/com/arialyy/aria/http/download/HttpDStartStartController.kt @@ -24,7 +24,7 @@ import com.arialyy.aria.core.processor.IHttpFileLenAdapter 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.http.HttpBaseController +import com.arialyy.aria.http.HttpBaseStartController import com.arialyy.aria.http.HttpOption import com.arialyy.aria.http.HttpUtil import com.arialyy.aria.orm.entity.DEntity @@ -37,7 +37,7 @@ import java.net.HttpURLConnection * @Description * @Date 12:38 PM 2023/1/22 **/ -class HttpDStartController(target: Any, val url: String) : HttpBaseController(target), +class HttpDStartStartController(target: Any, val url: String) : HttpBaseStartController(target), IStartController { private var httpDTaskOption = HttpDTaskOption() @@ -50,7 +50,7 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseController(ta * use multi-threaded download file, if file size <= 5m, this setting is not valid * @param threadNum range [1 - 32] */ - fun setThreadNum(threadNum: Int): HttpDStartController { + fun setThreadNum(threadNum: Int): HttpDStartStartController { if (threadNum !in 1..32) { Timber.e("set thread num fail, only 0 < threadNum < 33, threadNum: $threadNum") return this @@ -62,7 +62,7 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseController(ta /** * set http params, link Header */ - fun setHttpOption(httpOption: HttpOption): HttpDStartController { + fun setHttpOption(httpOption: HttpOption): HttpDStartStartController { httpDTaskOption.httpOption = httpOption return this } @@ -70,7 +70,7 @@ 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] */ - fun setHttpFileLenAdapter(adapter: IHttpFileLenAdapter): HttpDStartController { + fun setHttpFileLenAdapter(adapter: IHttpFileLenAdapter): HttpDStartStartController { httpDTaskOption.fileSizeAdapter = adapter return this } @@ -79,7 +79,7 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseController(ta * 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 { + fun setTaskInterceptor(taskInterceptor: ITaskInterceptor): HttpDStartStartController { httpDTaskOption.taskInterceptor.add(taskInterceptor) return this } @@ -87,7 +87,7 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseController(ta /** * set download listener */ - fun setListener(listener: HttpDownloadListener): HttpDStartController { + fun setListener(listener: HttpDownloadListener): HttpDStartStartController { DuaContext.getLifeManager().addCustomListener(target, listener) return this } @@ -95,7 +95,7 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseController(ta /** * set file save path, eg: /mnt/sdcard/Downloads/test.zip */ - fun setSavePath(savePath: Uri): HttpDStartController { + fun setSavePath(savePath: Uri): HttpDStartStartController { httpDTaskOption.savePathUri = savePath return this } @@ -104,7 +104,7 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseController(ta if (HttpUtil.checkHttpDParams(httpDTaskOption)) { throw IllegalArgumentException("invalid params") } - val savePath = httpDTaskOption.savePathUri!!.toString() + val savePath = httpDTaskOption.savePathUri!! var util = TaskCachePool.getTaskUtil(savePath) if (util == null) { util = HttpDTaskUtil() @@ -115,6 +115,7 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseController(ta val dEntity = findDEntityBySavePath(httpDTaskOption) TaskCachePool.putEntity(task.taskId, dEntity) } + TaskCachePool.putTask(task) return task } 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 new file mode 100644 index 00000000..5c7b33a0 --- /dev/null +++ b/Http/src/main/java/com/arialyy/aria/http/download/HttpDStopController.kt @@ -0,0 +1,47 @@ +/* + * 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.http.download + +import android.net.Uri +import com.arialyy.aria.core.task.TaskCachePool +import timber.log.Timber + +/** + * @Author laoyuyu + * @Description + * @Date 20:25 2023/2/19 + **/ +class HttpDStopController(val taskId: Int) { + + fun cancel() { + val task = TaskCachePool.getTask(taskId) + if (task == null) { + Timber.e("task not found, taskId: $taskId") + return + } + HttpDStopController2(Uri.parse(task.filePath)).cancel() + } + + fun stop() { + val task = TaskCachePool.getTask(taskId) + if (task == null) { + Timber.e("task not found, taskId: $taskId") + return + } + HttpDStopController2(Uri.parse(task.filePath)).stop() + } + +} \ No newline at end of file diff --git a/Http/src/main/java/com/arialyy/aria/http/download/HttpDStopController2.kt b/Http/src/main/java/com/arialyy/aria/http/download/HttpDStopController2.kt new file mode 100644 index 00000000..72a60d36 --- /dev/null +++ b/Http/src/main/java/com/arialyy/aria/http/download/HttpDStopController2.kt @@ -0,0 +1,65 @@ +/* + * 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.http.download + +import android.net.Uri +import com.arialyy.aria.core.DuaContext +import com.arialyy.aria.http.HttpUtil +import com.arialyy.aria.util.FileUtils +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import timber.log.Timber + +/** + * @Author laoyuyu + * @Description + * @Date 20:25 2023/2/19 + **/ +class HttpDStopController2(val filePath: Uri) { + + private suspend fun checkUri(): Boolean { + if (!FileUtils.uriEffective(filePath)) { + Timber.e("invalid uri: $filePath") + return false + } + return withContext(Dispatchers.IO) { + val entity = DuaContext.getServiceManager().getDbService().getDuaDb().getDEntityDao() + .getDEntityBySavePath(filePath.toString()) + if (entity == null) { + Timber.e("No found task, uri: $filePath") + return@withContext false + } + return@withContext true + } + } + + fun cancel() { + DuaContext.duaScope.launch { + if (checkUri()) { + HttpUtil.getDTaskUtil(filePath).cancel() + } + } + } + + fun stop() { + DuaContext.duaScope.launch { + if (checkUri()) { + HttpUtil.getDTaskUtil(filePath).stop() + } + } + } +} \ No newline at end of file diff --git a/Http/src/main/java/com/arialyy/aria/http/download/HttpDTTBuilderAdapter.java b/Http/src/main/java/com/arialyy/aria/http/download/HttpDTTBuilderAdapter.java deleted file mode 100644 index e4e3186e..00000000 --- a/Http/src/main/java/com/arialyy/aria/http/download/HttpDTTBuilderAdapter.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.arialyy.aria.http.download; - -import com.arialyy.aria.core.TaskRecord; -import com.arialyy.aria.core.common.SubThreadConfig; -import com.arialyy.aria.core.loader.AbsNormalTTBuilderAdapter; -import com.arialyy.aria.core.loader.IRecordHandler; -import com.arialyy.aria.core.task.IThreadTaskAdapter; -import com.arialyy.aria.util.ALog; -import com.arialyy.aria.util.BufferedRandomAccessFile; -import com.arialyy.aria.util.FileUtil; -import java.io.File; -import java.io.IOException; - -final class HttpDTTBuilderAdapter extends AbsNormalTTBuilderAdapter { - - @Override public IThreadTaskAdapter getAdapter(SubThreadConfig config) { - return new HttpDThreadTaskAdapter(config); - } - - @Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) { - if (!record.isBlock) { - if (getTempFile().exists()) { - FileUtil.deleteFile(getTempFile()); - } - } else { - for (int i = 0; i < totalThreadNum; i++) { - File blockFile = - new File(String.format(IRecordHandler.SUB_PATH, getTempFile().getPath(), i)); - if (blockFile.exists()) { - ALog.d(TAG, String.format("分块【%s】已经存在,将删除该分块", i)); - FileUtil.deleteFile(blockFile); - } - } - } - BufferedRandomAccessFile file = null; - try { - if (totalThreadNum > 1 && !record.isBlock) { - file = new BufferedRandomAccessFile(getTempFile().getPath(), "rwd", 8192); - //设置文件长度 - file.setLength(getEntity().getFileSize()); - } - if (getTempFile().exists()) { - FileUtil.deleteFile(getTempFile()); - } - return true; - } catch (IOException e) { - e.printStackTrace(); - ALog.e(TAG, String.format("下载失败,filePath: %s, url: %s", getEntity().getFilePath(), - getEntity().getUrl())); - } finally { - if (file != null) { - try { - file.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - return false; - } -} \ No newline at end of file diff --git a/Http/src/main/java/com/arialyy/aria/http/download/HttpDownloader.kt b/Http/src/main/java/com/arialyy/aria/http/download/HttpDownloader.kt index b268ac7b..d65a1469 100644 --- a/Http/src/main/java/com/arialyy/aria/http/download/HttpDownloader.kt +++ b/Http/src/main/java/com/arialyy/aria/http/download/HttpDownloader.kt @@ -15,6 +15,7 @@ */ package com.arialyy.aria.http.download +import android.net.Uri import com.arialyy.annotations.TaskEnum import com.arialyy.annotations.TaskEnum.DOWNLOAD import com.arialyy.aria.core.inf.IDownloader @@ -30,7 +31,28 @@ class HttpDownloader(val target: Any) : IDownloader { return DOWNLOAD } - fun load(url: String): HttpDStartController { - return HttpDStartController(target, url) + /** + * start, create a task + * @param url download url + */ + fun load(url: String): HttpDStartStartController { + return HttpDStartStartController(target, url) } + + /** + * stop, cancel a task + * @param taskId taskId + */ + fun load(taskId: Int): HttpDStopController { + return HttpDStopController(taskId) + } + + /** + * stop, cancel a task + * @param filePath filePath + */ + fun load(filePath: Uri): HttpDStopController2 { + return HttpDStopController2(filePath) + } + } \ No newline at end of file diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/inf/IEntity.java b/PublicComponent/src/main/java/com/arialyy/aria/core/inf/IEntity.java index 58336051..f51b47f2 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/inf/IEntity.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/inf/IEntity.java @@ -15,12 +15,13 @@ */ package com.arialyy.aria.core.inf; +import android.os.Parcelable; import androidx.room.Ignore; /** * Created by lyy on 2017/2/23. */ -public interface IEntity { +public interface IEntity extends Parcelable { /** * 其它状态 */ diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/inf/IStopController.kt b/PublicComponent/src/main/java/com/arialyy/aria/core/inf/IStopController.kt new file mode 100644 index 00000000..f705bdd9 --- /dev/null +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/inf/IStopController.kt @@ -0,0 +1,46 @@ +/* + * 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.core.inf + +import android.net.Uri + +/** + * @Author laoyuyu + * @Description + * @Date 20:26 2023/2/19 + **/ +interface IStopController { + + /** + * remove a task + */ + fun cancel(taskId: Int) + + /** + * remove task by file path + */ + fun cancelByFilePath(filePath: Uri) + + /** + * stop a task + */ + fun stop(taskId: Int) + + /** + * remove task by file path + */ + fun stopByFilePath(filePath: Uri) +} \ No newline at end of file diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/listener/AbsEventListener.java b/PublicComponent/src/main/java/com/arialyy/aria/core/listener/AbsEventListener.java index fe503a02..dd5ea04a 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/listener/AbsEventListener.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/listener/AbsEventListener.java @@ -26,7 +26,6 @@ import com.arialyy.aria.core.task.TaskState; import com.arialyy.aria.exception.AriaException; import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ErrorHelp; -import java.lang.ref.WeakReference; import timber.log.Timber; public abstract class AbsEventListener implements IEventListener { @@ -142,8 +141,12 @@ public abstract class AbsEventListener implements IEventListener { if (state == IEntity.STATE_CANCEL) { handleCancel(); + TaskCachePool.INSTANCE.removeTask(getTask().getTaskId()); return; } + if (state == IEntity.STATE_COMPLETE || state == IEntity.STATE_STOP) { + TaskCachePool.INSTANCE.removeTask(getTask().getTaskId()); + } TaskCachePool.INSTANCE.updateState(mTask.getTaskId(), state, location); } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/task/AbsTask.java b/PublicComponent/src/main/java/com/arialyy/aria/core/task/AbsTask.java index 9e7c62c8..2eac0864 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/task/AbsTask.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/task/AbsTask.java @@ -218,7 +218,7 @@ public abstract class AbsTask implements ITask { * @return {@code true}任务已经取消 */ @Override - public boolean isCancel() { + public boolean isCanceled() { return isCancel; } @@ -228,7 +228,7 @@ public abstract class AbsTask implements ITask { * @return {@code true}任务已经停止 */ @Override - public boolean isStop() { + public boolean isStopped() { return isStop; } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/task/DownloadTask.java b/PublicComponent/src/main/java/com/arialyy/aria/core/task/DownloadTask.java index e6c23723..24073ae0 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/task/DownloadTask.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/task/DownloadTask.java @@ -46,7 +46,7 @@ public class DownloadTask extends AbsTask { return ITask.DOWNLOAD; } - @Override public String getTaskKey() { + @Override public String getFilePath() { return Objects.requireNonNull(getTaskOption(DTaskOption.class).getSavePathUri()).toString(); } } \ No newline at end of file diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/task/ITask.java b/PublicComponent/src/main/java/com/arialyy/aria/core/task/ITask.java index e03847c5..ce383c18 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/task/ITask.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/task/ITask.java @@ -99,14 +99,14 @@ public interface ITask { * * @return {@code true}任务已经停止 */ - boolean isStop(); + boolean isStopped(); /** * 任务是否取消了 * * @return {@code true}任务已经取消 */ - boolean isCancel(); + boolean isCanceled(); /** * 任务的调度类型 @@ -116,7 +116,10 @@ public interface ITask { int getTaskId(); - String getTaskKey(); + /** + * @return task unique identifier, like: savePath + */ + String getFilePath(); T getTaskOption(Class clazz); } 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 903aea3c..152e6c22 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 @@ -15,10 +15,12 @@ */ 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.ITaskUtil import timber.log.Timber +import java.util.concurrent.ConcurrentHashMap /** * @Author laoyuyu @@ -29,25 +31,35 @@ object TaskCachePool { /** * key: taskId */ - private val entityMap = hashMapOf() - private val taskUtilMap = hashMapOf() + private val entityMap = ConcurrentHashMap() + private val taskUtilMap = ConcurrentHashMap() + private val taskMap = ConcurrentHashMap() + + fun removeTask(taskId: Int) { + taskMap.remove(taskId) + } /** - * @param taskKey task unique identifier, like: savePath, sourceUrl + * if task is completed, stopped, canceled, return null */ - fun putTaskUtil(taskKey: String, taskUtil: ITaskUtil) { - if (taskKey.isEmpty()) { - Timber.e("invalid taskKey: $taskKey") - return - } - taskUtilMap[taskKey] = taskUtil + fun getTask(taskId: Int) = taskMap[taskId] + + fun putTask(task: ITask) { + taskMap[task.taskId] = task + } + + /** + * @param filePath task unique identifier, like: savePath, sourceUrl + */ + fun putTaskUtil(filePath: Uri, taskUtil: ITaskUtil) { + taskUtilMap[filePath] = taskUtil } /** - * @param taskKey task unique identifier, like: savePath, sourceUrl + * @param filePath unique identifier, like: savePath, sourceUrl */ - fun getTaskUtil(taskKey: String): ITaskUtil? { - return taskUtilMap[taskKey] + fun getTaskUtil(filePath: Uri): ITaskUtil? { + return taskUtilMap[filePath] } fun putEntity(taskId: Int, entity: BaseEntity) { 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 ce570c4d..d620e00e 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 @@ -16,6 +16,8 @@ package com.arialyy.aria.orm.entity import android.net.Uri +import android.os.Parcel +import android.os.Parcelable.Creator import androidx.room.Entity import androidx.room.Index import androidx.room.PrimaryKey @@ -53,6 +55,17 @@ data class DEntity( val fileSize: Long = 0 ) : BaseEntity() { + constructor(parcel: Parcel) : this( + parcel.readInt(), + parcel.readInt(), + parcel.readString()!!, + parcel.readParcelable(Uri::class.java.classLoader)!!, + parcel.readString(), + parcel.readByte() != 0.toByte(), + parcel.readLong() + ) { + } + override fun update() { updateTime = System.currentTimeMillis() DuaContext.duaScope.launch(Dispatchers.IO) { @@ -60,4 +73,28 @@ data class DEntity( .update(this@DEntity) } } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeInt(did) + parcel.writeInt(parentId) + parcel.writeString(sourceUrl) + parcel.writeParcelable(savePath, flags) + parcel.writeString(ext) + parcel.writeByte(if (isSub) 1 else 0) + parcel.writeLong(fileSize) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Creator { + override fun createFromParcel(parcel: Parcel): DEntity { + return DEntity(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } } \ No newline at end of file diff --git a/Queue/src/main/java/com/arialyy/aria/queue/AbsTaskQueue.java b/Queue/src/main/java/com/arialyy/aria/queue/AbsTaskQueue.java index 9efb0e6b..382a8ad4 100644 --- a/Queue/src/main/java/com/arialyy/aria/queue/AbsTaskQueue.java +++ b/Queue/src/main/java/com/arialyy/aria/queue/AbsTaskQueue.java @@ -20,8 +20,8 @@ import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IPool; import com.arialyy.aria.core.inf.ITaskQueue; import com.arialyy.aria.core.inf.TaskSchedulerType; -import com.arialyy.aria.core.task.ThreadTaskManager2; import com.arialyy.aria.core.task.ITask; +import com.arialyy.aria.core.task.ThreadTaskManager2; import timber.log.Timber; /** @@ -65,17 +65,17 @@ public abstract class AbsTaskQueue implements ITaskQueue implements ITaskQueue implements ISchedulers { private ISchedulerListener createListener(String proxyClassName) { ISchedulerListener listener = null; try { - Class clazz = Class.forName(proxyClassName); + Class clazz = Class.forName(proxyClassName); listener = (ISchedulerListener) clazz.newInstance(); - } catch (ClassNotFoundException e) { - ALog.e(TAG, e.getMessage()); - } catch (InstantiationException e) { - ALog.e(TAG, e.getMessage()); - } catch (IllegalAccessException e) { + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { ALog.e(TAG, e.getMessage()); } return listener; @@ -312,7 +306,7 @@ public class TaskSchedulers implements ISchedulers { if (!queue.isFull()) { Timber.d("stop task success, if there is a task, start the next task, taskId: %s", task.getTaskId()); - startNextTask(queue, task.getSchedulerType()); + queue.startNextTask(); } else { Timber.d("stop task success, taskId: %s", task.getTaskId()); } @@ -323,7 +317,7 @@ public class TaskSchedulers implements ISchedulers { if (!queue.isFull()) { Timber.d("remove task success, if there is a task, start the next task, taskId: %s", task.getTaskId()); - startNextTask(queue, task.getSchedulerType()); + queue.startNextTask(); } else { Timber.d("remove task success, taskId: %s", task.getTaskId()); } @@ -331,7 +325,7 @@ public class TaskSchedulers implements ISchedulers { case COMPLETE: queue.removeTask(task); Timber.d("task complete, taskId: %s", task.getTaskId()); - startNextTask(queue, task.getSchedulerType()); + queue.startNextTask(); break; case FAIL: handleFailTask(queue, task); @@ -350,8 +344,7 @@ public class TaskSchedulers implements ISchedulers { * @param taskType 任务类型 */ private void handlePreFailTask(int taskType) { - startNextTask(getQueue(taskType), TaskSchedulerType.TYPE_DEFAULT); - + getQueue(taskType).startNextTask(); // 发送广播 boolean canSend = mAriaConfig.getAConfig().isUseBroadcast(); if (canSend) { @@ -478,11 +471,9 @@ public class TaskSchedulers implements ISchedulers { } int type = task.getTaskType(); if (type == ITask.DOWNLOAD || type == ITask.DOWNLOAD_GROUP) { - mAriaConfig.getAPP().sendBroadcast( - createData(state, type, task.getTaskWrapper().getEntity())); + mAriaConfig.getAPP().sendBroadcast(createData(task)); } else if (type == ITask.UPLOAD) { - mAriaConfig.getAPP().sendBroadcast( - createData(state, type, task.getTaskWrapper().getEntity())); + mAriaConfig.getAPP().sendBroadcast(createData(task)); } else { ALog.w(TAG, "发送广播失败,没有对应的任务"); } @@ -490,20 +481,16 @@ public class TaskSchedulers implements ISchedulers { /** * 创建广播发送的数据 - * - * @param taskState 任务状态 {@link ISchedulers} - * @param taskType 任务类型 {@link ITask} - * @param entity 任务实体 */ - private Intent createData(int taskState, int taskType, AbsEntity entity) { + private Intent createData(ITask task) { Intent intent = new Intent(ISchedulers.ARIA_TASK_INFO_ACTION); intent.setPackage(mAriaConfig.getAPP().getPackageName()); Bundle b = new Bundle(); - b.putInt(ISchedulers.TASK_TYPE, taskType); - b.putInt(ISchedulers.TASK_STATE, taskState); - b.putLong(ISchedulers.TASK_SPEED, entity.getSpeed()); - b.putInt(ISchedulers.TASK_PERCENT, entity.getPercent()); - b.putParcelable(ISchedulers.TASK_ENTITY, entity); + b.putInt(ISchedulers.TASK_TYPE, task.getTaskType()); + b.putInt(ISchedulers.TASK_STATE, task.getTaskState().getState()); + b.putLong(ISchedulers.TASK_SPEED, task.getTaskState().getSpeed()); + b.putInt(ISchedulers.TASK_PERCENT, task.getTaskState().getPercent()); + b.putParcelable(ISchedulers.TASK_ENTITY, TaskCachePool.INSTANCE.getEntity(task.getTaskId())); intent.putExtras(b); return intent; } @@ -514,9 +501,9 @@ public class TaskSchedulers implements ISchedulers { * @param task 下载任务 */ private void handleFailTask(final ITaskQueue queue, final TASK task) { - if (!task.getTaskState().getNeedRetry() || task.isStop() || task.isCancel()) { + if (!task.getTaskState().getNeedRetry() || task.isStopped() || task.isCanceled()) { queue.removeTask(task); - startNextTask(queue, task.getSchedulerType()); + queue.startNextTask(); normalTaskCallback(FAIL, task); return; } @@ -525,7 +512,7 @@ public class TaskSchedulers implements ISchedulers { if ((!NetUtils.isConnected(mAriaConfig.getAPP()) && !isNotNetRetry)) { queue.removeTask(task); - startNextTask(queue, task.getSchedulerType()); + queue.startNextTask(); normalTaskCallback(FAIL, task); return; } @@ -533,25 +520,6 @@ public class TaskSchedulers implements ISchedulers { mFailureTaskHandler.offer(task); } - /** - * 启动下一个任务,条件:任务停止,取消下载,任务完成 - */ - void startNextTask(final ITaskQueue queue, int schedulerType) { - if (schedulerType == TaskSchedulerType.TYPE_STOP_NOT_NEXT) { - return; - } - TASK newTask = (TASK) queue.getNextTask(); - if (newTask == null) { - if (queue.getCurrentExePoolNum() == 0) { - ALog.i(TAG, "没有等待中的任务"); - } - return; - } - if (newTask.getTaskState().getState() == IEntity.STATE_WAIT) { - queue.startTask(newTask); - } - } - @Override public void init(@NonNull Context context) { }