parent
e2d706fbc6
commit
e80f2904e1
@ -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<String, String> params = taskOption.getParams(); |
||||
if (params != null) { |
||||
OutputStreamWriter dos = new OutputStreamWriter(conn.getOutputStream()); |
||||
Set<String> 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<String, List<String>> 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<String> 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"参数 |
||||
* <a href=https://cloud.tencent.com/developer/section/1189916>Content-Disposition</a></>
|
||||
* |
||||
* @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<String, List<String>> headers) { |
||||
if (headers == null || headers.isEmpty()) { |
||||
ALog.e(TAG, "header为空,获取文件长度失败"); |
||||
return -1; |
||||
} |
||||
List<String> 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<String> 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; |
||||
} |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
@ -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() |
||||
} |
||||
|
||||
} |
@ -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() |
||||
} |
||||
} |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
@ -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) |
||||
} |
Loading…
Reference in new issue