Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
418ec74b7b | ||
|
|
29f9bdcdbd | ||
|
|
9a5e491e37 | ||
|
|
e64f3b1240 | ||
|
|
dcde3f07b8 | ||
|
|
290e58c58b | ||
|
|
b109726c7c | ||
|
|
4d9a887076 | ||
|
|
a1c294bcbd | ||
|
|
1f2ac36580 | ||
|
|
203eeb10ad | ||
|
|
06a0d764ed | ||
|
|
baf4bac091 | ||
|
|
4951dda5b0 | ||
|
|
ba0162e413 | ||
|
|
0476c3a941 | ||
|
|
73292b6405 | ||
|
|
e99d4a3d7e | ||
|
|
e0dc7f3644 | ||
|
|
cd31276591 | ||
|
|
a65b2e31f9 | ||
|
|
de09add3a3 | ||
|
|
41088dfa23 | ||
|
|
14901d4c0c | ||
|
|
9cb6490da9 | ||
|
|
a1fd63b5c6 | ||
|
|
b90450f1cd | ||
|
|
370dca27ff | ||
|
|
669ac6b09c | ||
|
|
54cbdb7ee0 | ||
|
|
e770818cee | ||
|
|
d92f1bba94 | ||
|
|
ea2e27f3e9 | ||
|
|
ad58dce395 | ||
|
|
472006ef61 | ||
|
|
604fb91800 | ||
|
|
63ec23f241 | ||
|
|
2f2d783655 | ||
|
|
e015c2a2f7 | ||
|
|
96efa35c4e | ||
|
|
7f81995bd8 |
@@ -43,6 +43,8 @@ import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.orm.DelegateWrapper;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.AriaCrashHandler;
|
||||
import com.arialyy.aria.util.DeleteDGRecord;
|
||||
import com.arialyy.aria.util.DeleteURecord;
|
||||
import com.arialyy.aria.util.RecordUtil;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@@ -285,7 +287,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
RecordUtil.delGroupTaskRecordByHash(key, removeFile);
|
||||
break;
|
||||
case 3:
|
||||
RecordUtil.delTaskRecord(key, IRecordHandler.TYPE_UPLOAD);
|
||||
DeleteURecord.getInstance().deleteRecord(key, removeFile, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ import com.arialyy.aria.util.NetUtils;
|
||||
*/
|
||||
final public class StartCmd<T extends AbsTaskWrapper> extends AbsNormalCmd<T> {
|
||||
|
||||
private boolean newStart = false;
|
||||
private boolean nowStart = false;
|
||||
|
||||
StartCmd(T entity, int taskType) {
|
||||
super(entity, taskType);
|
||||
@@ -38,10 +38,10 @@ final public class StartCmd<T extends AbsTaskWrapper> extends AbsNormalCmd<T> {
|
||||
/**
|
||||
* 立即执行任务
|
||||
*
|
||||
* @param newStart true 立即执行任务,无论执行队列是否满了
|
||||
* @param nowStart true 立即执行任务,无论执行队列是否满了
|
||||
*/
|
||||
public void setNewStart(boolean newStart) {
|
||||
this.newStart = newStart;
|
||||
public void setNowStart(boolean nowStart) {
|
||||
this.nowStart = nowStart;
|
||||
}
|
||||
|
||||
@Override public void executeCmd() {
|
||||
@@ -82,7 +82,7 @@ final public class StartCmd<T extends AbsTaskWrapper> extends AbsNormalCmd<T> {
|
||||
startTask();
|
||||
}
|
||||
} else {
|
||||
if (newStart) {
|
||||
if (nowStart) {
|
||||
startTask();
|
||||
} else {
|
||||
sendWaitState(task);
|
||||
@@ -92,7 +92,19 @@ final public class StartCmd<T extends AbsTaskWrapper> extends AbsNormalCmd<T> {
|
||||
} else {
|
||||
//任务没执行并且执行队列中没有该任务,才认为任务没有运行中
|
||||
if (!mQueue.taskIsRunning(task.getKey())) {
|
||||
resumeTask();
|
||||
if (mod.equals(QueueMod.NOW.getTag())) {
|
||||
resumeTask();
|
||||
} else {
|
||||
if (mQueue.getCurrentExePoolNum() < maxTaskNum) {
|
||||
resumeTask();
|
||||
} else {
|
||||
if (nowStart) {
|
||||
resumeTask();
|
||||
} else {
|
||||
sendWaitState(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ALog.w(TAG, String.format("任务【%s】已经在运行", task.getTaskName()));
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.manager.TaskWrapperManager;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.DeleteDGRecord;
|
||||
import com.arialyy.aria.util.RecordUtil;
|
||||
|
||||
/**
|
||||
@@ -82,11 +83,10 @@ public abstract class AbsNormalTarget<TARGET extends AbsNormalTarget> extends Ab
|
||||
cancel();
|
||||
} else {
|
||||
if (getEntity() instanceof AbsNormalEntity) {
|
||||
RecordUtil.delTaskRecord((AbsNormalEntity) getEntity(), getTaskWrapper().isRemoveFile());
|
||||
RecordUtil.delNormalTaskRecord((AbsNormalEntity) getEntity(), getTaskWrapper().isRemoveFile());
|
||||
} else if (getEntity() instanceof DownloadGroupEntity) {
|
||||
RecordUtil.delGroupTaskRecord(((DownloadGroupEntity) getEntity()),
|
||||
getTaskWrapper().isRemoveFile(),
|
||||
true);
|
||||
DeleteDGRecord.getInstance()
|
||||
.deleteRecord(getEntity(), getTaskWrapper().isRemoveFile(), true);
|
||||
}
|
||||
TaskWrapperManager.getInstance().removeTaskWrapper(getTaskWrapper());
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.arialyy.aria.core.common;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.processor.IHttpFileLenAdapter;
|
||||
import com.arialyy.aria.core.processor.IHttpFileNameAdapter;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CheckUtil;
|
||||
import java.net.Proxy;
|
||||
@@ -35,6 +36,7 @@ public class HttpOption extends BaseOption {
|
||||
private Proxy proxy;
|
||||
private boolean useServerFileName = false;
|
||||
private IHttpFileLenAdapter fileLenAdapter;
|
||||
private IHttpFileNameAdapter fileNameAdapter;
|
||||
private String attachment;
|
||||
|
||||
public HttpOption() {
|
||||
@@ -168,4 +170,12 @@ public class HttpOption extends BaseOption {
|
||||
this.fileLenAdapter = fileLenAdapter;
|
||||
return this;
|
||||
}
|
||||
public HttpOption setFilNameAdapter(IHttpFileNameAdapter fileNameAdapter) {
|
||||
if (fileNameAdapter == null) {
|
||||
throw new IllegalArgumentException("adapter为空");
|
||||
}
|
||||
CheckUtil.checkMemberClass(fileNameAdapter.getClass());
|
||||
this.fileNameAdapter = fileNameAdapter;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public final class NormalController extends FeatureController implements INormal
|
||||
StartCmd cmd =
|
||||
(StartCmd) CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_START,
|
||||
checkTaskType());
|
||||
cmd.setNewStart(newStart);
|
||||
cmd.setNowStart(newStart);
|
||||
EventMsgUtil.getDefault()
|
||||
.post(cmd);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ public class CheckDEntityUtil implements ICheckEntityUtil {
|
||||
@Override
|
||||
public boolean checkEntity() {
|
||||
if (mWrapper.getErrorEvent() != null) {
|
||||
ALog.e(TAG, String.format("下载失败,%s", mWrapper.getErrorEvent().errorMsg));
|
||||
ALog.e(TAG, String.format("任务操作失败,%s", mWrapper.getErrorEvent().errorMsg));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -140,7 +140,8 @@ public class CheckDEntityUtil implements ICheckEntityUtil {
|
||||
//设置文件保存路径,如果新文件路径和旧文件路径不同,则修改路径
|
||||
if (!filePath.equals(mEntity.getFilePath())) {
|
||||
// 检查路径冲突
|
||||
if (!CheckUtil.checkDPathConflicts(mWrapper.isIgnoreFilePathOccupy(), filePath)) {
|
||||
if (!CheckUtil.checkDPathConflicts(mWrapper.isIgnoreFilePathOccupy(), filePath,
|
||||
mWrapper.getRequestType())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.arialyy.aria.core.inf.IOptionConstant;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CheckUtil;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.RecordUtil;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@@ -44,6 +43,9 @@ public class CheckDGEntityUtil implements ICheckEntityUtil {
|
||||
private boolean needModifyPath = false;
|
||||
private int action;
|
||||
|
||||
/**
|
||||
* @param action {@link FeatureController#ACTION_CREATE}
|
||||
*/
|
||||
public static CheckDGEntityUtil newInstance(DGTaskWrapper wrapper, int action) {
|
||||
return new CheckDGEntityUtil(wrapper, action);
|
||||
}
|
||||
@@ -113,10 +115,36 @@ public class CheckDGEntityUtil implements ICheckEntityUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查和处理组合任务的路径冲突
|
||||
*
|
||||
* @param isIgnoreTaskOccupy true,如果hash冲突,将删除其它任务的记录的
|
||||
* @param groupHash 组任务hash
|
||||
* @return false 任务不再执行,true 任务继续执行
|
||||
*/
|
||||
private boolean checkGroupHash(boolean isIgnoreTaskOccupy, String groupHash) {
|
||||
if (DbEntity.checkDataExist(DownloadGroupEntity.class, "groupHash=?", groupHash)) {
|
||||
if (!isIgnoreTaskOccupy) {
|
||||
ALog.e(TAG, String.format("下载失败,数据库中已存在相同的url的组任务,groupHash = %s", groupHash));
|
||||
return false;
|
||||
} else {
|
||||
ALog.w(TAG, String.format("数据库中已存在相同的url的组任务,将删除groupHash = %s 的旧任务", groupHash));
|
||||
RecordUtil.delGroupTaskRecordByHash(groupHash, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEntity() {
|
||||
if (mWrapper.getErrorEvent() != null) {
|
||||
ALog.e(TAG, String.format("操作失败,%s", mWrapper.getErrorEvent().errorMsg));
|
||||
ALog.e(TAG, String.format("任务操作失败,%s", mWrapper.getErrorEvent().errorMsg));
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((action == FeatureController.ACTION_CREATE || action == FeatureController.ACTION_ADD)
|
||||
&& !checkGroupHash(mWrapper.isIgnoreTaskOccupy(), mEntity.getGroupHash())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -240,9 +268,6 @@ public class CheckDGEntityUtil implements ICheckEntityUtil {
|
||||
mWrapper.getSubNameTemp().remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
mEntity.setGroupHash(CommonUtil.getMd5Code(mEntity.getUrls()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ public class CheckFtpDirEntityUtil implements ICheckEntityUtil {
|
||||
@Override
|
||||
public boolean checkEntity() {
|
||||
if (mWrapper.getErrorEvent() != null) {
|
||||
ALog.e(TAG, String.format("下载失败,%s", mWrapper.getErrorEvent().errorMsg));
|
||||
ALog.e(TAG, String.format("任务操作失败,%s", mWrapper.getErrorEvent().errorMsg));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -417,15 +417,7 @@ public class DownloadReceiver extends AbsReceiver {
|
||||
* @return 如果没有任务组列表,则返回null
|
||||
*/
|
||||
public List<DownloadGroupEntity> getGroupTaskList() {
|
||||
List<DGEntityWrapper> wrappers = DbEntity.findRelationData(DGEntityWrapper.class);
|
||||
if (wrappers == null || wrappers.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
List<DownloadGroupEntity> entities = new ArrayList<>();
|
||||
for (DGEntityWrapper wrapper : wrappers) {
|
||||
entities.add(wrapper.groupEntity);
|
||||
}
|
||||
return entities;
|
||||
return getGroupTaskList(1,10);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,12 +37,23 @@ public class M3U8Option<OP extends M3U8Option> extends BaseOption {
|
||||
private IKeyUrlConverter keyUrlConverter;
|
||||
private boolean ignoreFailureTs = false;
|
||||
private String keyPath;
|
||||
private boolean useDefConvert = true;
|
||||
|
||||
M3U8Option() {
|
||||
super();
|
||||
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_M3U8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置使用默认的码率转换器和TS转换器,默认打开
|
||||
* @param useDefConvert true 使用默认的转换器,false 关闭默认的转换器
|
||||
*/
|
||||
public OP setUseDefConvert(boolean useDefConvert) {
|
||||
this.useDefConvert = true;
|
||||
ALog.d(TAG, "使用默认的码率转换器和TS转换器,如果无法下载,请参考:https://github.com/AriaLyy/Aria/issues/597 定制转换器");
|
||||
return (OP) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置密钥文件的保存路径
|
||||
*
|
||||
@@ -76,7 +87,7 @@ public class M3U8Option<OP extends M3U8Option> extends BaseOption {
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否合并ts文件,默认合并ts
|
||||
* 下载完成后,将所有的切片合并为一个文件
|
||||
*
|
||||
* @param mergeFile {@code true}合并所有ts文件为一个
|
||||
*/
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.arialyy.aria.core.download.target;
|
||||
|
||||
import com.arialyy.aria.core.common.AbsBuilderTarget;
|
||||
import com.arialyy.aria.core.common.HttpOption;
|
||||
import com.arialyy.aria.core.download.AbsGroupTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DGTaskWrapper;
|
||||
import com.arialyy.aria.core.manager.SubTaskManager;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
@@ -105,6 +106,14 @@ public class GroupBuilderTarget extends AbsBuilderTarget<GroupBuilderTarget> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code true} 忽略任务冲突,不考虑组任务hash冲突的情况
|
||||
*/
|
||||
public GroupBuilderTarget ignoreTaskOccupy() {
|
||||
((AbsGroupTaskWrapper) getTaskWrapper()).setIgnoreTaskOccupy(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置任务组的文件夹路径,在Aria中,任务组的所有子任务都会下载到以任务组组名的文件夹中。
|
||||
* 如:groupDirPath = "/mnt/sdcard/download/group_test"
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.arialyy.aria.core.download.target;
|
||||
|
||||
import com.arialyy.aria.core.common.AbsNormalTarget;
|
||||
import com.arialyy.aria.core.common.HttpOption;
|
||||
import com.arialyy.aria.core.download.AbsGroupTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DGTaskWrapper;
|
||||
import com.arialyy.aria.core.manager.SubTaskManager;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
@@ -73,6 +74,14 @@ public class GroupNormalTarget extends AbsNormalTarget<GroupNormalTarget> {
|
||||
return mConfigHandler.updateUrls(urls);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code true} 忽略任务冲突,不考虑组任务hash冲突的情况
|
||||
*/
|
||||
public GroupNormalTarget ignoreTaskOccupy() {
|
||||
((AbsGroupTaskWrapper) getTaskWrapper()).setIgnoreTaskOccupy(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新任务组的文件夹路径,在Aria中,任务组的所有子任务都会下载到以任务组组名的文件夹中。
|
||||
* 如:groupDirPath = "/mnt/sdcard/download/group_test"
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.arialyy.aria.core.queue;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import com.arialyy.aria.core.common.AbsEntity;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.inf.TaskSchedulerType;
|
||||
@@ -113,6 +114,10 @@ public abstract class AbsTaskQueue<TASK extends AbsTask, TASK_WRAPPER extends Ab
|
||||
ALog.w(TAG, "resume task fail, task is null");
|
||||
return;
|
||||
}
|
||||
if (mExecutePool.taskExits(task.getKey())) {
|
||||
ALog.w(TAG, String.format("task【%s】running", task.getKey()));
|
||||
return;
|
||||
}
|
||||
if (mExecutePool.size() >= getMaxTaskNum()) {
|
||||
task.getTaskWrapper().getEntity().setState(IEntity.STATE_WAIT);
|
||||
mCachePool.putTaskToFirst(task);
|
||||
@@ -229,6 +234,7 @@ public abstract class AbsTaskQueue<TASK extends AbsTask, TASK_WRAPPER extends Ab
|
||||
if (task == null) {
|
||||
task = mCachePool.getTask(key);
|
||||
}
|
||||
ALog.i(TAG, "获取任务,key:" + key);
|
||||
return task;
|
||||
}
|
||||
|
||||
@@ -259,6 +265,7 @@ public abstract class AbsTaskQueue<TASK extends AbsTask, TASK_WRAPPER extends Ab
|
||||
ALog.w(TAG, String.format("任务【%s】执行中", task.getKey()));
|
||||
return;
|
||||
}
|
||||
ALog.i(TAG, "添加任务,key:" + task.getKey());
|
||||
mCachePool.removeTask(task);
|
||||
mExecutePool.putTask(task);
|
||||
task.getTaskWrapper().getEntity().setFailNum(0);
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.arialyy.aria.core.scheduler;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
import com.arialyy.annotations.TaskEnum;
|
||||
import com.arialyy.aria.core.AriaConfig;
|
||||
import com.arialyy.aria.core.common.AbsEntity;
|
||||
|
||||
@@ -40,7 +40,7 @@ public class CheckUEntityUtil implements ICheckEntityUtil {
|
||||
@Override
|
||||
public boolean checkEntity() {
|
||||
if (mWrapper.getErrorEvent() != null) {
|
||||
ALog.e(TAG, String.format("上传失败,%s", mWrapper.getErrorEvent().errorMsg));
|
||||
ALog.e(TAG, String.format("任务操作失败,%s", mWrapper.getErrorEvent().errorMsg));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -61,8 +61,9 @@ public class CheckUEntityUtil implements ICheckEntityUtil {
|
||||
return false;
|
||||
}
|
||||
// 任务是新任务,并且路径冲突就不会继续执行
|
||||
if (mWrapper.isNewTask() && !CheckUtil.checkUPathConflicts(
|
||||
mWrapper.isIgnoreFilePathOccupy(), filePath)) {
|
||||
if (mWrapper.isNewTask()
|
||||
&& !CheckUtil.checkUPathConflicts(mWrapper.isIgnoreFilePathOccupy(), filePath,
|
||||
mWrapper.getRequestType())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
25
DEV_LOG.md
25
DEV_LOG.md
@@ -1,4 +1,29 @@
|
||||
## 开发日志
|
||||
+ v_3.8.9 (2020/6/14)
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/688
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/690
|
||||
- m3u8任务增加`setUseDefConvert()`方法,用于处理默认的m3u8任务
|
||||
+ v_3.8.8 (2020/6/7)
|
||||
- 修复设置了cancel(false),文件还是被删除的问题 https://github.com/AriaLyy/Aria/issues/686
|
||||
- 修复错误url的下载任务,无法删除的问题 https://github.com/AriaLyy/Aria/issues/684
|
||||
+ v_3.8.7 (2020/5/25)
|
||||
- 修复组合任务单个子任务失败后,重新恢复组合任务,组合任务状态变为完成的问题
|
||||
- 修复40x错误,会继续重试并且无法重试成功的问题 https://github.com/AriaLyy/Aria/issues/619
|
||||
- 修复wait模式下,resume(true)无效问题
|
||||
- 修复now模式下的一些问题 https://github.com/AriaLyy/Aria/issues/620
|
||||
- 修复组任务,其中一个子任务在获取文件长度失败后,重新恢复组合任务,组合任务状态变为完成的问题 https://github.com/AriaLyy/Aria/issues/628
|
||||
- 修复组任务中,其中一个子任务是30x地址,导致调度器无法出现该子任务状态的问题
|
||||
- 增加组任务groupHash冲突检查 https://github.com/AriaLyy/Aria/issues/635
|
||||
- 修复task.cancel(false)还是把本地文件删除的问题 https://github.com/AriaLyy/Aria/issues/646
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/670
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/664
|
||||
+ v_3.8.6 (2020/2/17)
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/608
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/579#issuecomment-586665035
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/610
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/614
|
||||
- 增加文件名适配器(感谢小伙伴[DaveBoy](https://github.com/DaveBoy)的PR)
|
||||
- 优化异常提示
|
||||
+ v_3.8.5 (2020/1/18)
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/599
|
||||
- 增加密钥url转换器的参数 https://github.com/AriaLyy/Aria/issues/603
|
||||
|
||||
@@ -31,8 +31,7 @@ import com.arialyy.aria.core.common.FtpConnectionMode;
|
||||
import com.arialyy.aria.core.loader.IInfoTask;
|
||||
import com.arialyy.aria.core.loader.ILoaderVisitor;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.exception.AriaIOException;
|
||||
import com.arialyy.aria.exception.TaskException;
|
||||
import com.arialyy.aria.exception.AriaFTPException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CheckUtil;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
@@ -161,9 +160,9 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
|
||||
loginSuccess = client.login(urlEntity.user, urlEntity.password, urlEntity.account);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
ALog.e(TAG,
|
||||
new TaskException(TAG, String.format("登录失败,错误码为:%s, msg:%s", client.getReplyCode(),
|
||||
client.getReplyString()), e));
|
||||
e.printStackTrace();
|
||||
ALog.e(TAG, String.format("登录失败,错误码为:%s, msg:%s", client.getReplyCode(),
|
||||
client.getReplyString()));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -329,7 +328,7 @@ public abstract class AbsFtpInfoTask<ENTITY extends AbsEntity, TASK_WRAPPER exte
|
||||
needRetry = needRetry && !CheckUtil.ftpIsBadRequest(client.getReplyCode());
|
||||
}
|
||||
|
||||
callback.onFail(mEntity, new AriaIOException(TAG, msg), needRetry);
|
||||
callback.onFail(mEntity, new AriaFTPException(TAG, msg), needRetry);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import com.arialyy.aria.core.FtpUrlEntity;
|
||||
import com.arialyy.aria.core.common.FtpConnectionMode;
|
||||
import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
import com.arialyy.aria.core.task.AbsThreadTaskAdapter;
|
||||
import com.arialyy.aria.exception.AriaIOException;
|
||||
import com.arialyy.aria.exception.AriaFTPException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.SSLContextUtil;
|
||||
import java.io.IOException;
|
||||
@@ -105,7 +105,7 @@ public abstract class BaseFtpThreadTaskAdapter extends AbsThreadTaskAdapter {
|
||||
int reply = client.getReplyCode();
|
||||
if (!FTPReply.isPositiveCompletion(reply)) {
|
||||
client.disconnect();
|
||||
fail(new AriaIOException(TAG,
|
||||
fail(new AriaFTPException(TAG,
|
||||
String.format("无法连接到ftp服务器,错误码为:%s,msg:%s", reply, client.getReplyString())), false);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import aria.apache.commons.net.ftp.FTPReply;
|
||||
import com.arialyy.aria.core.common.CompleteInfo;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.exception.AriaIOException;
|
||||
import com.arialyy.aria.exception.AriaFTPException;
|
||||
import com.arialyy.aria.ftp.AbsFtpInfoTask;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.FileUtil;
|
||||
@@ -41,7 +41,7 @@ final class FtpDFileInfoTask extends AbsFtpInfoTask<DownloadEntity, DTaskWrapper
|
||||
@Override protected void handleFile(String remotePath, FTPFile ftpFile) {
|
||||
super.handleFile(remotePath, ftpFile);
|
||||
if (!FileUtil.checkMemorySpace(mEntity.getFilePath(), ftpFile.getSize())) {
|
||||
callback.onFail(mEntity, new AriaIOException(TAG,
|
||||
callback.onFail(mEntity, new AriaFTPException(TAG,
|
||||
String.format("获取ftp文件信息失败,内存空间不足, filePath: %s", mEntity.getFilePath())),
|
||||
false);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ import com.arialyy.aria.ftp.FtpTaskOption;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.RecordUtil;
|
||||
import com.arialyy.aria.util.DeleteDGRecord;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
@@ -236,6 +236,6 @@ final class FtpDGInfoTask extends AbsFtpInfoTask<DownloadGroupEntity, DGTaskWrap
|
||||
@Override
|
||||
protected void failDownload(FTPClient client, String msg, Exception e, boolean needRetry) {
|
||||
super.failDownload(client, msg, e, needRetry);
|
||||
RecordUtil.delGroupTaskRecord(mTaskWrapper.getEntity(), true, true);
|
||||
DeleteDGRecord.getInstance().deleteRecord(mTaskWrapper.getEntity(), true, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.core.loader.IInfoTask;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
|
||||
/**
|
||||
@@ -79,7 +79,7 @@ final class FtpDGLoader extends AbsGroupLoader {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
|
||||
@Override public void onFail(AbsEntity entity, AriaException e, boolean needRetry) {
|
||||
//getListener().onFail(needRetry, e);
|
||||
fail(e, needRetry);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,7 @@ package com.arialyy.aria.ftp.download;
|
||||
import aria.apache.commons.net.ftp.FTPClient;
|
||||
import aria.apache.commons.net.ftp.FTPReply;
|
||||
import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
import com.arialyy.aria.exception.AriaIOException;
|
||||
import com.arialyy.aria.exception.TaskException;
|
||||
import com.arialyy.aria.exception.AriaFTPException;
|
||||
import com.arialyy.aria.ftp.BaseFtpThreadTaskAdapter;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
||||
@@ -57,7 +56,7 @@ final class FtpDThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
getThreadRecord().endLocation));
|
||||
client = createClient();
|
||||
if (client == null) {
|
||||
fail(new TaskException(TAG, "ftp client 创建失败"), false);
|
||||
fail(new AriaFTPException(TAG, "ftp client 创建失败"), false);
|
||||
return;
|
||||
}
|
||||
if (getThreadRecord().startLocation > 0) {
|
||||
@@ -66,7 +65,7 @@ final class FtpDThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
//发送第二次指令时,还需要再做一次判断
|
||||
int reply = client.getReplyCode();
|
||||
if (!FTPReply.isPositivePreliminary(reply) && reply != FTPReply.COMMAND_OK) {
|
||||
fail(new AriaIOException(TAG,
|
||||
fail(new AriaFTPException(TAG,
|
||||
String.format("获取文件信息错误,错误码为:%s,msg:%s", reply, client.getReplyString())), false);
|
||||
client.disconnect();
|
||||
return;
|
||||
@@ -77,7 +76,7 @@ final class FtpDThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
is = client.retrieveFileStream(remotePath);
|
||||
reply = client.getReplyCode();
|
||||
if (!FTPReply.isPositivePreliminary(reply)) {
|
||||
fail(new AriaIOException(TAG,
|
||||
fail(new AriaFTPException(TAG,
|
||||
String.format("获取流失败,错误码为:%s,msg:%s", reply, client.getReplyString())), true);
|
||||
client.disconnect();
|
||||
return;
|
||||
@@ -90,9 +89,9 @@ final class FtpDThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
handleComplete();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
fail(new AriaIOException(TAG, String.format("下载失败【%s】", getThreadConfig().url), e), true);
|
||||
fail(new AriaFTPException(TAG, String.format("下载失败【%s】", getThreadConfig().url), e), true);
|
||||
} catch (Exception e) {
|
||||
fail(new AriaIOException(TAG, String.format("下载失败【%s】", getThreadConfig().url), e), false);
|
||||
fail(new AriaFTPException(TAG, String.format("下载失败【%s】", getThreadConfig().url), e), false);
|
||||
} finally {
|
||||
try {
|
||||
if (is != null) {
|
||||
@@ -154,7 +153,7 @@ final class FtpDThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
}
|
||||
handleComplete();
|
||||
} catch (IOException e) {
|
||||
fail(new AriaIOException(TAG, String.format("下载失败【%s】", getThreadConfig().url), e), true);
|
||||
fail(new AriaFTPException(TAG, String.format("下载失败【%s】", getThreadConfig().url), e), true);
|
||||
} finally {
|
||||
try {
|
||||
if (fos != null) {
|
||||
@@ -179,8 +178,9 @@ final class FtpDThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
BufferedRandomAccessFile file = null;
|
||||
try {
|
||||
file =
|
||||
new BufferedRandomAccessFile(getThreadConfig().tempFile, "rwd", getTaskConfig().getBuffSize());
|
||||
if (getThreadRecord().startLocation > 0){
|
||||
new BufferedRandomAccessFile(getThreadConfig().tempFile, "rwd",
|
||||
getTaskConfig().getBuffSize());
|
||||
if (getThreadRecord().startLocation > 0) {
|
||||
file.seek(getThreadRecord().startLocation);
|
||||
}
|
||||
byte[] buffer = new byte[getTaskConfig().getBuffSize()];
|
||||
@@ -203,7 +203,7 @@ final class FtpDThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
fail(new AriaIOException(TAG, String.format("下载失败【%s】", getThreadConfig().url), e), true);
|
||||
fail(new AriaFTPException(TAG, String.format("下载失败【%s】", getThreadConfig().url), e), true);
|
||||
} finally {
|
||||
try {
|
||||
if (file != null) {
|
||||
|
||||
@@ -26,7 +26,7 @@ import com.arialyy.aria.core.loader.NormalLoader;
|
||||
import com.arialyy.aria.core.manager.ThreadTaskManager;
|
||||
import com.arialyy.aria.core.task.IThreadTask;
|
||||
import com.arialyy.aria.core.upload.UTaskWrapper;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
|
||||
final class FtpULoader extends NormalLoader<UTaskWrapper> {
|
||||
private FTPFile ftpFile;
|
||||
@@ -37,6 +37,9 @@ final class FtpULoader extends NormalLoader<UTaskWrapper> {
|
||||
|
||||
@Override
|
||||
protected void startThreadTask() {
|
||||
if (isBreak()) {
|
||||
return;
|
||||
}
|
||||
// 检查记录
|
||||
((FtpURecordHandler) mRecordHandler).setFtpFile(ftpFile);
|
||||
if (mRecordHandler.checkTaskCompleted()) {
|
||||
@@ -79,7 +82,7 @@ final class FtpULoader extends NormalLoader<UTaskWrapper> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
|
||||
@Override public void onFail(AbsEntity entity, AriaException e, boolean needRetry) {
|
||||
getListener().onFail(needRetry, e);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ import aria.apache.commons.net.ftp.FTPReply;
|
||||
import aria.apache.commons.net.ftp.OnFtpInputStreamListener;
|
||||
import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.exception.AriaIOException;
|
||||
import com.arialyy.aria.exception.AriaFTPException;
|
||||
import com.arialyy.aria.ftp.BaseFtpThreadTaskAdapter;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
||||
@@ -58,12 +58,16 @@ final class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
return;
|
||||
}
|
||||
initPath();
|
||||
client.makeDirectory(dir);
|
||||
boolean b = client.makeDirectory(dir);
|
||||
if (!b) {
|
||||
ALog.w(TAG, String.format("创建目录失败,错误码为:%s, msg:%s", client.getReplyCode(),
|
||||
client.getReplyString()));
|
||||
}
|
||||
client.changeWorkingDirectory(dir);
|
||||
client.setRestartOffset(getThreadRecord().startLocation);
|
||||
int reply = client.getReplyCode();
|
||||
if (!FTPReply.isPositivePreliminary(reply) && reply != FTPReply.FILE_ACTION_OK) {
|
||||
fail(new AriaIOException(TAG,
|
||||
fail(new AriaFTPException(TAG,
|
||||
String.format("文件上传错误,错误码为:%s, msg:%s, filePath: %s", reply,
|
||||
client.getReplyString(), getEntity().getFilePath())), false);
|
||||
client.disconnect();
|
||||
@@ -80,8 +84,8 @@ final class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
if (getThreadTask().isBreak()) {
|
||||
return;
|
||||
}
|
||||
if (!complete){
|
||||
fail(new AriaIOException(TAG, "ftp文件上传失败"), false);
|
||||
if (!complete) {
|
||||
fail(new AriaFTPException(TAG, "ftp文件上传失败"), false);
|
||||
return;
|
||||
}
|
||||
ALog.i(TAG,
|
||||
@@ -89,11 +93,11 @@ final class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
complete();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail(new AriaIOException(TAG,
|
||||
fail(new AriaFTPException(TAG,
|
||||
String.format("上传失败,filePath: %s, uploadUrl: %s", getEntity().getFilePath(),
|
||||
getThreadConfig().url)), true);
|
||||
} catch (Exception e) {
|
||||
fail(new AriaIOException(TAG, null, e), false);
|
||||
fail(new AriaFTPException(TAG, null, e), false);
|
||||
} finally {
|
||||
try {
|
||||
if (file != null) {
|
||||
@@ -132,7 +136,7 @@ final class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
@Override public void run() {
|
||||
try {
|
||||
if (isTimeOut) {
|
||||
fail(new AriaIOException(TAG, "socket连接失败,该问题一般出现于网络断开,客户端重新连接,"
|
||||
fail(new AriaFTPException(TAG, "socket连接失败,该问题一般出现于网络断开,客户端重新连接,"
|
||||
+ "但是服务器端无法创建socket缺没有返回错误码的情况。"), false);
|
||||
if (fa != null) {
|
||||
fa.close();
|
||||
@@ -195,7 +199,7 @@ final class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
if (e.getMessage().contains("AriaIOException caught while copying")) {
|
||||
e.printStackTrace();
|
||||
} else {
|
||||
fail(new AriaIOException(TAG, msg, e), !storeSuccess);
|
||||
fail(new AriaFTPException(TAG, msg, e), !storeSuccess);
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
@@ -204,7 +208,7 @@ final class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
int reply = client.getReplyCode();
|
||||
if (!FTPReply.isPositiveCompletion(reply)) {
|
||||
if (reply != FTPReply.TRANSFER_ABORTED) {
|
||||
fail(new AriaIOException(TAG,
|
||||
fail(new AriaFTPException(TAG,
|
||||
String.format("文件上传错误,错误码为:%s, msg:%s, filePath: %s", reply, client.getReplyString(),
|
||||
getEntity().getFilePath())), false);
|
||||
}
|
||||
|
||||
@@ -36,13 +36,6 @@ public final class HttpRecordHandler extends RecordHandler {
|
||||
super(wrapper);
|
||||
}
|
||||
|
||||
@Override public void onPre() {
|
||||
super.onPre();
|
||||
//if (getWrapper().getRequestType() == ITaskWrapper.U_HTTP) {
|
||||
// RecordUtil.delTaskRecord(getEntity().getFilePath(), IRecordHandler.TYPE_UPLOAD);
|
||||
//}
|
||||
}
|
||||
|
||||
@Override public void handlerTaskRecord(TaskRecord record) {
|
||||
RecordHelper helper = new RecordHelper(getWrapper(), record);
|
||||
if (getWrapper().isSupportBP() && record.threadNum > 1) {
|
||||
|
||||
@@ -20,6 +20,8 @@ import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.common.RequestEnum;
|
||||
import com.arialyy.aria.core.inf.ITaskOption;
|
||||
import com.arialyy.aria.core.processor.IHttpFileLenAdapter;
|
||||
import com.arialyy.aria.core.processor.IHttpFileNameAdapter;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.net.CookieManager;
|
||||
import java.net.Proxy;
|
||||
@@ -81,17 +83,23 @@ public final class HttpTaskOption implements ITaskOption {
|
||||
|
||||
private SoftReference<IHttpFileLenAdapter> fileLenAdapter;
|
||||
|
||||
private SoftReference<IHttpFileNameAdapter> fileNameAdapter;
|
||||
|
||||
public IHttpFileLenAdapter getFileLenAdapter() {
|
||||
return fileLenAdapter == null ? null : fileLenAdapter.get();
|
||||
}
|
||||
|
||||
public IHttpFileNameAdapter getFileNameAdapter() {
|
||||
return fileNameAdapter == null ? null : fileNameAdapter.get();
|
||||
}
|
||||
/**
|
||||
* 如果是匿名内部类,完成后需要将adapter设置为空,否则会出现内存泄漏
|
||||
*/
|
||||
public void setFileLenAdapter(IHttpFileLenAdapter fileLenAdapter) {
|
||||
this.fileLenAdapter = new SoftReference<>(fileLenAdapter);
|
||||
}
|
||||
|
||||
public void setFileNameAdapter(IHttpFileNameAdapter fileNameAdapter) {
|
||||
this.fileNameAdapter = new SoftReference<>(fileNameAdapter);
|
||||
}
|
||||
public Map<String, String> getFormFields() {
|
||||
return formFields;
|
||||
}
|
||||
@@ -179,4 +187,5 @@ public final class HttpTaskOption implements ITaskOption {
|
||||
public void setParams(Map<String, String> params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,9 +27,7 @@ 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.AriaIOException;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.TaskException;
|
||||
import com.arialyy.aria.exception.AriaHTTPException;
|
||||
import com.arialyy.aria.http.ConnectionHelp;
|
||||
import com.arialyy.aria.http.HttpTaskOption;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
@@ -40,6 +38,7 @@ 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;
|
||||
@@ -58,7 +57,7 @@ import java.util.UUID;
|
||||
* 下载文件信息获取
|
||||
*/
|
||||
final class HttpDFileInfoTask implements IInfoTask, Runnable {
|
||||
private static final String TAG = "HttpFileInfoThread";
|
||||
private static final String TAG = "HttpDFileInfoTask";
|
||||
private DownloadEntity mEntity;
|
||||
private DTaskWrapper mTaskWrapper;
|
||||
private int mConnectTimeOut;
|
||||
@@ -85,14 +84,16 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
|
||||
conn.connect();
|
||||
handleConnect(conn);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
failDownload(new AriaIOException(TAG,
|
||||
String.format("下载失败,filePath: %s, url: %s", mEntity.getFilePath(), mEntity.getUrl())),
|
||||
true);
|
||||
failDownload(new AriaHTTPException(TAG,
|
||||
String.format("下载失败,filePath: %s, url: %s", mEntity.getFilePath(), mEntity.getUrl()),
|
||||
e), true);
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
try {
|
||||
conn.getInputStream().close();
|
||||
InputStream is = conn.getInputStream();
|
||||
if (is != null) {
|
||||
is.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -132,7 +133,7 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
|
||||
long len = lenAdapter.handleFileLen(conn.getHeaderFields());
|
||||
|
||||
if (!FileUtil.checkMemorySpace(mEntity.getFilePath(), len)) {
|
||||
failDownload(new TaskException(TAG,
|
||||
failDownload(new AriaHTTPException(TAG,
|
||||
String.format("下载失败,内存空间不足;filePath: %s, url: %s", mEntity.getFilePath(),
|
||||
mEntity.getUrl())), false);
|
||||
return;
|
||||
@@ -158,9 +159,15 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
|
||||
mEntity.setDisposition(CommonUtil.encryptBASE64(disposition));
|
||||
handleContentDisposition(disposition);
|
||||
} else {
|
||||
ALog.w(TAG, "Content-Disposition对于端字段为空,使用服务器端文件名失败");
|
||||
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");
|
||||
|
||||
@@ -176,7 +183,8 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
|
||||
if (!checkLen(len) && !isChunked) {
|
||||
if (len < 0) {
|
||||
failDownload(
|
||||
new AriaIOException(TAG, String.format("任务下载失败,文件长度小于0, url: %s", mEntity.getUrl())),
|
||||
new AriaHTTPException(TAG,
|
||||
String.format("任务下载失败,文件长度小于0, url: %s", mEntity.getUrl())),
|
||||
false);
|
||||
}
|
||||
return;
|
||||
@@ -203,7 +211,8 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
|
||||
} else if (!checkLen(len) && !isChunked) {
|
||||
if (len < 0) {
|
||||
failDownload(
|
||||
new AriaIOException(TAG, String.format("任务下载失败,文件长度小于0, url: %s", mEntity.getUrl())),
|
||||
new AriaHTTPException(TAG,
|
||||
String.format("任务下载失败,文件长度小于0, url: %s", mEntity.getUrl())),
|
||||
false);
|
||||
}
|
||||
ALog.d(TAG, "len < 0");
|
||||
@@ -213,17 +222,17 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
|
||||
mTaskWrapper.setNewTask(true);
|
||||
mTaskWrapper.setSupportBP(false);
|
||||
end = true;
|
||||
} else if (code == HttpURLConnection.HTTP_NOT_FOUND) {
|
||||
failDownload(new AriaIOException(TAG,
|
||||
String.format("任务下载失败,errorCode:404, url: %s", mEntity.getUrl())), 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 >= HttpURLConnection.HTTP_BAD_REQUEST) {
|
||||
failDownload(new AriaHTTPException(TAG,
|
||||
String.format("任务下载失败,errorCode:%s, url: %s", code, mEntity.getUrl())), false);
|
||||
} else {
|
||||
failDownload(new AriaIOException(TAG,
|
||||
failDownload(new AriaHTTPException(TAG,
|
||||
String.format("任务下载失败,errorCode:%s, errorMsg: %s, url: %s", code,
|
||||
conn.getResponseMessage(), mEntity.getUrl())), !CheckUtil.httpIsBadRequest(code));
|
||||
}
|
||||
@@ -282,6 +291,10 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
|
||||
ALog.d(TAG, String.format("文件重命名为:%s", newName));
|
||||
File oldFile = new File(mEntity.getFilePath());
|
||||
String newPath = oldFile.getParent() + "/" + newName;
|
||||
if (!CheckUtil.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 ? "成功" : "失败"));
|
||||
@@ -298,7 +311,7 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
|
||||
ALog.d(TAG, "30x跳转,新url为【" + newUrl + "】");
|
||||
if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null")) {
|
||||
if (callback != null) {
|
||||
callback.onFail(mEntity, new TaskException(TAG, "获取重定向链接失败"), false);
|
||||
callback.onFail(mEntity, new AriaHTTPException(TAG, "获取重定向链接失败"), false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -308,7 +321,7 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
|
||||
}
|
||||
|
||||
if (!CheckUtil.checkUrl(newUrl)) {
|
||||
failDownload(new TaskException(TAG, "下载失败,重定向url错误"), false);
|
||||
failDownload(new AriaHTTPException(TAG, "下载失败,重定向url错误"), false);
|
||||
return;
|
||||
}
|
||||
taskOption.setRedirectUrl(newUrl);
|
||||
@@ -341,7 +354,7 @@ final class HttpDFileInfoTask implements IInfoTask, Runnable {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void failDownload(BaseException e, boolean needRetry) {
|
||||
private void failDownload(AriaHTTPException e, boolean needRetry) {
|
||||
if (callback != null) {
|
||||
callback.onFail(mEntity, e, needRetry);
|
||||
}
|
||||
|
||||
@@ -23,13 +23,14 @@ import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.listener.DownloadGroupListener;
|
||||
import com.arialyy.aria.core.loader.IInfoTask;
|
||||
import com.arialyy.aria.core.loader.ILoaderVisitor;
|
||||
import com.arialyy.aria.exception.AriaIOException;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.exception.AriaHTTPException;
|
||||
import com.arialyy.aria.http.HttpTaskOption;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* 组合任务文件信息,用于获取长度未知时,组合任务的长度
|
||||
@@ -41,8 +42,8 @@ public final class HttpDGInfoTask implements IInfoTask {
|
||||
private final Object LOCK = new Object();
|
||||
private ExecutorService mPool = null;
|
||||
private boolean getLenComplete = false;
|
||||
private int count;
|
||||
private int failCount;
|
||||
private AtomicInteger count = new AtomicInteger();
|
||||
private AtomicInteger failCount = new AtomicInteger();
|
||||
private DownloadGroupListener listener;
|
||||
|
||||
/**
|
||||
@@ -50,18 +51,18 @@ public final class HttpDGInfoTask implements IInfoTask {
|
||||
*/
|
||||
private Callback subCallback = new Callback() {
|
||||
@Override public void onSucceed(String url, CompleteInfo info) {
|
||||
count++;
|
||||
checkGetSizeComplete(count, failCount);
|
||||
count.getAndIncrement();
|
||||
checkGetSizeComplete(count.get(), failCount.get());
|
||||
ALog.d(TAG, "获取子任务信息完成");
|
||||
}
|
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
|
||||
@Override public void onFail(AbsEntity entity, AriaException e, boolean needRetry) {
|
||||
ALog.e(TAG, String.format("获取文件信息失败,url:%s", ((DownloadEntity) entity).getUrl()));
|
||||
count++;
|
||||
failCount++;
|
||||
listener.onSubFail((DownloadEntity) entity, new AriaIOException(TAG,
|
||||
count.getAndIncrement();
|
||||
failCount.getAndIncrement();
|
||||
listener.onSubFail((DownloadEntity) entity, new AriaHTTPException(TAG,
|
||||
String.format("子任务获取文件长度失败,url:%s", ((DownloadEntity) entity).getUrl())));
|
||||
checkGetSizeComplete(count, failCount);
|
||||
checkGetSizeComplete(count.get(), failCount.get());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -79,7 +80,7 @@ public final class HttpDGInfoTask implements IInfoTask {
|
||||
return;
|
||||
}
|
||||
// 处理组合任务大小未知的情况
|
||||
if (wrapper.isUnknownSize() && wrapper.getEntity().getFileSize() < 1) {
|
||||
if (wrapper.isUnknownSize()) {
|
||||
mPool = Executors.newCachedThreadPool();
|
||||
getGroupSize();
|
||||
try {
|
||||
@@ -89,7 +90,7 @@ public final class HttpDGInfoTask implements IInfoTask {
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (!mPool.isShutdown()){
|
||||
if (!mPool.isShutdown()) {
|
||||
mPool.shutdown();
|
||||
}
|
||||
} else {
|
||||
@@ -107,6 +108,16 @@ public final class HttpDGInfoTask implements IInfoTask {
|
||||
new Thread(new Runnable() {
|
||||
@Override public void run() {
|
||||
for (DTaskWrapper dTaskWrapper : wrapper.getSubTaskWrapper()) {
|
||||
DownloadEntity subEntity = dTaskWrapper.getEntity();
|
||||
if (subEntity.getFileSize() > 0) {
|
||||
count.getAndIncrement();
|
||||
if (subEntity.getCurrentProgress() < subEntity.getFileSize()){
|
||||
// 如果没有完成需要拷贝一份数据
|
||||
cloneHeader(dTaskWrapper);
|
||||
}
|
||||
checkGetSizeComplete(count.get(), failCount.get());
|
||||
continue;
|
||||
}
|
||||
cloneHeader(dTaskWrapper);
|
||||
HttpDFileInfoTask infoTask = new HttpDFileInfoTask(dTaskWrapper);
|
||||
infoTask.setCallback(subCallback);
|
||||
@@ -121,7 +132,7 @@ public final class HttpDGInfoTask implements IInfoTask {
|
||||
*/
|
||||
private void checkGetSizeComplete(int count, int failCount) {
|
||||
if (failCount == wrapper.getSubTaskWrapper().size()) {
|
||||
callback.onFail(wrapper.getEntity(), new AriaIOException(TAG, "获取子任务长度失败"), false);
|
||||
callback.onFail(wrapper.getEntity(), new AriaHTTPException(TAG, "获取子任务长度失败"), false);
|
||||
notifyLock();
|
||||
return;
|
||||
}
|
||||
@@ -155,6 +166,10 @@ public final class HttpDGInfoTask implements IInfoTask {
|
||||
|
||||
// 设置属性
|
||||
subOption.setFileLenAdapter(groupOption.getFileLenAdapter());
|
||||
subOption.setFileNameAdapter(groupOption.getFileNameAdapter());
|
||||
subOption.setUseServerFileName(groupOption.isUseServerFileName());
|
||||
|
||||
subOption.setFileNameAdapter(groupOption.getFileNameAdapter());
|
||||
subOption.setRequestEnum(groupOption.getRequestEnum());
|
||||
subOption.setHeaders(groupOption.getHeaders());
|
||||
subOption.setProxy(groupOption.getProxy());
|
||||
|
||||
@@ -25,7 +25,8 @@ import com.arialyy.aria.core.group.AbsSubDLoadUtil;
|
||||
import com.arialyy.aria.core.listener.DownloadGroupListener;
|
||||
import com.arialyy.aria.core.loader.IInfoTask;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* http 组合任务加载器
|
||||
@@ -54,6 +55,7 @@ final class HttpDGLoader extends AbsGroupLoader {
|
||||
onPostStart();
|
||||
for (DTaskWrapper wrapper : getWrapper().getSubTaskWrapper()) {
|
||||
DownloadEntity dEntity = wrapper.getEntity();
|
||||
|
||||
startSubLoader(createSubLoader(wrapper, dEntity.getFileSize() < 0));
|
||||
}
|
||||
}
|
||||
@@ -65,7 +67,7 @@ final class HttpDGLoader extends AbsGroupLoader {
|
||||
startSub();
|
||||
}
|
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
|
||||
@Override public void onFail(AbsEntity entity, AriaException e, boolean needRetry) {
|
||||
fail(e, needRetry);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -15,27 +15,17 @@
|
||||
*/
|
||||
package com.arialyy.aria.http.download;
|
||||
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.core.loader.AbsNormalLoader;
|
||||
import com.arialyy.aria.core.loader.AbsNormalLoaderUtil;
|
||||
import com.arialyy.aria.core.loader.AbsNormalTTBuilderAdapter;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
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.NormalThreadStateManager;
|
||||
import com.arialyy.aria.core.task.IThreadTaskAdapter;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.http.HttpRecordHandler;
|
||||
import com.arialyy.aria.http.HttpTaskOption;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
@@ -60,6 +50,4 @@ public final class HttpDLoaderUtil extends AbsNormalLoaderUtil {
|
||||
structure.accept(getLoader());
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -18,8 +18,7 @@ package com.arialyy.aria.http.download;
|
||||
import com.arialyy.aria.core.common.RequestEnum;
|
||||
import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.exception.AriaIOException;
|
||||
import com.arialyy.aria.exception.TaskException;
|
||||
import com.arialyy.aria.exception.AriaHTTPException;
|
||||
import com.arialyy.aria.http.BaseHttpThreadTaskAdapter;
|
||||
import com.arialyy.aria.http.ConnectionHelp;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
@@ -44,7 +43,7 @@ import java.util.Set;
|
||||
* Created by lyy on 2017/1/18. 下载线程
|
||||
*/
|
||||
final class HttpDThreadTaskAdapter extends BaseHttpThreadTaskAdapter {
|
||||
private final String TAG = "HttpThreadTask";
|
||||
private final String TAG = "HttpDThreadTaskAdapter";
|
||||
private DTaskWrapper mTaskWrapper;
|
||||
|
||||
HttpDThreadTaskAdapter(SubThreadConfig config) {
|
||||
@@ -60,10 +59,6 @@ final class HttpDThreadTaskAdapter extends BaseHttpThreadTaskAdapter {
|
||||
HttpURLConnection conn = null;
|
||||
BufferedInputStream is = null;
|
||||
BufferedRandomAccessFile file = null;
|
||||
if (getThreadRecord().threadId == 1){
|
||||
fail(null, false);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
URL url = ConnectionHelp.handleUrl(getThreadConfig().url, mTaskOption);
|
||||
conn = ConnectionHelp.handleConnection(url, mTaskOption);
|
||||
@@ -122,19 +117,19 @@ final class HttpDThreadTaskAdapter extends BaseHttpThreadTaskAdapter {
|
||||
handleComplete();
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
fail(new TaskException(TAG,
|
||||
fail(new AriaHTTPException(TAG,
|
||||
String.format("任务【%s】下载失败,filePath: %s, url: %s", getFileName(),
|
||||
getEntity().getFilePath(), getEntity().getUrl()), e), false);
|
||||
} catch (IOException e) {
|
||||
fail(new TaskException(TAG,
|
||||
fail(new AriaHTTPException(TAG,
|
||||
String.format("任务【%s】下载失败,filePath: %s, url: %s", getFileName(),
|
||||
getEntity().getFilePath(), getEntity().getUrl()), e), true);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
fail(new TaskException(TAG,
|
||||
fail(new AriaHTTPException(TAG,
|
||||
String.format("任务【%s】下载失败,filePath: %s, url: %s", getFileName(),
|
||||
getEntity().getFilePath(), getEntity().getUrl()), e), false);
|
||||
} catch (Exception e) {
|
||||
fail(new TaskException(TAG,
|
||||
fail(new AriaHTTPException(TAG,
|
||||
String.format("任务【%s】下载失败,filePath: %s, url: %s", getFileName(),
|
||||
getEntity().getFilePath(), getEntity().getUrl()), e), false);
|
||||
} finally {
|
||||
@@ -176,9 +171,9 @@ final class HttpDThreadTaskAdapter extends BaseHttpThreadTaskAdapter {
|
||||
}
|
||||
handleComplete();
|
||||
} catch (IOException e) {
|
||||
fail(new AriaIOException(TAG,
|
||||
fail(new AriaHTTPException(TAG,
|
||||
String.format("文件下载失败,savePath: %s, url: %s", getEntity().getFilePath(),
|
||||
getThreadConfig().url)), true);
|
||||
getThreadConfig().url), e), true);
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
try {
|
||||
@@ -229,7 +224,7 @@ final class HttpDThreadTaskAdapter extends BaseHttpThreadTaskAdapter {
|
||||
}
|
||||
handleComplete();
|
||||
} catch (IOException e) {
|
||||
fail(new AriaIOException(TAG,
|
||||
fail(new AriaHTTPException(TAG,
|
||||
String.format("文件下载失败,savePath: %s, url: %s", getEntity().getFilePath(),
|
||||
getThreadConfig().url), e), true);
|
||||
} finally {
|
||||
|
||||
@@ -19,6 +19,7 @@ import android.os.Handler;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.group.AbsSubDLoadUtil;
|
||||
import com.arialyy.aria.core.group.SubRecordHandler;
|
||||
import com.arialyy.aria.core.loader.GroupSubThreadStateManager;
|
||||
import com.arialyy.aria.core.loader.LoaderStructure;
|
||||
import com.arialyy.aria.core.loader.NormalTTBuilder;
|
||||
import com.arialyy.aria.core.loader.SubLoader;
|
||||
@@ -49,8 +50,9 @@ final class HttpSubDLoaderUtil extends AbsSubDLoadUtil {
|
||||
@Override protected LoaderStructure buildLoaderStructure() {
|
||||
LoaderStructure structure = new LoaderStructure();
|
||||
structure.addComponent(new SubRecordHandler(getWrapper()))
|
||||
.addComponent(new NormalTTBuilder(getWrapper(), new HttpDTTBuilderAdapter()))
|
||||
.addComponent(new HttpDFileInfoTask(getWrapper()));
|
||||
.addComponent(new GroupSubThreadStateManager(getSchedulers(),getKey()))
|
||||
.addComponent(new NormalTTBuilder(getWrapper(), new HttpDTTBuilderAdapter()))
|
||||
.addComponent(new HttpDFileInfoTask(getWrapper()));
|
||||
structure.accept(getLoader());
|
||||
return structure;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import com.arialyy.aria.core.loader.IThreadTaskBuilder;
|
||||
import com.arialyy.aria.core.manager.ThreadTaskManager;
|
||||
import com.arialyy.aria.core.task.IThreadTask;
|
||||
import com.arialyy.aria.core.upload.UTaskWrapper;
|
||||
import com.arialyy.aria.exception.AriaIOException;
|
||||
import com.arialyy.aria.exception.AriaHTTPException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import java.util.List;
|
||||
|
||||
@@ -62,7 +62,7 @@ final class HttpULoader extends AbsNormalLoader<UTaskWrapper> {
|
||||
new Handler(looper, mStateManager.getHandlerCallback()));
|
||||
if (tt == null || tt.isEmpty()) {
|
||||
ALog.e(TAG, "创建线程任务失败");
|
||||
getListener().onFail(false, new AriaIOException(TAG, "创建线程任务失败"));
|
||||
getListener().onFail(false, new AriaHTTPException(TAG, "创建线程任务失败"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,7 @@ package com.arialyy.aria.http.upload;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.exception.AriaIOException;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.TaskException;
|
||||
import com.arialyy.aria.exception.AriaHTTPException;
|
||||
import com.arialyy.aria.http.BaseHttpThreadTaskAdapter;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
@@ -56,7 +54,7 @@ final class HttpUThreadTaskAdapter extends BaseHttpThreadTaskAdapter {
|
||||
@Override protected void handlerThreadTask() {
|
||||
File uploadFile = new File(getEntity().getFilePath());
|
||||
if (!uploadFile.exists()) {
|
||||
fail(new TaskException(TAG,
|
||||
fail(new AriaHTTPException(TAG,
|
||||
String.format("上传失败,文件不存在;filePath: %s, url: %s", getEntity().getFilePath(),
|
||||
getEntity().getUrl())));
|
||||
return;
|
||||
@@ -106,13 +104,13 @@ final class HttpUThreadTaskAdapter extends BaseHttpThreadTaskAdapter {
|
||||
getEntity().setResponseStr(finish(writer));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail(new TaskException(TAG,
|
||||
fail(new AriaHTTPException(TAG,
|
||||
String.format("上传失败,filePath: %s, url: %s", getEntity().getFilePath(),
|
||||
getEntity().getUrl()), e));
|
||||
}
|
||||
}
|
||||
|
||||
private void fail(BaseException e1) {
|
||||
private void fail(AriaHTTPException e1) {
|
||||
try {
|
||||
fail(e1, false);
|
||||
if (mOutputStream != null) {
|
||||
@@ -222,7 +220,7 @@ final class HttpUThreadTaskAdapter extends BaseHttpThreadTaskAdapter {
|
||||
} else {
|
||||
String msg = "response msg: " + mHttpConn.getResponseMessage() + ",code: " + status;
|
||||
ALog.e(TAG, msg);
|
||||
fail(new AriaIOException(TAG, msg), false);
|
||||
fail(new AriaHTTPException(TAG, msg), false);
|
||||
}
|
||||
writer.flush();
|
||||
writer.close();
|
||||
|
||||
@@ -13,12 +13,17 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.exception;
|
||||
package com.arialyy.aria.m3u8;
|
||||
|
||||
public class ParamException extends RuntimeException {
|
||||
private static final String ARIA_NET_EXCEPTION = "Aria Params Exception:";
|
||||
import com.arialyy.aria.core.processor.IBandWidthUrlConverter;
|
||||
|
||||
public ParamException(String message) {
|
||||
super(String.format("%s%s", ARIA_NET_EXCEPTION, message));
|
||||
/**
|
||||
* 点播文件默认的码率转换器
|
||||
*/
|
||||
class BandWidthDefConverter implements IBandWidthUrlConverter {
|
||||
|
||||
@Override public String convert(String m3u8Url, String bandWidthUrl) {
|
||||
int index = m3u8Url.lastIndexOf("/");
|
||||
return m3u8Url.substring(0, index + 1) + bandWidthUrl;
|
||||
}
|
||||
}
|
||||
@@ -30,8 +30,7 @@ import com.arialyy.aria.core.processor.IBandWidthUrlConverter;
|
||||
import com.arialyy.aria.core.processor.IKeyUrlConverter;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.exception.M3U8Exception;
|
||||
import com.arialyy.aria.exception.TaskException;
|
||||
import com.arialyy.aria.exception.AriaM3U8Exception;
|
||||
import com.arialyy.aria.http.ConnectionHelp;
|
||||
import com.arialyy.aria.http.HttpTaskOption;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
@@ -177,7 +176,7 @@ final public class M3U8InfoTask implements IInfoTask {
|
||||
} else if (bandWidth == setBand) {
|
||||
handleBandWidth(conn, reader.readLine());
|
||||
} else {
|
||||
failDownload(String.format("【%s】码率不存在", bandWidth), false);
|
||||
failDownload(String.format("【%s】码率不存在", setBand), false);
|
||||
}
|
||||
return;
|
||||
} else if (line.startsWith("#EXT-X-KEY")) {
|
||||
@@ -209,8 +208,8 @@ final public class M3U8InfoTask implements IInfoTask {
|
||||
|| code == HttpURLConnection.HTTP_CREATED // 201 跳转
|
||||
|| code == 307) {
|
||||
handleUrlReTurn(conn, conn.getHeaderField("Location"));
|
||||
} else if (code == HttpURLConnection.HTTP_NOT_FOUND) {
|
||||
failDownload("404错误", false);
|
||||
} else if (code >= HttpURLConnection.HTTP_BAD_REQUEST) {
|
||||
failDownload("下载失败错误,错误码:" + code, false);
|
||||
} else {
|
||||
failDownload(String.format("不支持的响应,code: %s", code), true);
|
||||
}
|
||||
@@ -296,7 +295,7 @@ final public class M3U8InfoTask implements IInfoTask {
|
||||
ALog.d(TAG, "30x跳转,新url为【" + newUrl + "】");
|
||||
if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null")) {
|
||||
if (mCallback != null) {
|
||||
mCallback.onFail(mEntity, new TaskException(TAG, "获取重定向链接失败"), false);
|
||||
mCallback.onFail(mEntity, new AriaM3U8Exception(TAG, "获取重定向链接失败"), false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -329,9 +328,10 @@ final public class M3U8InfoTask implements IInfoTask {
|
||||
* 处理码率
|
||||
*/
|
||||
private void handleBandWidth(HttpURLConnection conn, String bandWidthM3u8Url) throws IOException {
|
||||
IBandWidthUrlConverter converter = mM3U8Option.getBandWidthUrlConverter();
|
||||
IBandWidthUrlConverter converter = mM3U8Option.isUseDefConvert() ? new BandWidthDefConverter()
|
||||
: mM3U8Option.getBandWidthUrlConverter();
|
||||
if (converter != null) {
|
||||
bandWidthM3u8Url = converter.convert(bandWidthM3u8Url);
|
||||
bandWidthM3u8Url = converter.convert(mEntity.getUrl(), bandWidthM3u8Url);
|
||||
if (!bandWidthM3u8Url.startsWith("http")) {
|
||||
failDownload(String.format("码率转换器转换后的url地址无效,转换后的url:%s", bandWidthM3u8Url), false);
|
||||
return;
|
||||
@@ -354,7 +354,7 @@ final public class M3U8InfoTask implements IInfoTask {
|
||||
}
|
||||
|
||||
private void failDownload(String errorInfo, boolean needRetry) {
|
||||
mCallback.onFail(mEntity, new M3U8Exception(TAG, errorInfo), needRetry);
|
||||
mCallback.onFail(mEntity, new AriaM3U8Exception(TAG, errorInfo), needRetry);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,17 +19,22 @@ import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.listener.BaseDListener;
|
||||
import com.arialyy.aria.core.inf.TaskSchedulerType;
|
||||
import com.arialyy.aria.core.listener.BaseListener;
|
||||
import com.arialyy.aria.core.listener.IDLoadListener;
|
||||
import com.arialyy.aria.core.listener.ISchedulers;
|
||||
import com.arialyy.aria.core.task.AbsTask;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.DeleteM3u8Record;
|
||||
|
||||
/**
|
||||
* 下载监听类
|
||||
*/
|
||||
public final class M3U8Listener extends BaseDListener implements IDLoadListener {
|
||||
public final class M3U8Listener
|
||||
extends BaseListener<DownloadEntity, DTaskWrapper, AbsTask<DTaskWrapper>>
|
||||
implements IDLoadListener {
|
||||
|
||||
public M3U8Listener(AbsTask<DTaskWrapper> task, Handler outHandler) {
|
||||
super(task, outHandler);
|
||||
@@ -43,6 +48,12 @@ public final class M3U8Listener extends BaseDListener implements IDLoadListener
|
||||
sendInState2Target(ISchedulers.POST_PRE);
|
||||
}
|
||||
|
||||
@Override public void supportBreakpoint(boolean support) {
|
||||
if (!support) {
|
||||
sendInState2Target(ISchedulers.NO_SUPPORT_BREAK_POINT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 切片开始下载
|
||||
*/
|
||||
@@ -75,4 +86,15 @@ public final class M3U8Listener extends BaseDListener implements IDLoadListener
|
||||
msg.arg1 = ISchedulers.IS_M3U8_PEER;
|
||||
msg.sendToTarget();
|
||||
}
|
||||
|
||||
@Override protected void handleCancel() {
|
||||
int sType = getTask().getSchedulerType();
|
||||
if (sType == TaskSchedulerType.TYPE_CANCEL_AND_NOT_NOTIFY) {
|
||||
mEntity.setComplete(false);
|
||||
mEntity.setState(IEntity.STATE_WAIT);
|
||||
DeleteM3u8Record.getInstance().deleteRecord(mEntity, mTaskWrapper.isRemoveFile(), false);
|
||||
} else {
|
||||
DeleteM3u8Record.getInstance().deleteRecord(mEntity, mTaskWrapper.isRemoveFile(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,6 +120,19 @@ public final class M3U8TaskOption implements ITaskOption {
|
||||
*/
|
||||
private String keyPath;
|
||||
|
||||
/**
|
||||
* 是否使用默认的码率转换器和Ts转换器
|
||||
*/
|
||||
private boolean useDefConvert = false;
|
||||
|
||||
public boolean isUseDefConvert() {
|
||||
return useDefConvert;
|
||||
}
|
||||
|
||||
public void setUseDefConvert(boolean useDefConvert) {
|
||||
this.useDefConvert = useDefConvert;
|
||||
}
|
||||
|
||||
public String getKeyPath() {
|
||||
return keyPath;
|
||||
}
|
||||
|
||||
@@ -21,8 +21,7 @@ import com.arialyy.aria.core.common.RequestEnum;
|
||||
import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.task.AbsThreadTaskAdapter;
|
||||
import com.arialyy.aria.exception.AriaIOException;
|
||||
import com.arialyy.aria.exception.TaskException;
|
||||
import com.arialyy.aria.exception.AriaM3U8Exception;
|
||||
import com.arialyy.aria.http.ConnectionHelp;
|
||||
import com.arialyy.aria.http.HttpTaskOption;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
@@ -92,15 +91,15 @@ public final class M3U8ThreadTaskAdapter extends AbsThreadTaskAdapter {
|
||||
|
||||
handleConn(conn);
|
||||
} catch (MalformedURLException e) {
|
||||
fail(new TaskException(TAG,
|
||||
fail(new AriaM3U8Exception(TAG,
|
||||
String.format("分片【%s】下载失败,filePath: %s, url: %s", getThreadRecord().threadId,
|
||||
getThreadConfig().tempFile.getPath(), getEntity().getUrl()), e), false);
|
||||
} catch (IOException e) {
|
||||
fail(new TaskException(TAG,
|
||||
fail(new AriaM3U8Exception(TAG,
|
||||
String.format("分片【%s】下载失败,filePath: %s, url: %s", getThreadRecord().threadId,
|
||||
getThreadConfig().tempFile.getPath(), getEntity().getUrl()), e), true);
|
||||
} catch (Exception e) {
|
||||
fail(new TaskException(TAG,
|
||||
fail(new AriaM3U8Exception(TAG,
|
||||
String.format("分片【%s】下载失败,filePath: %s, url: %s", getThreadRecord().threadId,
|
||||
getThreadConfig().tempFile.getPath(), getEntity().getUrl()), e), false);
|
||||
} finally {
|
||||
@@ -138,7 +137,7 @@ public final class M3U8ThreadTaskAdapter extends AbsThreadTaskAdapter {
|
||||
|| code == 307) {
|
||||
handleUrlReTurn(conn, conn.getHeaderField("Location"));
|
||||
} else {
|
||||
fail(new TaskException(TAG,
|
||||
fail(new AriaM3U8Exception(TAG,
|
||||
String.format("连接错误,http错误码:%s,url:%s", code, getThreadConfig().url)),
|
||||
false);
|
||||
}
|
||||
@@ -151,7 +150,7 @@ public final class M3U8ThreadTaskAdapter extends AbsThreadTaskAdapter {
|
||||
private void handleUrlReTurn(HttpURLConnection conn, String newUrl) throws IOException {
|
||||
ALog.d(TAG, "30x跳转,新url为【" + newUrl + "】");
|
||||
if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null")) {
|
||||
fail(new AriaIOException(TAG, "下载失败,重定向url为空"), false);
|
||||
fail(new AriaM3U8Exception(TAG, "下载失败,重定向url为空"), false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -161,14 +160,14 @@ public final class M3U8ThreadTaskAdapter extends AbsThreadTaskAdapter {
|
||||
}
|
||||
|
||||
if (!CheckUtil.checkUrl(newUrl)) {
|
||||
fail(new AriaIOException(TAG, "下载失败,重定向url错误"), false);
|
||||
fail(new AriaM3U8Exception(TAG, "下载失败,重定向url错误"), false);
|
||||
return;
|
||||
}
|
||||
String cookies = conn.getHeaderField("Set-Cookie");
|
||||
conn.disconnect(); // 关闭上一个连接
|
||||
URL url = ConnectionHelp.handleUrl(newUrl, mHttpTaskOption);
|
||||
conn = ConnectionHelp.handleConnection(url, mHttpTaskOption);
|
||||
if (!TextUtils.isEmpty(cookies)){
|
||||
if (!TextUtils.isEmpty(cookies)) {
|
||||
conn.setRequestProperty("Cookie", cookies);
|
||||
}
|
||||
if (mHttpTaskOption.isChunked()) {
|
||||
@@ -199,7 +198,7 @@ public final class M3U8ThreadTaskAdapter extends AbsThreadTaskAdapter {
|
||||
}
|
||||
handleComplete();
|
||||
} catch (IOException e) {
|
||||
fail(new AriaIOException(TAG,
|
||||
fail(new AriaM3U8Exception(TAG,
|
||||
String.format("文件下载失败,savePath: %s, url: %s", getThreadConfig().tempFile.getPath(),
|
||||
getThreadConfig().url), e), true);
|
||||
} finally {
|
||||
@@ -242,7 +241,7 @@ public final class M3U8ThreadTaskAdapter extends AbsThreadTaskAdapter {
|
||||
}
|
||||
handleComplete();
|
||||
} catch (IOException e) {
|
||||
fail(new AriaIOException(TAG,
|
||||
fail(new AriaM3U8Exception(TAG,
|
||||
String.format("文件下载失败,savePath: %s, url: %s", getThreadConfig().tempFile.getPath(),
|
||||
getThreadConfig().url), e), true);
|
||||
} finally {
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.m3u8.M3U8TaskOption;
|
||||
import com.arialyy.aria.util.DeleteM3u8Record;
|
||||
import com.arialyy.aria.util.RecordUtil;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -41,7 +42,7 @@ final class LiveRecordHandler extends RecordHandler {
|
||||
|
||||
@Override public void onPre() {
|
||||
super.onPre();
|
||||
RecordUtil.delTaskRecord(getEntity().getFilePath(), IRecordHandler.TYPE_DOWNLOAD);
|
||||
DeleteM3u8Record.getInstance().deleteRecord(getEntity().getFilePath(), true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.m3u8.live;
|
||||
|
||||
import com.arialyy.aria.core.processor.ILiveTsUrlConverter;
|
||||
|
||||
/**
|
||||
* 默认的m3u8 ts转换器
|
||||
*/
|
||||
class LiveTsDefConverter implements ILiveTsUrlConverter {
|
||||
@Override public String convert(String m3u8Url, String tsUrl) {
|
||||
int index = m3u8Url.lastIndexOf("/");
|
||||
String parentUrl = m3u8Url.substring(0, index + 1);
|
||||
return parentUrl + tsUrl;
|
||||
}
|
||||
}
|
||||
@@ -32,9 +32,8 @@ import com.arialyy.aria.core.processor.ILiveTsUrlConverter;
|
||||
import com.arialyy.aria.core.processor.ITsMergeHandler;
|
||||
import com.arialyy.aria.core.task.ThreadTask;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.M3U8Exception;
|
||||
import com.arialyy.aria.exception.TaskException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.exception.AriaM3U8Exception;
|
||||
import com.arialyy.aria.m3u8.BaseM3U8Loader;
|
||||
import com.arialyy.aria.m3u8.IdGenerator;
|
||||
import com.arialyy.aria.m3u8.M3U8InfoTask;
|
||||
@@ -255,7 +254,7 @@ final class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
ALog.d(TAG, "更新直播的m3u8文件");
|
||||
}
|
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
|
||||
@Override public void onFail(AbsEntity entity, AriaException e, boolean needRetry) {
|
||||
|
||||
}
|
||||
});
|
||||
@@ -266,7 +265,9 @@ final class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
return;
|
||||
}
|
||||
mPeerUrls.add(url);
|
||||
ILiveTsUrlConverter converter = mM3U8Option.getLiveTsUrlConverter();
|
||||
ILiveTsUrlConverter converter = mM3U8Option.isUseDefConvert() ?
|
||||
new LiveTsDefConverter() :
|
||||
mM3U8Option.getLiveTsUrlConverter();
|
||||
if (converter != null) {
|
||||
if (TextUtils.isEmpty(mM3U8Option.getBandWidthUrl())) {
|
||||
url = converter.convert(getEntity().getUrl(), url);
|
||||
@@ -275,7 +276,7 @@ final class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
}
|
||||
}
|
||||
if (TextUtils.isEmpty(url) || !url.startsWith("http")) {
|
||||
fail(new M3U8Exception(TAG, String.format("ts地址错误,url:%s", url)), false);
|
||||
fail(new AriaM3U8Exception(TAG, String.format("ts地址错误,url:%s", url)), false);
|
||||
return;
|
||||
}
|
||||
offerPeer(new M3U8LiveLoader.ExtInfo(url, extInf));
|
||||
@@ -283,7 +284,7 @@ final class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
});
|
||||
}
|
||||
|
||||
private void fail(BaseException e, boolean needRetry) {
|
||||
private void fail(AriaM3U8Exception e, boolean needRetry) {
|
||||
getListener().onFail(needRetry, e);
|
||||
handleComplete();
|
||||
}
|
||||
@@ -296,13 +297,13 @@ final class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
if (generateIndexFile(true)) {
|
||||
getListener().onComplete();
|
||||
} else {
|
||||
getListener().onFail(false, new TaskException(TAG, "创建索引文件失败"));
|
||||
getListener().onFail(false, new AriaM3U8Exception(TAG, "创建索引文件失败"));
|
||||
}
|
||||
} else if (mM3U8Option.isMergeFile()) {
|
||||
if (mergeFile()) {
|
||||
getListener().onComplete();
|
||||
} else {
|
||||
getListener().onFail(false, new M3U8Exception(TAG, "合并文件失败"));
|
||||
getListener().onFail(false, new AriaM3U8Exception(TAG, "合并文件失败"));
|
||||
}
|
||||
} else {
|
||||
getListener().onComplete();
|
||||
|
||||
@@ -35,8 +35,8 @@ import com.arialyy.aria.core.manager.ThreadTaskManager;
|
||||
import com.arialyy.aria.core.processor.IVodTsUrlConverter;
|
||||
import com.arialyy.aria.core.task.ThreadTask;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.M3U8Exception;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.exception.AriaM3U8Exception;
|
||||
import com.arialyy.aria.m3u8.BaseM3U8Loader;
|
||||
import com.arialyy.aria.m3u8.M3U8Listener;
|
||||
import com.arialyy.aria.m3u8.M3U8TaskOption;
|
||||
@@ -51,6 +51,7 @@ import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
@@ -75,10 +76,11 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
private SparseArray<ThreadRecord> mAfterPeer = new SparseArray<>();
|
||||
private PeerIndexEvent mCurrentEvent;
|
||||
private String mCacheDir;
|
||||
private int aIndex = 0, bIndex = 0;
|
||||
private int mCurrentFlagSize;
|
||||
private AtomicInteger afterPeerIndex = new AtomicInteger();
|
||||
private AtomicInteger beforePeerIndex = new AtomicInteger();
|
||||
private AtomicInteger mCompleteNum = new AtomicInteger();
|
||||
private AtomicInteger mCurrentFlagSize = new AtomicInteger();
|
||||
private boolean isJump = false, isDestroy = false;
|
||||
private int mCompleteNum = 0;
|
||||
private ExecutorService mJumpThreadPool;
|
||||
private Thread jumpThread = null;
|
||||
private M3U8TaskOption mM3U8Option;
|
||||
@@ -102,20 +104,20 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
}
|
||||
|
||||
int getCompleteNum() {
|
||||
return mCompleteNum;
|
||||
return mCompleteNum.get();
|
||||
}
|
||||
|
||||
void setCompleteNum(int mCompleteNum) {
|
||||
this.mCompleteNum = mCompleteNum;
|
||||
void setCompleteNum(int completeNum) {
|
||||
mCompleteNum.set(completeNum);
|
||||
}
|
||||
|
||||
int getCurrentFlagSize() {
|
||||
mCurrentFlagSize = mFlagQueue.size();
|
||||
return mCurrentFlagSize;
|
||||
mCurrentFlagSize.set(mFlagQueue.size());
|
||||
return mCurrentFlagSize.get();
|
||||
}
|
||||
|
||||
void setCurrentFlagSize(int currentFlagSize) {
|
||||
mCurrentFlagSize = currentFlagSize;
|
||||
mCurrentFlagSize.set(currentFlagSize);
|
||||
}
|
||||
|
||||
boolean isJump() {
|
||||
@@ -135,10 +137,6 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean isBreak() {
|
||||
return super.isBreak() || isDestroy;
|
||||
}
|
||||
|
||||
@Override protected void handleTask(Looper looper) {
|
||||
if (isBreak()) {
|
||||
return;
|
||||
@@ -182,7 +180,7 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
try {
|
||||
LOCK.lock();
|
||||
while (mFlagQueue.size() < EXEC_MAX_NUM && !isBreak()) {
|
||||
if (mCompleteNum == mRecord.threadRecords.size()) {
|
||||
if (mCompleteNum.get() == mRecord.threadRecords.size()) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -218,16 +216,18 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
ThreadRecord tr = null;
|
||||
try {
|
||||
// 优先下载peer指针之后的数据
|
||||
if (bIndex == 0 && aIndex < mAfterPeer.size()) {
|
||||
if (beforePeerIndex.get() == 0 && afterPeerIndex.get() < mAfterPeer.size()) {
|
||||
//ALog.d(TAG, String.format("afterArray size:%s, index:%s", mAfterPeer.size(), aIndex));
|
||||
tr = mAfterPeer.valueAt(aIndex);
|
||||
aIndex++;
|
||||
tr = mAfterPeer.valueAt(afterPeerIndex.get());
|
||||
afterPeerIndex.getAndIncrement();
|
||||
}
|
||||
|
||||
// 如果指针之后的数组没有切片了,则重新初始化指针位置,并获取指针之前的数组获取切片进行下载
|
||||
if (mBeforePeer.size() > 0 && (tr == null || bIndex != 0) && bIndex < mBeforePeer.size()) {
|
||||
tr = mBeforePeer.valueAt(bIndex);
|
||||
bIndex++;
|
||||
if (mBeforePeer.size() > 0
|
||||
&& (tr == null || beforePeerIndex.get() != 0)
|
||||
&& beforePeerIndex.get() < mBeforePeer.size()) {
|
||||
tr = mBeforePeer.valueAt(beforePeerIndex.get());
|
||||
beforePeerIndex.getAndIncrement();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -260,19 +260,19 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
return;
|
||||
}
|
||||
// 设置需要下载的切片
|
||||
mCompleteNum = 0;
|
||||
mCompleteNum.set(0);
|
||||
for (ThreadRecord tr : mRecord.threadRecords) {
|
||||
if (!tr.isComplete) {
|
||||
mAfterPeer.put(tr.threadId, tr);
|
||||
} else {
|
||||
mCompleteNum++;
|
||||
mCompleteNum.getAndIncrement();
|
||||
}
|
||||
}
|
||||
getStateManager().updateStateCount();
|
||||
if (mCompleteNum <= 0) {
|
||||
if (mCompleteNum.get() <= 0) {
|
||||
getListener().onStart(0);
|
||||
} else {
|
||||
int percent = mCompleteNum * 100 / mRecord.threadRecords.size();
|
||||
int percent = mCompleteNum.get() * 100 / mRecord.threadRecords.size();
|
||||
getListener().onResume(percent);
|
||||
}
|
||||
}
|
||||
@@ -333,7 +333,7 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
|
||||
isJump = true;
|
||||
notifyWaitLock(false);
|
||||
mCurrentFlagSize = mFlagQueue.size();
|
||||
mCurrentFlagSize.set(mFlagQueue.size());
|
||||
// 停止所有正在执行的线程任务
|
||||
try {
|
||||
TempFlag flag;
|
||||
@@ -407,12 +407,12 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
mBeforePeer.clear();
|
||||
mAfterPeer.clear();
|
||||
mFlagQueue.clear();
|
||||
aIndex = 0;
|
||||
bIndex = 0;
|
||||
mCompleteNum = 0;
|
||||
afterPeerIndex.set(0);
|
||||
beforePeerIndex.set(0);
|
||||
mCompleteNum.set(0);
|
||||
for (ThreadRecord tr : mRecord.threadRecords) {
|
||||
if (tr.isComplete) {
|
||||
mCompleteNum++;
|
||||
mCompleteNum.getAndIncrement();
|
||||
continue;
|
||||
}
|
||||
if (tr.threadId < mCurrentEvent.peerIndex) {
|
||||
@@ -504,7 +504,9 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
final List<String> urls = new ArrayList<>();
|
||||
mInfoTask.setCallback(new IInfoTask.Callback() {
|
||||
@Override public void onSucceed(String key, CompleteInfo info) {
|
||||
IVodTsUrlConverter converter = mM3U8Option.getVodUrlConverter();
|
||||
IVodTsUrlConverter converter = mM3U8Option.isUseDefConvert() ?
|
||||
new VodTsDefConverter() :
|
||||
mM3U8Option.getVodUrlConverter();
|
||||
if (converter != null) {
|
||||
if (TextUtils.isEmpty(mM3U8Option.getBandWidthUrl())) {
|
||||
urls.addAll(
|
||||
@@ -517,10 +519,10 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
urls.addAll((Collection<? extends String>) info.obj);
|
||||
}
|
||||
if (urls.isEmpty()) {
|
||||
fail(new M3U8Exception(TAG, "获取地址失败"), false);
|
||||
fail(new AriaM3U8Exception(TAG, "获取地址失败"), false);
|
||||
return;
|
||||
} else if (!urls.get(0).startsWith("http")) {
|
||||
fail(new M3U8Exception(TAG, "地址错误,请使用IVodTsUrlConverter处理你的url信息"), false);
|
||||
fail(new AriaM3U8Exception(TAG, "地址错误,请使用IVodTsUrlConverter处理你的url信息"), false);
|
||||
return;
|
||||
}
|
||||
mM3U8Option.setUrls(urls);
|
||||
@@ -534,13 +536,13 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
|
||||
@Override public void onFail(AbsEntity entity, AriaException e, boolean needRetry) {
|
||||
fail(e, needRetry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void fail(BaseException e, boolean needRetry) {
|
||||
protected void fail(AriaException e, boolean needRetry) {
|
||||
if (isBreak()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ import com.arialyy.aria.core.loader.ILoaderVisitor;
|
||||
import com.arialyy.aria.core.manager.ThreadTaskManager;
|
||||
import com.arialyy.aria.core.processor.ITsMergeHandler;
|
||||
import com.arialyy.aria.core.task.ThreadTask;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.TaskException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.exception.AriaM3U8Exception;
|
||||
import com.arialyy.aria.m3u8.BaseM3U8Loader;
|
||||
import com.arialyy.aria.m3u8.M3U8Listener;
|
||||
import com.arialyy.aria.m3u8.M3U8TaskOption;
|
||||
@@ -40,6 +40,7 @@ import com.arialyy.aria.util.FileUtil;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* m3u8 点播下载状态管理器
|
||||
@@ -49,9 +50,9 @@ public final class VodStateManager implements IThreadStateManager {
|
||||
|
||||
private M3U8Listener listener;
|
||||
private int startThreadNum; // 启动的线程总数
|
||||
private int cancelNum = 0; // 已经取消的线程的数
|
||||
private int stopNum = 0; // 已经停止的线程数
|
||||
private int failNum = 0; // 失败的线程数
|
||||
private AtomicInteger cancelNum = new AtomicInteger(0); // 已经取消的线程的数
|
||||
private AtomicInteger stopNum = new AtomicInteger(0); // 已经停止的线程数
|
||||
private AtomicInteger failNum = new AtomicInteger(0); // 失败的线程数
|
||||
private long progress;
|
||||
private TaskRecord taskRecord; // 任务记录
|
||||
private Looper looper;
|
||||
@@ -74,11 +75,11 @@ public final class VodStateManager implements IThreadStateManager {
|
||||
int peerIndex = msg.getData().getInt(ISchedulers.DATA_M3U8_PEER_INDEX);
|
||||
switch (msg.what) {
|
||||
case STATE_STOP:
|
||||
stopNum++;
|
||||
stopNum.getAndIncrement();
|
||||
removeSignThread((ThreadTask) msg.obj);
|
||||
// 处理跳转位置后,恢复任务
|
||||
if (loader.isJump()
|
||||
&& (stopNum == loader.getCurrentFlagSize() || loader.getCurrentFlagSize() == 0)
|
||||
&& (stopNum.get() == loader.getCurrentFlagSize() || loader.getCurrentFlagSize() == 0)
|
||||
&& !loader.isBreak()) {
|
||||
loader.resumeTask();
|
||||
return true;
|
||||
@@ -90,7 +91,7 @@ public final class VodStateManager implements IThreadStateManager {
|
||||
}
|
||||
break;
|
||||
case STATE_CANCEL:
|
||||
cancelNum++;
|
||||
cancelNum.getAndIncrement();
|
||||
removeSignThread((ThreadTask) msg.obj);
|
||||
|
||||
if (loader.isBreak()) {
|
||||
@@ -99,7 +100,7 @@ public final class VodStateManager implements IThreadStateManager {
|
||||
}
|
||||
break;
|
||||
case STATE_FAIL:
|
||||
failNum++;
|
||||
failNum.getAndIncrement();
|
||||
for (ThreadRecord tr : taskRecord.threadRecords) {
|
||||
if (tr.threadId == peerIndex) {
|
||||
loader.getBeforePeer().put(peerIndex, tr);
|
||||
@@ -113,7 +114,7 @@ public final class VodStateManager implements IThreadStateManager {
|
||||
ALog.d(TAG, String.format("vod任务【%s】失败", loader.getTempFile().getName()));
|
||||
Bundle b = msg.getData();
|
||||
listener.onFail(b.getBoolean(DATA_RETRY, true),
|
||||
(BaseException) b.getSerializable(DATA_ERROR_INFO));
|
||||
(AriaException) b.getSerializable(DATA_ERROR_INFO));
|
||||
quitLooper();
|
||||
}
|
||||
break;
|
||||
@@ -148,7 +149,7 @@ public final class VodStateManager implements IThreadStateManager {
|
||||
if (loader.generateIndexFile(false)) {
|
||||
listener.onComplete();
|
||||
} else {
|
||||
listener.onFail(false, new TaskException(TAG, "创建索引文件失败"));
|
||||
listener.onFail(false, new AriaM3U8Exception(TAG, "创建索引文件失败"));
|
||||
}
|
||||
} else if (m3U8Option.isMergeFile()) {
|
||||
if (mergeFile()) {
|
||||
@@ -175,9 +176,9 @@ public final class VodStateManager implements IThreadStateManager {
|
||||
};
|
||||
|
||||
void updateStateCount() {
|
||||
cancelNum = 0;
|
||||
stopNum = 0;
|
||||
failNum = 0;
|
||||
cancelNum.set(0);
|
||||
stopNum.set(0);
|
||||
failNum.set(0);
|
||||
}
|
||||
|
||||
@Override public void setLooper(TaskRecord taskRecord, Looper looper) {
|
||||
@@ -233,12 +234,12 @@ public final class VodStateManager implements IThreadStateManager {
|
||||
|
||||
@Override public boolean isFail() {
|
||||
printInfo("isFail");
|
||||
return failNum != 0 && failNum == loader.getCurrentFlagSize() && !loader.isJump();
|
||||
return failNum.get() != 0 && failNum.get() == loader.getCurrentFlagSize() && !loader.isJump();
|
||||
}
|
||||
|
||||
@Override public boolean isComplete() {
|
||||
if (m3U8Option.isIgnoreFailureTs()) {
|
||||
return loader.getCompleteNum() + failNum >= taskRecord.threadRecords.size()
|
||||
return loader.getCompleteNum() + failNum.get() >= taskRecord.threadRecords.size()
|
||||
&& !loader.isJump();
|
||||
} else {
|
||||
return loader.getCompleteNum() == taskRecord.threadRecords.size() && !loader.isJump();
|
||||
|
||||
@@ -13,20 +13,24 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.exception;
|
||||
package com.arialyy.aria.m3u8.vod;
|
||||
|
||||
import com.arialyy.aria.core.processor.IVodTsUrlConverter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2017/1/18.
|
||||
* Aria 文件异常
|
||||
* 默认的m3u8 ts转换器
|
||||
*/
|
||||
public class FileNotFoundException extends BaseException {
|
||||
private static final String ARIA_FILE_EXCEPTION = "Aria File not found Exception:";
|
||||
class VodTsDefConverter implements IVodTsUrlConverter {
|
||||
@Override public List<String> convert(String m3u8Url, List<String> tsUrls) {
|
||||
int index = m3u8Url.lastIndexOf("/");
|
||||
List<String> convertedTsUrl = new ArrayList<>();
|
||||
|
||||
public FileNotFoundException(String tag, String detailMessage) {
|
||||
super(tag, String.format("%s%s", ARIA_FILE_EXCEPTION, detailMessage));
|
||||
}
|
||||
|
||||
public FileNotFoundException(String tag, String message, Exception e) {
|
||||
super(tag, message, e);
|
||||
String parentUrl = m3u8Url.substring(0, index + 1);
|
||||
for (String temp : tsUrls) {
|
||||
convertedTsUrl.add(parentUrl + temp);
|
||||
}
|
||||
return convertedTsUrl;
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkRequest;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
@@ -120,6 +121,7 @@ public class AriaConfig {
|
||||
* 注册网络监听,只有配置了检查网络{@link AppConfig#isNetCheck()}才会注册事件
|
||||
*/
|
||||
private void regNetCallBack(Context context) {
|
||||
isConnectedNet = isNetworkAvailable();
|
||||
if (!getAConfig().isNetCheck()) {
|
||||
return;
|
||||
}
|
||||
@@ -142,19 +144,44 @@ public class AriaConfig {
|
||||
|
||||
@Override public void onLost(Network network) {
|
||||
super.onLost(network);
|
||||
isConnectedNet = false;
|
||||
ALog.d(TAG, "onLost");
|
||||
isConnectedNet = isNetworkAvailable();
|
||||
ALog.d(TAG, "onLost, isConnectNet = " + isConnectedNet);
|
||||
}
|
||||
|
||||
@Override public void onAvailable(Network network) {
|
||||
super.onAvailable(network);
|
||||
ALog.d(TAG, "onAvailable");
|
||||
isConnectedNet = true;
|
||||
ALog.d(TAG, "onAvailable, isConnectNet = true");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isNetworkAvailable() {
|
||||
// 获取手机所有连接管理对象(包括对wi-fi,net等连接的管理)
|
||||
ConnectivityManager connectivityManager =
|
||||
(ConnectivityManager) getAPP().getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
|
||||
if (connectivityManager == null) {
|
||||
|
||||
return false;
|
||||
} else {
|
||||
// 获取NetworkInfo对象
|
||||
NetworkInfo[] networkInfo = connectivityManager.getAllNetworkInfo();
|
||||
|
||||
if (networkInfo != null && networkInfo.length > 0) {
|
||||
for (NetworkInfo info : networkInfo) {
|
||||
// 判断当前网络状态是否为连接状态
|
||||
if (info.getState() == NetworkInfo.State.CONNECTED) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public boolean isConnectedNet() {
|
||||
return isConnectedNet;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.arialyy.aria.core.processor.FtpInterceptHandler;
|
||||
import com.arialyy.aria.core.processor.IBandWidthUrlConverter;
|
||||
import com.arialyy.aria.core.processor.IFtpUploadInterceptor;
|
||||
import com.arialyy.aria.core.processor.IHttpFileLenAdapter;
|
||||
import com.arialyy.aria.core.processor.IHttpFileNameAdapter;
|
||||
import com.arialyy.aria.core.processor.IKeyUrlConverter;
|
||||
import com.arialyy.aria.core.processor.ILiveTsUrlConverter;
|
||||
import com.arialyy.aria.core.processor.ITsMergeHandler;
|
||||
@@ -59,6 +60,7 @@ public class TaskOptionParams {
|
||||
PROCESSORES.add(IBandWidthUrlConverter.class);
|
||||
PROCESSORES.add(IFtpUploadInterceptor.class);
|
||||
PROCESSORES.add(IHttpFileLenAdapter.class);
|
||||
PROCESSORES.add(IHttpFileNameAdapter.class);
|
||||
PROCESSORES.add(ILiveTsUrlConverter.class);
|
||||
PROCESSORES.add(ITsMergeHandler.class);
|
||||
PROCESSORES.add(IVodTsUrlConverter.class);
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.DbDataHelper;
|
||||
import com.arialyy.aria.util.FileUtil;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
@@ -84,6 +85,11 @@ public abstract class RecordHandler implements IRecordHandler {
|
||||
mTaskRecord = DbDataHelper.getTaskRecord(getFilePath(), mEntity.getTaskType());
|
||||
if (mTaskRecord == null) {
|
||||
initRecord(true);
|
||||
}else if (mTaskRecord.threadRecords == null || mTaskRecord.threadRecords.size() == 0){
|
||||
if (mTaskRecord.threadRecords == null){
|
||||
mTaskRecord.threadRecords = new ArrayList<>();
|
||||
}
|
||||
initRecord(false);
|
||||
}
|
||||
handlerTaskRecord(mTaskRecord);
|
||||
}
|
||||
|
||||
@@ -130,13 +130,17 @@ public class RecordHelper {
|
||||
/*
|
||||
* 检查记录文件
|
||||
*/
|
||||
if (blockFileLen == threadRect) {
|
||||
if (blockFileLen == threadRect && blockFileLen != 0) {
|
||||
ALog.i(TAG, String.format("分块【%s】已完成,更新记录", temp.getPath()));
|
||||
tr.startLocation = blockFileLen;
|
||||
tr.isComplete = true;
|
||||
} else if (tr.startLocation != realLocation) { // 处理记录小于分块文件长度的情况
|
||||
ALog.i(TAG, String.format("修正分块【%s】的进度记录为:%s", temp.getPath(), realLocation));
|
||||
tr.startLocation = realLocation;
|
||||
} else {
|
||||
ALog.i(TAG, String.format("修正分块【%s】的进度记录为:%s", temp.getPath(), realLocation));
|
||||
tr.startLocation = realLocation;
|
||||
tr.isComplete = false;
|
||||
}
|
||||
} else {
|
||||
ALog.i(TAG, String.format("分块【%s】已完成", temp.getPath()));
|
||||
@@ -159,8 +163,10 @@ public class RecordHelper {
|
||||
// 目标文件
|
||||
File targetFile = new File(mTaskRecord.filePath);
|
||||
// 处理组合任务其中一个子任务完成的情况
|
||||
if (tr.isComplete && targetFile.exists() && targetFile.length() == mWrapper.getEntity()
|
||||
.getFileSize()) {
|
||||
if (tr.isComplete
|
||||
&& targetFile.exists()
|
||||
&& targetFile.length() != 0
|
||||
&& targetFile.length() == mWrapper.getEntity().getFileSize()) {
|
||||
tr.isComplete = true;
|
||||
} else {
|
||||
ALog.w(TAG, String.format("文件【%s】不存在,任务将重新开始", file.getPath()));
|
||||
@@ -174,7 +180,7 @@ public class RecordHelper {
|
||||
tr.startLocation = 0;
|
||||
tr.isComplete = false;
|
||||
tr.endLocation = mWrapper.getEntity().getFileSize();
|
||||
} else if (file.length() == mWrapper.getEntity().getFileSize()) {
|
||||
} else if (file.length() != 0 && file.length() == mWrapper.getEntity().getFileSize()) {
|
||||
ALog.d(TAG, "文件长度一致,线程完成");
|
||||
tr.isComplete = true;
|
||||
} else {
|
||||
|
||||
@@ -36,6 +36,7 @@ public class SubThreadConfig {
|
||||
public boolean isBlock = false;
|
||||
// 启动的线程
|
||||
public int startThreadNum;
|
||||
// 真正的下载地址,如果是30x,则是30x后的地址
|
||||
public String url;
|
||||
public File tempFile;
|
||||
// 线程记录
|
||||
|
||||
@@ -31,6 +31,11 @@ public class DGroupConfig extends BaseTaskConfig implements Serializable {
|
||||
*/
|
||||
int subMaxTaskNum = 3;
|
||||
|
||||
/**
|
||||
* 子任务失败时回调stop,默认true
|
||||
*/
|
||||
private boolean subFailAsStop = true;
|
||||
|
||||
/**
|
||||
* 子任务重试次数,默认为5
|
||||
*/
|
||||
@@ -118,4 +123,14 @@ public class DGroupConfig extends BaseTaskConfig implements Serializable {
|
||||
save();
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isSubFailAsStop() {
|
||||
return subFailAsStop;
|
||||
}
|
||||
|
||||
public DGroupConfig setSubFailAsStop(boolean subFailAsStop) {
|
||||
this.subFailAsStop = subFailAsStop;
|
||||
save();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -144,6 +144,10 @@ public class XMLReader extends DefaultHandler {
|
||||
int subMaxTaskNum = checkInt(value) ? Integer.parseInt(value) : 3;
|
||||
setField("subMaxTaskNum", subMaxTaskNum, ConfigType.D_GROUP);
|
||||
break;
|
||||
case "subFailAsStop": // 子任务失败时回调stop
|
||||
setField("subFailAsStop", checkBoolean(value) ? Boolean.valueOf(value) : false,
|
||||
ConfigType.D_GROUP);
|
||||
break;
|
||||
case "subReTryNum": // 子任务重试次数
|
||||
int subReTryNum = checkInt(value) ? Integer.parseInt(value) : 5;
|
||||
setField("subReTryNum", subReTryNum, ConfigType.D_GROUP);
|
||||
|
||||
@@ -32,4 +32,17 @@ public abstract class AbsGroupTaskWrapper<ENTITY extends AbsEntity, SUB extends
|
||||
public abstract List<SUB> getSubTaskWrapper();
|
||||
|
||||
public abstract void setSubTaskWrapper(List<SUB> subTaskWrapper);
|
||||
|
||||
/**
|
||||
* {@code true} 忽略任务冲突,不考虑组任务hash冲突的情况
|
||||
*/
|
||||
private boolean ignoreTaskOccupy = false;
|
||||
|
||||
public boolean isIgnoreTaskOccupy() {
|
||||
return ignoreTaskOccupy;
|
||||
}
|
||||
|
||||
public void setIgnoreTaskOccupy(boolean ignoreTaskOccupy) {
|
||||
this.ignoreTaskOccupy = ignoreTaskOccupy;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,27 +74,34 @@ public class DownloadEntity extends AbsNormalEntity implements Parcelable {
|
||||
return m3U8Entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置进来的地址,如果需要获取真实的下载地址,请使用{@link #getRealUrl()}
|
||||
*/
|
||||
@Override public String getKey() {
|
||||
return getUrl();
|
||||
}
|
||||
|
||||
public String getRealUrl(){
|
||||
return isRedirect() ? getRedirectUrl() : getUrl();
|
||||
}
|
||||
|
||||
@Override public int getTaskType() {
|
||||
int type;
|
||||
if (TextUtils.isEmpty(getUrl())) {
|
||||
if (getUrl() == null) {
|
||||
type = ITaskWrapper.ERROR;
|
||||
} else if (getUrl().startsWith("http")) {
|
||||
type = ITaskWrapper.D_HTTP;
|
||||
} else if (getUrl().startsWith("ftp")) {
|
||||
type = ITaskWrapper.D_FTP;
|
||||
} else if (getUrl().startsWith("sftp")) {
|
||||
type = ITaskWrapper.D_SFTP;
|
||||
} else {
|
||||
M3U8Entity temp = getM3U8Entity();
|
||||
if (temp == null) {
|
||||
type = ITaskWrapper.D_HTTP;
|
||||
} else {
|
||||
type = temp.isLive() ? ITaskWrapper.M3U8_LIVE : ITaskWrapper.M3U8_VOD;
|
||||
}
|
||||
} else if (getUrl().startsWith("ftp")) {
|
||||
type = ITaskWrapper.D_FTP;
|
||||
} else if (getUrl().startsWith("sftp")) {
|
||||
type = ITaskWrapper.D_SFTP;
|
||||
} else {
|
||||
type = ITaskWrapper.ERROR;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import com.arialyy.aria.core.loader.ILoaderVisitor;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.loader.IThreadTaskBuilder;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.io.File;
|
||||
@@ -101,12 +101,12 @@ public abstract class AbsGroupLoader implements ILoaderVisitor, ILoader {
|
||||
for (DTaskWrapper wrapper : mGTWrapper.getSubTaskWrapper()) {
|
||||
long fileLen = checkFileExists(wrapper.getEntity().getFilePath());
|
||||
if (wrapper.getEntity().getState() == IEntity.STATE_COMPLETE
|
||||
&& fileLen != -1
|
||||
&& fileLen > 0
|
||||
&& fileLen == wrapper.getEntity().getFileSize()) {
|
||||
mState.updateCompleteNum();
|
||||
//mState.updateCompleteNum();
|
||||
mCurrentLocation += wrapper.getEntity().getFileSize();
|
||||
} else {
|
||||
if (fileLen == -1) {
|
||||
if (fileLen <= 0) {
|
||||
wrapper.getEntity().setCurrentProgress(0);
|
||||
}
|
||||
wrapper.getEntity().setState(IEntity.STATE_POST_PRE);
|
||||
@@ -153,7 +153,7 @@ public abstract class AbsGroupLoader implements ILoaderVisitor, ILoader {
|
||||
if (!checkSubTask(url, "开始")) {
|
||||
return;
|
||||
}
|
||||
if (!mState.isRunning) {
|
||||
if (!mState.isRunning.get()) {
|
||||
startTimer();
|
||||
}
|
||||
AbsSubDLoadUtil d = getDownloader(url, false);
|
||||
@@ -212,7 +212,7 @@ public abstract class AbsGroupLoader implements ILoaderVisitor, ILoader {
|
||||
}
|
||||
|
||||
@Override public boolean isRunning() {
|
||||
return mState != null && mState.isRunning;
|
||||
return mState != null && mState.isRunning.get();
|
||||
}
|
||||
|
||||
@Override public void cancel() {
|
||||
@@ -275,11 +275,11 @@ public abstract class AbsGroupLoader implements ILoaderVisitor, ILoader {
|
||||
}
|
||||
|
||||
private synchronized void startTimer() {
|
||||
mState.isRunning = true;
|
||||
mState.isRunning.set(true);
|
||||
mTimer = new ScheduledThreadPoolExecutor(1);
|
||||
mTimer.scheduleWithFixedDelay(new Runnable() {
|
||||
@Override public void run() {
|
||||
if (!mState.isRunning) {
|
||||
if (!mState.isRunning.get()) {
|
||||
closeTimer();
|
||||
} else if (mCurrentLocation >= 0) {
|
||||
long t = 0;
|
||||
@@ -321,7 +321,7 @@ public abstract class AbsGroupLoader implements ILoaderVisitor, ILoader {
|
||||
}
|
||||
}
|
||||
|
||||
protected void fail(BaseException e, boolean needRetry){
|
||||
protected void fail(AriaException e, boolean needRetry) {
|
||||
closeTimer();
|
||||
getListener().onFail(needRetry, e);
|
||||
}
|
||||
|
||||
@@ -97,6 +97,7 @@ public abstract class AbsGroupLoaderUtil implements IUtil {
|
||||
ALog.w(TAG, "启动组合任务失败,任务已停止或已取消");
|
||||
return;
|
||||
}
|
||||
mListener.onPre();
|
||||
|
||||
buildLoaderStructure();
|
||||
new Thread(mLoader).start();
|
||||
|
||||
@@ -15,14 +15,20 @@
|
||||
*/
|
||||
package com.arialyy.aria.core.group;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.inf.IThreadStateManager;
|
||||
import com.arialyy.aria.core.inf.IUtil;
|
||||
import com.arialyy.aria.core.listener.IDLoadListener;
|
||||
import com.arialyy.aria.core.listener.ISchedulers;
|
||||
import com.arialyy.aria.core.loader.LoaderStructure;
|
||||
import com.arialyy.aria.core.loader.SubLoader;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
|
||||
@@ -91,7 +97,7 @@ public abstract class AbsSubDLoadUtil implements IUtil, Runnable {
|
||||
return;
|
||||
}
|
||||
buildLoaderStructure();
|
||||
mDLoader.run();
|
||||
new Thread(mDLoader).start();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,13 +17,17 @@ package com.arialyy.aria.core.group;
|
||||
|
||||
import com.arialyy.aria.core.listener.IDGroupListener;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* 组合任务执行中的状态信息
|
||||
*/
|
||||
public final class GroupRunState {
|
||||
private String TAG = "GroupRunState";
|
||||
/**
|
||||
* 子任务数
|
||||
*/
|
||||
@@ -32,17 +36,18 @@ public final class GroupRunState {
|
||||
/**
|
||||
* 已经完成的任务数
|
||||
*/
|
||||
private int mCompleteNum;
|
||||
private AtomicInteger mCompleteNum = new AtomicInteger();
|
||||
|
||||
/**
|
||||
* 失败的任务数
|
||||
*/
|
||||
private int mFailNum;
|
||||
private AtomicInteger mFailNum = new AtomicInteger();
|
||||
|
||||
/**
|
||||
* 停止的任务数
|
||||
*/
|
||||
private int mStopNum;
|
||||
private AtomicInteger mStopNum = new AtomicInteger();
|
||||
;
|
||||
|
||||
/**
|
||||
* 当前进度
|
||||
@@ -62,7 +67,7 @@ public final class GroupRunState {
|
||||
/**
|
||||
* 是否在执行
|
||||
*/
|
||||
boolean isRunning = false;
|
||||
AtomicBoolean isRunning = new AtomicBoolean(false);
|
||||
|
||||
/**
|
||||
* 子任务失败、停止记录,用于当子任务失败重新被用户点击开始时,更新{@link #mStopNum}或{@link #mFailNum}
|
||||
@@ -78,7 +83,7 @@ public final class GroupRunState {
|
||||
mGroupHash = groupHash;
|
||||
}
|
||||
|
||||
public void setSubSize(int subSize){
|
||||
public void setSubSize(int subSize) {
|
||||
mSubSize = subSize;
|
||||
}
|
||||
|
||||
@@ -88,11 +93,11 @@ public final class GroupRunState {
|
||||
* @return {@code true}组合任务正在执行
|
||||
*/
|
||||
public boolean isRunning() {
|
||||
return isRunning;
|
||||
return isRunning.get();
|
||||
}
|
||||
|
||||
public void setRunning(boolean running) {
|
||||
isRunning = running;
|
||||
isRunning.set(running);
|
||||
}
|
||||
|
||||
String getGroupHash() {
|
||||
@@ -110,21 +115,21 @@ public final class GroupRunState {
|
||||
* 获取失败的数量
|
||||
*/
|
||||
public int getFailNum() {
|
||||
return mFailNum;
|
||||
return mFailNum.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取停止的数量
|
||||
*/
|
||||
public int getStopNum() {
|
||||
return mStopNum;
|
||||
return mStopNum.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取完成的数量
|
||||
*/
|
||||
public int getCompleteNum() {
|
||||
return mCompleteNum;
|
||||
return mCompleteNum.get();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,7 +143,7 @@ public final class GroupRunState {
|
||||
* 更新完成的数量,mCompleteNum + 1
|
||||
*/
|
||||
public void updateCompleteNum() {
|
||||
mCompleteNum++;
|
||||
mCompleteNum.getAndIncrement();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,10 +161,10 @@ public final class GroupRunState {
|
||||
public void updateCount(String key) {
|
||||
if (mFailTemp.contains(key)) {
|
||||
mFailTemp.remove(key);
|
||||
mFailNum--;
|
||||
mFailNum.getAndDecrement();
|
||||
} else if (mStopTemp.contains(key)) {
|
||||
mStopTemp.remove(key);
|
||||
mStopNum--;
|
||||
mStopNum.getAndDecrement();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +175,7 @@ public final class GroupRunState {
|
||||
*/
|
||||
public void countStopNum(String key) {
|
||||
mStopTemp.add(key);
|
||||
mStopNum++;
|
||||
mStopNum.getAndIncrement();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,6 +185,6 @@ public final class GroupRunState {
|
||||
*/
|
||||
public void countFailNum(String key) {
|
||||
mFailTemp.add(key);
|
||||
mFailNum++;
|
||||
mFailNum.getAndIncrement();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,12 @@ import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import com.arialyy.aria.core.AriaConfig;
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.config.Configuration;
|
||||
import com.arialyy.aria.core.inf.IThreadStateManager;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.manager.ThreadTaskManager;
|
||||
import com.arialyy.aria.exception.TaskException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.NetUtils;
|
||||
@@ -71,7 +72,7 @@ final class SimpleSchedulers implements Handler.Callback {
|
||||
mGState.listener.onSubRunning(loaderUtil.getEntity(), range);
|
||||
break;
|
||||
case IThreadStateManager.STATE_PRE:
|
||||
mGState.listener.onSubPre(loaderUtil.getEntity());
|
||||
mGState.listener.onSubPre(loaderUtil.getEntity( ));
|
||||
mGState.updateCount(loaderUtil.getKey());
|
||||
break;
|
||||
case IThreadStateManager.STATE_START:
|
||||
@@ -113,7 +114,7 @@ final class SimpleSchedulers implements Handler.Callback {
|
||||
|| loaderUtil.getLoader() == null // 如果获取不到文件信息,loader为空
|
||||
|| loaderUtil.getEntity().getFailNum() > num) {
|
||||
mQueue.removeTaskFromExecQ(loaderUtil);
|
||||
mGState.listener.onSubFail(loaderUtil.getEntity(), new TaskException(TAG,
|
||||
mGState.listener.onSubFail(loaderUtil.getEntity(), new AriaException(TAG,
|
||||
String.format("任务组子任务【%s】下载失败,下载地址【%s】", loaderUtil.getEntity().getFileName(),
|
||||
loaderUtil.getEntity().getUrl())));
|
||||
mGState.countFailNum(loaderUtil.getKey());
|
||||
@@ -121,9 +122,14 @@ final class SimpleSchedulers implements Handler.Callback {
|
||||
|| mGState.getStopNum() + mGState.getFailNum() + mGState.getCompleteNum()
|
||||
== mGState.getSubSize()) {
|
||||
mQueue.clear();
|
||||
mGState.isRunning = false;
|
||||
mGState.listener.onFail(false, new TaskException(TAG,
|
||||
String.format("任务组【%s】下载失败", mGState.getGroupHash())));
|
||||
mGState.isRunning.set(false);
|
||||
if (mGState.getCompleteNum() > 0&&Configuration.getInstance().dGroupCfg.isSubFailAsStop()) {
|
||||
ALog.e(TAG, String.format("任务组【%s】停止", mGState.getGroupHash()));
|
||||
mGState.listener.onStop(mGState.getProgress());
|
||||
} else {
|
||||
mGState.listener.onFail(false, new AriaException(TAG,
|
||||
String.format("任务组【%s】下载失败", mGState.getGroupHash())));
|
||||
}
|
||||
} else {
|
||||
startNext();
|
||||
}
|
||||
@@ -147,7 +153,7 @@ final class SimpleSchedulers implements Handler.Callback {
|
||||
+ mQueue.getCacheSize()
|
||||
== mGState.getSubSize()) {
|
||||
mQueue.clear();
|
||||
mGState.isRunning = false;
|
||||
mGState.isRunning.set(false);
|
||||
mGState.listener.onStop(mGState.getProgress());
|
||||
} else {
|
||||
startNext();
|
||||
@@ -164,10 +170,11 @@ final class SimpleSchedulers implements Handler.Callback {
|
||||
*/
|
||||
private synchronized void handleComplete(AbsSubDLoadUtil loader) {
|
||||
ALog.d(TAG, String.format("子任务【%s】完成", loader.getEntity().getFileName()));
|
||||
if (loader.getRecord().isBlock) {
|
||||
TaskRecord record = loader.getRecord();
|
||||
if (record != null && record.isBlock) {
|
||||
File partFile =
|
||||
new File(String.format(IRecordHandler.SUB_PATH, loader.getRecord().filePath, 0));
|
||||
partFile.renameTo(new File(loader.getRecord().filePath));
|
||||
new File(String.format(IRecordHandler.SUB_PATH, record.filePath, 0));
|
||||
partFile.renameTo(new File(record.filePath));
|
||||
}
|
||||
ThreadTaskManager.getInstance().removeTaskThread(loader.getKey());
|
||||
mGState.listener.onSubComplete(loader.getEntity());
|
||||
@@ -179,11 +186,14 @@ final class SimpleSchedulers implements Handler.Callback {
|
||||
== mGState.getSubSize()) {
|
||||
if (mGState.getStopNum() == 0 && mGState.getFailNum() == 0) {
|
||||
mGState.listener.onComplete();
|
||||
} else if(mGState.getStopNum() == 0&&!Configuration.getInstance().dGroupCfg.isSubFailAsStop() ){
|
||||
mGState.listener.onFail(false, new AriaException(TAG,
|
||||
String.format("任务组【%s】下载失败", mGState.getGroupHash())));
|
||||
} else {
|
||||
mGState.listener.onStop(mGState.getProgress());
|
||||
}
|
||||
mQueue.clear();
|
||||
mGState.isRunning = false;
|
||||
mGState.isRunning.set(false);
|
||||
} else {
|
||||
startNext();
|
||||
}
|
||||
|
||||
@@ -19,8 +19,12 @@ import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.ThreadRecord;
|
||||
import com.arialyy.aria.core.common.RecordHandler;
|
||||
import com.arialyy.aria.core.common.RecordHelper;
|
||||
import com.arialyy.aria.core.config.Configuration;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.util.RecordUtil;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
@@ -33,7 +37,17 @@ public class SubRecordHandler extends RecordHandler {
|
||||
|
||||
@Override public void handlerTaskRecord(TaskRecord record) {
|
||||
RecordHelper helper = new RecordHelper(getWrapper(), record);
|
||||
helper.handleSingleThreadRecord();
|
||||
if (getWrapper().isSupportBP() && record.threadNum > 1) {
|
||||
if (record.isBlock) {
|
||||
helper.handleBlockRecord();
|
||||
} else {
|
||||
helper.handleMultiRecord();
|
||||
}
|
||||
} else if (!getWrapper().isSupportBP()) {
|
||||
helper.handleNoSupportBPRecord();
|
||||
} else {
|
||||
helper.handleSingleThreadRecord();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,9 +58,14 @@ public class SubRecordHandler extends RecordHandler {
|
||||
tr.threadId = threadId;
|
||||
tr.startLocation = startL;
|
||||
tr.isComplete = false;
|
||||
tr.threadType = getEntity().getTaskType();
|
||||
tr.endLocation = getFileSize();
|
||||
tr.blockLen = getFileSize();
|
||||
|
||||
tr.threadType = record.taskType;
|
||||
//最后一个线程的结束位置即为文件的总长度
|
||||
if (threadId == (record.threadNum - 1)) {
|
||||
endL = getFileSize();
|
||||
}
|
||||
tr.endLocation = endL;
|
||||
tr.blockLen = RecordUtil.getBlockLen(getFileSize(), threadId, record.threadNum);
|
||||
return tr;
|
||||
}
|
||||
|
||||
@@ -54,20 +73,36 @@ public class SubRecordHandler extends RecordHandler {
|
||||
TaskRecord record = new TaskRecord();
|
||||
record.fileName = getEntity().getFileName();
|
||||
record.filePath = getEntity().getFilePath();
|
||||
record.fileLength = getFileSize();
|
||||
record.threadRecords = new ArrayList<>();
|
||||
record.threadNum = threadNum;
|
||||
record.isBlock = false;
|
||||
record.taskType = getWrapper().getRequestType();
|
||||
record.isGroupRecord = true;
|
||||
if (getEntity() instanceof DownloadEntity) {
|
||||
record.dGroupHash = ((DownloadEntity) getEntity()).getGroupHash();
|
||||
|
||||
int requestType = getWrapper().getRequestType();
|
||||
if (requestType == ITaskWrapper.D_HTTP || requestType == ITaskWrapper.DG_HTTP) {
|
||||
record.isBlock = Configuration.getInstance().downloadCfg.isUseBlock();
|
||||
} else {
|
||||
record.isBlock = false;
|
||||
}
|
||||
record.taskType = requestType;
|
||||
record.isGroupRecord = getEntity().isGroupChild();
|
||||
if (record.isGroupRecord) {
|
||||
if (getEntity() instanceof DownloadEntity) {
|
||||
record.dGroupHash = ((DownloadEntity) getEntity()).getGroupHash();
|
||||
}
|
||||
}
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
@Override public int initTaskThreadNum() {
|
||||
return 1;
|
||||
int requestTpe = getWrapper().getRequestType();
|
||||
if (requestTpe == ITaskWrapper.U_HTTP
|
||||
|| (requestTpe == ITaskWrapper.D_HTTP && (!getWrapper().isSupportBP())
|
||||
)) {
|
||||
return 1;
|
||||
}
|
||||
int threadNum = Configuration.getInstance().downloadCfg.getThreadNum();
|
||||
return getFileSize() <= IRecordHandler.SUB_LEN
|
||||
? 1
|
||||
: threadNum;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.inf.TaskSchedulerType;
|
||||
import com.arialyy.aria.core.task.AbsTask;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.DeleteDRecord;
|
||||
import com.arialyy.aria.util.RecordUtil;
|
||||
|
||||
/**
|
||||
@@ -55,11 +56,15 @@ public class BaseDListener extends BaseListener<DownloadEntity, DTaskWrapper, Ab
|
||||
if (sType == TaskSchedulerType.TYPE_CANCEL_AND_NOT_NOTIFY) {
|
||||
mEntity.setComplete(false);
|
||||
mEntity.setState(IEntity.STATE_WAIT);
|
||||
RecordUtil.delTaskRecord(mEntity.getFilePath(), IRecordHandler.TYPE_DOWNLOAD,
|
||||
mTaskWrapper.isRemoveFile(), false);
|
||||
|
||||
DeleteDRecord.getInstance().deleteRecord(mEntity, mTaskWrapper.isRemoveFile(), false);
|
||||
//RecordUtil.delTaskRecord(mEntity.getFilePath(), IRecordHandler.TYPE_DOWNLOAD,
|
||||
// mTaskWrapper.isRemoveFile(), false);
|
||||
} else {
|
||||
RecordUtil.delTaskRecord(mEntity.getFilePath(), IRecordHandler.TYPE_DOWNLOAD,
|
||||
mTaskWrapper.isRemoveFile(), true);
|
||||
//RecordUtil.delTaskRecord(mEntity.getFilePath(), IRecordHandler.TYPE_DOWNLOAD,
|
||||
// mTaskWrapper.isRemoveFile(), true);
|
||||
|
||||
DeleteDRecord.getInstance().deleteRecord(mEntity, mTaskWrapper.isRemoveFile(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,13 +16,14 @@
|
||||
package com.arialyy.aria.core.listener;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import com.arialyy.aria.core.common.AbsEntity;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.inf.TaskSchedulerType;
|
||||
import com.arialyy.aria.core.task.AbsTask;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.ErrorHelp;
|
||||
@@ -114,7 +115,7 @@ public abstract class BaseListener<ENTITY extends AbsEntity, TASK_WRAPPER extend
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void onFail(boolean needRetry, BaseException e) {
|
||||
@Override public void onFail(boolean needRetry, AriaException e) {
|
||||
mEntity.setFailNum(mEntity.getFailNum() + 1);
|
||||
saveData(IEntity.STATE_FAIL, mEntity.getCurrentProgress());
|
||||
handleSpeed(0);
|
||||
@@ -123,8 +124,8 @@ public abstract class BaseListener<ENTITY extends AbsEntity, TASK_WRAPPER extend
|
||||
sendInState2Target(ISchedulers.FAIL);
|
||||
if (e != null) {
|
||||
String error = ALog.getExceptionString(e);
|
||||
ALog.w(TAG, error);
|
||||
ErrorHelp.saveError(e.getTag(), "", error);
|
||||
ALog.e(TAG, error);
|
||||
ErrorHelp.saveError(e.getTag(), e.getMessage(), error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +180,6 @@ public abstract class BaseListener<ENTITY extends AbsEntity, TASK_WRAPPER extend
|
||||
|
||||
protected void saveData(int state, long location) {
|
||||
mEntity.setState(state);
|
||||
mEntity.setComplete(false);
|
||||
|
||||
if (state == IEntity.STATE_CANCEL) {
|
||||
handleCancel();
|
||||
|
||||
@@ -17,12 +17,11 @@ package com.arialyy.aria.core.listener;
|
||||
|
||||
import android.os.Handler;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.inf.TaskSchedulerType;
|
||||
import com.arialyy.aria.core.task.AbsTask;
|
||||
import com.arialyy.aria.core.upload.UTaskWrapper;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.util.RecordUtil;
|
||||
import com.arialyy.aria.util.DeleteURecord;
|
||||
|
||||
/**
|
||||
* 下载监听类
|
||||
@@ -39,11 +38,9 @@ public class BaseUListener extends BaseListener<UploadEntity, UTaskWrapper, AbsT
|
||||
if (sType == TaskSchedulerType.TYPE_CANCEL_AND_NOT_NOTIFY) {
|
||||
mEntity.setComplete(false);
|
||||
mEntity.setState(IEntity.STATE_WAIT);
|
||||
RecordUtil.delTaskRecord(mEntity.getFilePath(), IRecordHandler.TYPE_UPLOAD,
|
||||
mTaskWrapper.isRemoveFile(), false);
|
||||
DeleteURecord.getInstance().deleteRecord(mEntity, mTaskWrapper.isRemoveFile(), false);
|
||||
} else {
|
||||
RecordUtil.delTaskRecord(mEntity.getFilePath(), IRecordHandler.TYPE_UPLOAD,
|
||||
mTaskWrapper.isRemoveFile(), true);
|
||||
DeleteURecord.getInstance().deleteRecord(mEntity, mTaskWrapper.isRemoveFile(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,11 +24,13 @@ import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.inf.TaskSchedulerType;
|
||||
import com.arialyy.aria.core.task.AbsTask;
|
||||
import com.arialyy.aria.core.task.DownloadGroupTask;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.DeleteDGRecord;
|
||||
import com.arialyy.aria.util.ErrorHelp;
|
||||
import com.arialyy.aria.util.RecordUtil;
|
||||
|
||||
import static com.arialyy.aria.core.task.AbsTask.ERROR_INFO_KEY;
|
||||
|
||||
/**
|
||||
* Created by Aria.Lao on 2017/7/20. 任务组下载事件
|
||||
@@ -81,10 +83,11 @@ public class DownloadGroupListener
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSubFail(DownloadEntity subEntity, BaseException e) {
|
||||
public void onSubFail(DownloadEntity subEntity, AriaException e) {
|
||||
handleSubSpeed(subEntity, 0);
|
||||
saveSubState(IEntity.STATE_FAIL, subEntity);
|
||||
saveCurrentLocation();
|
||||
mSeedEntity.groupTask.putExpand(ERROR_INFO_KEY, e);
|
||||
sendInState2Target(ISchedulers.SUB_FAIL, subEntity);
|
||||
if (e != null) {
|
||||
e.printStackTrace();
|
||||
@@ -194,9 +197,9 @@ public class DownloadGroupListener
|
||||
if (sType == TaskSchedulerType.TYPE_CANCEL_AND_NOT_NOTIFY) {
|
||||
mEntity.setComplete(false);
|
||||
mEntity.setState(IEntity.STATE_WAIT);
|
||||
RecordUtil.delGroupTaskRecord(mEntity, mTaskWrapper.isRemoveFile(), false);
|
||||
DeleteDGRecord.getInstance().deleteRecord(mEntity, mTaskWrapper.isRemoveFile(), false);
|
||||
} else {
|
||||
RecordUtil.delGroupTaskRecord(mEntity, mTaskWrapper.isRemoveFile(), true);
|
||||
DeleteDGRecord.getInstance().deleteRecord(mEntity, mTaskWrapper.isRemoveFile(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
package com.arialyy.aria.core.listener;
|
||||
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
|
||||
/**
|
||||
* Created by Aria.Lao on 2017/7/20.
|
||||
@@ -54,7 +54,7 @@ public interface IDGroupListener extends IDLoadListener {
|
||||
/**
|
||||
* 子任务下载失败
|
||||
*/
|
||||
void onSubFail(DownloadEntity subEntity, BaseException e);
|
||||
void onSubFail(DownloadEntity subEntity, AriaException e);
|
||||
|
||||
/**
|
||||
* 子任务取消下载
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package com.arialyy.aria.core.listener;
|
||||
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
|
||||
/**
|
||||
* Created by Aria.Lao on 2017/7/18.
|
||||
@@ -64,5 +64,5 @@ public interface IEventListener {
|
||||
* @param needRetry 是否需要重试{@code true} 需要
|
||||
* @param e 失败信息
|
||||
*/
|
||||
void onFail(boolean needRetry, BaseException e);
|
||||
void onFail(boolean needRetry, AriaException e);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.arialyy.aria.core.loader;
|
||||
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.inf.IThreadStateManager;
|
||||
import com.arialyy.aria.core.listener.IEventListener;
|
||||
@@ -154,33 +155,43 @@ public abstract class AbsNormalLoader<T extends AbsTaskWrapper> implements ILoad
|
||||
if (isBreak()) {
|
||||
return;
|
||||
}
|
||||
ALog.d(TAG, "启动定时器");
|
||||
mTimer = new ScheduledThreadPoolExecutor(1);
|
||||
mTimer.scheduleWithFixedDelay(new Runnable() {
|
||||
@Override public void run() {
|
||||
// 线程池中是不抛异常的,没有日志,很难定位问题,需要手动try-catch
|
||||
try {
|
||||
if (mStateManager == null) {
|
||||
ALog.e(TAG, "stateManager is null");
|
||||
} else if (mStateManager.isComplete()
|
||||
|| mStateManager.isFail()
|
||||
|| !isRunning()
|
||||
|| isBreak()) {
|
||||
//ALog.d(TAG, "isComplete = " + mStateManager.isComplete()
|
||||
// + "; isFail = " + mStateManager.isFail()
|
||||
// + "; isRunning = " + isRunning()
|
||||
// + "; isBreak = " + isBreak());
|
||||
ThreadTaskManager.getInstance().removeTaskThread(mTaskWrapper.getKey());
|
||||
closeTimer();
|
||||
onDestroy();
|
||||
} else if (mStateManager.getCurrentProgress() >= 0) {
|
||||
mListener.onProgress(mStateManager.getCurrentProgress());
|
||||
ALog.d(TAG, String.format("启动定时器,delayTimer = %s, updateInterval = %s", delayTimer(),
|
||||
mUpdateInterval));
|
||||
closeTimer();
|
||||
try {
|
||||
mTimer = new ScheduledThreadPoolExecutor(1);
|
||||
mTimer.scheduleWithFixedDelay(new Runnable() {
|
||||
@Override public void run() {
|
||||
// 线程池中是不抛异常的,没有日志,很难定位问题,需要手动try-catch
|
||||
try {
|
||||
if (mStateManager == null) {
|
||||
ALog.e(TAG, "stateManager is null");
|
||||
} else if (mStateManager.isComplete()
|
||||
|| mStateManager.isFail()
|
||||
|| !isRunning()
|
||||
|| isBreak()) {
|
||||
//ALog.d(TAG, "isComplete = " + mStateManager.isComplete()
|
||||
// + "; isFail = " + mStateManager.isFail()
|
||||
// + "; isRunning = " + isRunning()
|
||||
// + "; isBreak = " + isBreak());
|
||||
ThreadTaskManager.getInstance().removeTaskThread(mTaskWrapper.getKey());
|
||||
closeTimer();
|
||||
onDestroy();
|
||||
} else if (mStateManager.getCurrentProgress() >= 0) {
|
||||
Log.d(TAG, "running...");
|
||||
mListener.onProgress(mStateManager.getCurrentProgress());
|
||||
} else {
|
||||
Log.d(TAG, "未知状态");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, delayTimer(), mUpdateInterval, TimeUnit.MILLISECONDS);
|
||||
}, delayTimer(), mUpdateInterval, TimeUnit.MILLISECONDS);
|
||||
} catch (Exception e) {
|
||||
ALog.e(TAG, "启动定时器失败");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void closeTimer() {
|
||||
|
||||
@@ -19,7 +19,7 @@ package com.arialyy.aria.core.loader;
|
||||
import com.arialyy.aria.core.inf.IUtil;
|
||||
import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
|
||||
@@ -135,7 +135,7 @@ public abstract class AbsNormalLoaderUtil implements IUtil {
|
||||
return mListener;
|
||||
}
|
||||
|
||||
protected void fail(BaseException e, boolean needRetry) {
|
||||
protected void fail(AriaException e, boolean needRetry) {
|
||||
if (isStop || isCancel) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* 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.loader;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.inf.IThreadStateManager;
|
||||
import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.FileUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* 线程任务管理器,用于处理多线程下载时任务的状态回调
|
||||
*/
|
||||
public class GroupSubThreadStateManager implements IThreadStateManager {
|
||||
private final String TAG = CommonUtil.getClassName(this);
|
||||
|
||||
/**
|
||||
* 任务状态回调
|
||||
*/
|
||||
private Handler mHandler;//SimpleSchedulers
|
||||
private int mThreadNum; // 启动的线程总数
|
||||
private AtomicInteger mCancelNum = new AtomicInteger(0); // 已经取消的线程的数
|
||||
private AtomicInteger mStopNum = new AtomicInteger(0); // 已经停止的线程数
|
||||
private AtomicInteger mFailNum = new AtomicInteger(0); // 失败的线程数
|
||||
private AtomicInteger mCompleteNum = new AtomicInteger(0); // 完成的线程数
|
||||
private long mProgress; //当前总进度
|
||||
private TaskRecord mTaskRecord; // 任务记录
|
||||
private Looper mLooper;
|
||||
private String mKey;
|
||||
/**
|
||||
* @param handler 任务事件
|
||||
*/
|
||||
public GroupSubThreadStateManager(Handler handler,String key) {
|
||||
mHandler = handler;
|
||||
mKey = key;
|
||||
}
|
||||
|
||||
@Override public void setLooper(TaskRecord taskRecord, Looper looper) {
|
||||
mTaskRecord = taskRecord;
|
||||
mThreadNum = mTaskRecord.threadNum;
|
||||
mLooper = looper;
|
||||
}
|
||||
|
||||
private void checkLooper() {
|
||||
if (mTaskRecord == null) {
|
||||
throw new NullPointerException("任务记录为空");
|
||||
}
|
||||
if (mLooper == null) {
|
||||
throw new NullPointerException("Looper为空");
|
||||
}
|
||||
}
|
||||
|
||||
private Handler.Callback callback = new Handler.Callback() {
|
||||
@Override public boolean handleMessage(Message msg) {
|
||||
checkLooper();
|
||||
switch (msg.what) {
|
||||
case STATE_STOP:
|
||||
mStopNum.getAndIncrement();
|
||||
if (isStop()) {
|
||||
quitLooper();
|
||||
}
|
||||
sendMessageFromMsg(msg);
|
||||
break;
|
||||
case STATE_CANCEL:
|
||||
mCancelNum.getAndIncrement();
|
||||
if (isCancel()) {
|
||||
quitLooper();
|
||||
}
|
||||
sendMessageFromMsg(msg);
|
||||
break;
|
||||
case STATE_FAIL:
|
||||
mFailNum.getAndIncrement();
|
||||
if (isFail()) {
|
||||
sendMessageFromMsg(msg);
|
||||
|
||||
/* Bundle b = msg.getData();
|
||||
mListener.onFail(b.getBoolean(DATA_RETRY, false),
|
||||
(AriaException) b.getSerializable(DATA_ERROR_INFO));*/
|
||||
quitLooper();
|
||||
}
|
||||
//sendMessageFromMsg(msg);
|
||||
break;
|
||||
case STATE_COMPLETE:
|
||||
mCompleteNum.getAndIncrement();
|
||||
if (isComplete()) {
|
||||
ALog.d(TAG, "isComplete, completeNum = " + mCompleteNum);
|
||||
//if (mTaskRecord.taskType == ITaskWrapper.D_SFTP) {
|
||||
// mergerSFtp();
|
||||
// mListener.onComplete();
|
||||
//} else
|
||||
|
||||
if (mTaskRecord.isBlock) {
|
||||
/*if (mergeFile()) {
|
||||
mListener.onComplete();
|
||||
} else {
|
||||
mListener.onFail(false, null);
|
||||
}*/
|
||||
if (!mergeFile()) {
|
||||
Bundle b=msg.getData();
|
||||
b.putBoolean(IThreadStateManager.DATA_RETRY, false);
|
||||
msg.setData(b);
|
||||
msg.what = STATE_FAIL;
|
||||
sendMessageFromMsg(msg);
|
||||
}
|
||||
sendMessageFromMsg(msg);
|
||||
} else {
|
||||
sendMessageFromMsg(msg);
|
||||
//mListener.onComplete();
|
||||
}
|
||||
quitLooper();
|
||||
}else if (isFail()) {
|
||||
sendMessageFromMsg(msg);
|
||||
quitLooper();
|
||||
}
|
||||
break;
|
||||
case STATE_RUNNING:
|
||||
Bundle b = msg.getData();
|
||||
if (b != null) {
|
||||
long len = b.getLong(IThreadStateManager.DATA_ADD_LEN, 0);
|
||||
mProgress += len;
|
||||
}
|
||||
msg.obj=mProgress;
|
||||
sendMessageFromMsg(msg);
|
||||
|
||||
break;
|
||||
case STATE_UPDATE_PROGRESS:
|
||||
|
||||
if (msg.obj == null) {
|
||||
mProgress = updateBlockProgress();
|
||||
} else if (msg.obj instanceof Long) {
|
||||
mProgress = (long) msg.obj;
|
||||
}
|
||||
msg.obj=mProgress;
|
||||
sendMessageFromMsg(msg);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public void sendMessageFromMsg(Message msg){
|
||||
Message mMsg=mHandler.obtainMessage();
|
||||
Bundle b=mMsg.getData();
|
||||
b.putString(IThreadStateManager.DATA_THREAD_NAME,mKey);
|
||||
msg.setData(b);
|
||||
mMsg.copyFrom(msg);
|
||||
mHandler.sendMessage(mMsg);
|
||||
}
|
||||
};
|
||||
|
||||
@Override public void updateCurrentProgress(long currentProgress) {
|
||||
mProgress = currentProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出looper循环
|
||||
*/
|
||||
private void quitLooper() {
|
||||
mLooper.quit();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前任务下载进度
|
||||
*
|
||||
* @return 当前任务下载进度
|
||||
*/
|
||||
@Override
|
||||
public long getCurrentProgress() {
|
||||
return mProgress;
|
||||
}
|
||||
|
||||
@Override public Handler.Callback getHandlerCallback() {
|
||||
return callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有子线程是否都已经停止
|
||||
*/
|
||||
public boolean isStop() {
|
||||
//ALog.d(TAG,
|
||||
// String.format("isStop; stopNum: %s, cancelNum: %s, failNum: %s, completeNum: %s", mStopNum,
|
||||
// mCancelNum, mFailNum, mCompleteNum));
|
||||
return mStopNum.get() == mThreadNum || mStopNum.get() + mCompleteNum.get() == mThreadNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有子线程是否都已经失败
|
||||
*/
|
||||
@Override
|
||||
public boolean isFail() {
|
||||
//ALog.d(TAG,
|
||||
// String.format("isFail; stopNum: %s, cancelNum: %s, failNum: %s, completeNum: %s", mStopNum,
|
||||
// mCancelNum, mFailNum, mCompleteNum));
|
||||
return mCompleteNum.get() != mThreadNum
|
||||
&& (mFailNum.get() == mThreadNum || mFailNum.get() + mCompleteNum.get() == mThreadNum);
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有子线程是否都已经完成
|
||||
*/
|
||||
@Override
|
||||
public boolean isComplete() {
|
||||
//ALog.d(TAG,
|
||||
// String.format("isComplete; stopNum: %s, cancelNum: %s, failNum: %s, completeNum: %s",
|
||||
// mStopNum,
|
||||
// mCancelNum, mFailNum, mCompleteNum));
|
||||
return mCompleteNum.get() == mThreadNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有子线程是否都已经取消
|
||||
*/
|
||||
public boolean isCancel() {
|
||||
//ALog.d(TAG, String.format("isCancel; stopNum: %s, cancelNum: %s, failNum: %s, completeNum: %s",
|
||||
// mStopNum,
|
||||
// mCancelNum, mFailNum, mCompleteNum));
|
||||
return mCancelNum.get() == mThreadNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新分块任务s的真实进度
|
||||
*/
|
||||
private long updateBlockProgress() {
|
||||
long size = 0;
|
||||
for (int i = 0, len = mTaskRecord.threadRecords.size(); i < len; i++) {
|
||||
File temp = new File(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, i));
|
||||
if (temp.exists()) {
|
||||
size += temp.length();
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并sftp的分块
|
||||
*/
|
||||
private boolean mergerSFtp() {
|
||||
if (mTaskRecord.threadNum == 1) {
|
||||
File partFile = new File(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, 0));
|
||||
return partFile.renameTo(new File(mTaskRecord.filePath));
|
||||
}
|
||||
|
||||
List<String> partPath = new ArrayList<>();
|
||||
for (int i = 0, len = mTaskRecord.threadNum; i < len; i++) {
|
||||
partPath.add(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, i));
|
||||
}
|
||||
FileUtil.mergeSFtpFile(mTaskRecord.filePath, partPath, mTaskRecord.fileLength);
|
||||
for (String pp : partPath) {
|
||||
FileUtil.deleteFile(pp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并文件
|
||||
*
|
||||
* @return {@code true} 合并成功,{@code false}合并失败
|
||||
*/
|
||||
private boolean mergeFile() {
|
||||
if (mTaskRecord.threadNum == 1) {
|
||||
File partFile = new File(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, 0));
|
||||
return partFile.renameTo(new File(mTaskRecord.filePath));
|
||||
}
|
||||
|
||||
List<String> partPath = new ArrayList<>();
|
||||
for (int i = 0, len = mTaskRecord.threadNum; i < len; i++) {
|
||||
partPath.add(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, i));
|
||||
}
|
||||
boolean isSuccess = FileUtil.mergeFile(mTaskRecord.filePath, partPath);
|
||||
if (isSuccess) {
|
||||
for (String pp : partPath) {
|
||||
FileUtil.deleteFile(pp);
|
||||
}
|
||||
File targetFile = new File(mTaskRecord.filePath);
|
||||
if (targetFile.exists() && targetFile.length() > mTaskRecord.fileLength) {
|
||||
ALog.e(TAG, String.format("任务【%s】分块文件合并失败,下载长度超出文件真实长度,downloadLen: %s,fileSize: %s",
|
||||
targetFile.getName(), targetFile.length(), mTaskRecord.fileLength));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
ALog.e(TAG, "合并失败");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void accept(ILoaderVisitor visitor) {
|
||||
visitor.addComponent(this);
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ package com.arialyy.aria.core.loader;
|
||||
|
||||
import com.arialyy.aria.core.common.AbsEntity;
|
||||
import com.arialyy.aria.core.common.CompleteInfo;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
|
||||
/**
|
||||
* 任务信息采集
|
||||
@@ -47,6 +47,6 @@ public interface IInfoTask extends ILoaderComponent {
|
||||
*
|
||||
* @param e 错误信息
|
||||
*/
|
||||
void onFail(AbsEntity entity, BaseException e, boolean needRetry);
|
||||
void onFail(AbsEntity entity, AriaException e, boolean needRetry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,14 @@ import com.arialyy.aria.core.inf.IThreadStateManager;
|
||||
import com.arialyy.aria.core.listener.IDLoadListener;
|
||||
import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.core.manager.ThreadTaskManager;
|
||||
import com.arialyy.aria.core.task.AbsTask;
|
||||
import com.arialyy.aria.core.task.IThreadTask;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.FileUtil;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 单文件
|
||||
@@ -99,6 +102,9 @@ public class NormalLoader<T extends AbsTaskWrapper> extends AbsNormalLoader<T> {
|
||||
}
|
||||
|
||||
protected void startThreadTask() {
|
||||
if (isBreak()){
|
||||
return;
|
||||
}
|
||||
|
||||
if (getListener() instanceof IDLoadListener) {
|
||||
((IDLoadListener) getListener()).onPostPre(getEntity().getFileSize());
|
||||
@@ -150,7 +156,7 @@ public class NormalLoader<T extends AbsTaskWrapper> extends AbsNormalLoader<T> {
|
||||
startThreadTask();
|
||||
}
|
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
|
||||
@Override public void onFail(AbsEntity entity, AriaException e, boolean needRetry) {
|
||||
getListener().onFail(needRetry, e);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -115,7 +115,7 @@ public final class NormalTTBuilder implements IThreadTaskBuilder {
|
||||
b = new Bundle();
|
||||
}
|
||||
b.putString(IThreadStateManager.DATA_THREAD_NAME,
|
||||
CommonUtil.getThreadName(getEntity().getUrl(), tr.threadId));
|
||||
CommonUtil.getThreadName(getEntity().getKey(), tr.threadId));
|
||||
msg.setData(b);
|
||||
msg.sendToTarget();
|
||||
continue;
|
||||
|
||||
@@ -22,28 +22,30 @@ import android.os.Message;
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.inf.IThreadStateManager;
|
||||
import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.FileUtil;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* 线程任务管理器,用于处理多线程下载时任务的状态回调
|
||||
*/
|
||||
public class NormalThreadStateManager implements IThreadStateManager {
|
||||
private final String TAG = "ThreadTaskStateManager";
|
||||
private final String TAG = CommonUtil.getClassName(this);
|
||||
|
||||
/**
|
||||
* 任务状态回调
|
||||
*/
|
||||
private IEventListener mListener;
|
||||
private int mThreadNum; // 启动的线程总数
|
||||
private int mCancelNum = 0; // 已经取消的线程的数
|
||||
private int mStopNum = 0; // 已经停止的线程数
|
||||
private int mFailNum = 0; // 失败的线程数
|
||||
private int mCompleteNum = 0; // 完成的线程数
|
||||
private AtomicInteger mCancelNum = new AtomicInteger(0); // 已经取消的线程的数
|
||||
private AtomicInteger mStopNum = new AtomicInteger(0); // 已经停止的线程数
|
||||
private AtomicInteger mFailNum = new AtomicInteger(0); // 失败的线程数
|
||||
private AtomicInteger mCompleteNum = new AtomicInteger(0); // 完成的线程数
|
||||
private long mProgress; //当前总进度
|
||||
private TaskRecord mTaskRecord; // 任务记录
|
||||
private Looper mLooper;
|
||||
@@ -75,28 +77,28 @@ public class NormalThreadStateManager implements IThreadStateManager {
|
||||
checkLooper();
|
||||
switch (msg.what) {
|
||||
case STATE_STOP:
|
||||
mStopNum++;
|
||||
mStopNum.getAndIncrement();
|
||||
if (isStop()) {
|
||||
quitLooper();
|
||||
}
|
||||
break;
|
||||
case STATE_CANCEL:
|
||||
mCancelNum++;
|
||||
mCancelNum.getAndIncrement();
|
||||
if (isCancel()) {
|
||||
quitLooper();
|
||||
}
|
||||
break;
|
||||
case STATE_FAIL:
|
||||
mFailNum++;
|
||||
mFailNum.getAndIncrement();
|
||||
if (isFail()) {
|
||||
Bundle b = msg.getData();
|
||||
mListener.onFail(b.getBoolean(DATA_RETRY, false),
|
||||
(BaseException) b.getSerializable(DATA_ERROR_INFO));
|
||||
(AriaException) b.getSerializable(DATA_ERROR_INFO));
|
||||
quitLooper();
|
||||
}
|
||||
break;
|
||||
case STATE_COMPLETE:
|
||||
mCompleteNum++;
|
||||
mCompleteNum.getAndIncrement();
|
||||
if (isComplete()) {
|
||||
ALog.d(TAG, "isComplete, completeNum = " + mCompleteNum);
|
||||
//if (mTaskRecord.taskType == ITaskWrapper.D_SFTP) {
|
||||
@@ -168,7 +170,7 @@ public class NormalThreadStateManager implements IThreadStateManager {
|
||||
//ALog.d(TAG,
|
||||
// String.format("isStop; stopNum: %s, cancelNum: %s, failNum: %s, completeNum: %s", mStopNum,
|
||||
// mCancelNum, mFailNum, mCompleteNum));
|
||||
return mStopNum == mThreadNum || mStopNum + mCompleteNum == mThreadNum;
|
||||
return mStopNum.get() == mThreadNum || mStopNum.get() + mCompleteNum.get() == mThreadNum;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,8 +181,8 @@ public class NormalThreadStateManager implements IThreadStateManager {
|
||||
//ALog.d(TAG,
|
||||
// String.format("isFail; stopNum: %s, cancelNum: %s, failNum: %s, completeNum: %s", mStopNum,
|
||||
// mCancelNum, mFailNum, mCompleteNum));
|
||||
return mCompleteNum != mThreadNum
|
||||
&& (mFailNum == mThreadNum || mFailNum + mCompleteNum == mThreadNum);
|
||||
return mCompleteNum.get() != mThreadNum
|
||||
&& (mFailNum.get() == mThreadNum || mFailNum.get() + mCompleteNum.get() == mThreadNum);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,7 +194,7 @@ public class NormalThreadStateManager implements IThreadStateManager {
|
||||
// String.format("isComplete; stopNum: %s, cancelNum: %s, failNum: %s, completeNum: %s",
|
||||
// mStopNum,
|
||||
// mCancelNum, mFailNum, mCompleteNum));
|
||||
return mCompleteNum == mThreadNum;
|
||||
return mCompleteNum.get() == mThreadNum;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,7 +204,7 @@ public class NormalThreadStateManager implements IThreadStateManager {
|
||||
//ALog.d(TAG, String.format("isCancel; stopNum: %s, cancelNum: %s, failNum: %s, completeNum: %s",
|
||||
// mStopNum,
|
||||
// mCancelNum, mFailNum, mCompleteNum));
|
||||
return mCancelNum == mThreadNum;
|
||||
return mCancelNum.get() == mThreadNum;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.arialyy.aria.core.loader;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
@@ -27,10 +28,11 @@ import com.arialyy.aria.core.manager.ThreadTaskManager;
|
||||
import com.arialyy.aria.core.task.IThreadTask;
|
||||
import com.arialyy.aria.core.task.ThreadTask;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -46,9 +48,10 @@ public final class SubLoader implements ILoader, ILoaderVisitor {
|
||||
private IInfoTask infoTask;
|
||||
private IThreadTaskBuilder ttBuild;
|
||||
private IRecordHandler recordHandler;
|
||||
private IThreadTask threadTask;
|
||||
private List<IThreadTask> mTask = new ArrayList<>();
|
||||
private String parentKey;
|
||||
private TaskRecord record;
|
||||
protected IThreadStateManager mStateManager;
|
||||
|
||||
public SubLoader(AbsTaskWrapper wrapper, Handler schedulers) {
|
||||
this.wrapper = wrapper;
|
||||
@@ -93,7 +96,21 @@ public final class SubLoader implements ILoader, ILoaderVisitor {
|
||||
}
|
||||
|
||||
private void handlerTask() {
|
||||
if (isBreak()) {
|
||||
return;
|
||||
}
|
||||
Looper looper = Looper.myLooper();
|
||||
if (looper == null) {
|
||||
Looper.prepare();
|
||||
looper = Looper.myLooper();
|
||||
}
|
||||
|
||||
record = recordHandler.getRecord(wrapper.getEntity().getFileSize());
|
||||
if (record == null){
|
||||
ALog.d(TAG, "子任务记录为空");
|
||||
sendFailState(false);
|
||||
return;
|
||||
}
|
||||
if (record.threadRecords != null
|
||||
&& !TextUtils.isEmpty(record.filePath)
|
||||
&& new File(record.filePath).exists()
|
||||
@@ -103,7 +120,9 @@ public final class SubLoader implements ILoader, ILoaderVisitor {
|
||||
sendNormalState(IThreadStateManager.STATE_COMPLETE);
|
||||
return;
|
||||
}
|
||||
List<IThreadTask> task = ttBuild.buildThreadTask(record, schedulers);
|
||||
List<IThreadTask> task =
|
||||
ttBuild.buildThreadTask(record, new Handler(looper, mStateManager.getHandlerCallback()));
|
||||
mStateManager.setLooper(record, looper);
|
||||
if (task == null || task.isEmpty()) {
|
||||
ALog.e(TAG, "创建子任务的线程任务失败,key:" + wrapper.getKey());
|
||||
sendFailState(false);
|
||||
@@ -114,17 +133,24 @@ public final class SubLoader implements ILoader, ILoaderVisitor {
|
||||
sendFailState(false);
|
||||
return;
|
||||
}
|
||||
|
||||
sendNormalState(IThreadStateManager.STATE_PRE);
|
||||
threadTask = task.get(0);
|
||||
mTask.addAll(task);
|
||||
try {
|
||||
ThreadTaskManager.getInstance().startThread(parentKey, threadTask);
|
||||
for (IThreadTask iThreadTask : mTask) {
|
||||
ThreadTaskManager.getInstance().startThread(parentKey, iThreadTask);
|
||||
}
|
||||
|
||||
sendNormalState(IThreadStateManager.STATE_START);
|
||||
|
||||
mStateManager.updateCurrentProgress(getWrapper().getEntity().getCurrentProgress());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Looper.loop();
|
||||
}
|
||||
|
||||
public TaskRecord getRecord(){
|
||||
public TaskRecord getRecord() {
|
||||
return record;
|
||||
}
|
||||
|
||||
@@ -138,8 +164,10 @@ public final class SubLoader implements ILoader, ILoaderVisitor {
|
||||
|
||||
public void retryTask() {
|
||||
try {
|
||||
if (threadTask != null) {
|
||||
threadTask.call();
|
||||
if (!mTask.isEmpty()) {
|
||||
for (IThreadTask iThreadTask : mTask) {
|
||||
iThreadTask.call();
|
||||
}
|
||||
} else {
|
||||
ALog.e(TAG, "子任务的线程任务为空");
|
||||
}
|
||||
@@ -154,11 +182,19 @@ public final class SubLoader implements ILoader, ILoaderVisitor {
|
||||
return;
|
||||
}
|
||||
isStop = true;
|
||||
threadTask.stop();
|
||||
for (IThreadTask iThreadTask : mTask) {
|
||||
iThreadTask.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean isRunning() {
|
||||
return threadTask != null && !threadTask.isBreak();
|
||||
if (mTask.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (IThreadTask iThreadTask : mTask) {
|
||||
if (!iThreadTask.isBreak()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public void cancel() {
|
||||
@@ -167,7 +203,9 @@ public final class SubLoader implements ILoader, ILoaderVisitor {
|
||||
return;
|
||||
}
|
||||
isCancel = true;
|
||||
threadTask.cancel();
|
||||
for (IThreadTask iThreadTask : mTask) {
|
||||
iThreadTask.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean isBreak() {
|
||||
@@ -188,12 +226,9 @@ public final class SubLoader implements ILoader, ILoaderVisitor {
|
||||
return CommonUtil.getThreadName(wrapper.getKey(), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 子任务不需要实现这个
|
||||
*/
|
||||
@Deprecated
|
||||
@Override public long getCurrentProgress() {
|
||||
return 0;
|
||||
return isRunning() ? mStateManager.getCurrentProgress()
|
||||
: getWrapper().getEntity().getCurrentProgress();
|
||||
}
|
||||
|
||||
@Override public void addComponent(IRecordHandler recordHandler) {
|
||||
@@ -207,17 +242,14 @@ public final class SubLoader implements ILoader, ILoaderVisitor {
|
||||
handlerTask();
|
||||
}
|
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
|
||||
@Override public void onFail(AbsEntity entity, AriaException e, boolean needRetry) {
|
||||
sendFailState(needRetry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 子任务不需要实现这个
|
||||
*/
|
||||
@Override public void addComponent(IThreadStateManager threadState) {
|
||||
// 子任务不需要实现这个
|
||||
mStateManager = threadState;
|
||||
}
|
||||
|
||||
@Override public void addComponent(IThreadTaskBuilder builder) {
|
||||
|
||||
@@ -255,7 +255,7 @@ public class ThreadTaskManager {
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ALog.e(TAG, e);
|
||||
ALog.e(TAG, "", e);
|
||||
return;
|
||||
}
|
||||
mExePool.submit(task);
|
||||
|
||||
@@ -27,8 +27,9 @@ public interface IBandWidthUrlConverter extends IEventHandler {
|
||||
* 转换码率地址为可用的http地址,对于某些服务器,返回的切片信息有可能是相对地址,也可能是处理过的,
|
||||
* 对于这种情况,你需要使用url转换器将地址转换为可正常访问的http地址
|
||||
*
|
||||
* @param m3u8Url m3u8url地址
|
||||
* @param bandWidthUrl 原始码率地址
|
||||
* @return 可正常访问的http地址
|
||||
*/
|
||||
String convert(String bandWidthUrl);
|
||||
String convert(String m3u8Url, String bandWidthUrl);
|
||||
}
|
||||
|
||||
@@ -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.core.processor;
|
||||
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.inf.IEventHandler;
|
||||
|
||||
import java.net.URLConnection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Http文件名适配器
|
||||
*/
|
||||
public interface IHttpFileNameAdapter extends IEventHandler {
|
||||
|
||||
/**
|
||||
* 根据header中的数据获取文件名字
|
||||
* @param headers header参数{@link URLConnection#getHeaderFields()}
|
||||
* @param key 这里如果传entity可能会导致entity属性变更而其他地方没有改变,所以就传了个key 减少可操作范围
|
||||
* @return 文件长度
|
||||
*/
|
||||
String handleFileName(Map<String, List<String>> headers, String key);
|
||||
}
|
||||
@@ -30,5 +30,5 @@ public interface ILiveTsUrlConverter extends IEventHandler {
|
||||
* @param tsUrl ts文件下载地址
|
||||
* @return 转换后的http地址
|
||||
*/
|
||||
public String convert(String m3u8Url, String tsUrl);
|
||||
String convert(String m3u8Url, String tsUrl);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import com.arialyy.aria.core.ThreadRecord;
|
||||
import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
import com.arialyy.aria.core.config.BaseTaskConfig;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.util.BandwidthLimiter;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
|
||||
@@ -110,7 +110,7 @@ public abstract class AbsThreadTaskAdapter implements IThreadTaskAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
protected void fail(BaseException ex, boolean needRetry) {
|
||||
protected void fail(AriaException ex, boolean needRetry) {
|
||||
if (mObserver != null) {
|
||||
mObserver.updateFailState(ex, needRetry);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class DownloadTask extends AbsTask<DTaskWrapper> {
|
||||
}
|
||||
|
||||
@Override public String getKey() {
|
||||
return mTaskWrapper.getEntity().getUrl();
|
||||
return mTaskWrapper.getEntity().getKey();
|
||||
}
|
||||
|
||||
public DownloadEntity getDownloadEntity() {
|
||||
|
||||
@@ -17,7 +17,7 @@ package com.arialyy.aria.core.task;
|
||||
|
||||
import android.os.Bundle;
|
||||
import com.arialyy.aria.core.inf.IThreadStateManager;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
|
||||
/**
|
||||
* 线程任务观察者
|
||||
@@ -44,7 +44,7 @@ public interface IThreadTaskObserver {
|
||||
*
|
||||
* @param needRetry 是否需要重试,一般是网络错误才需要重试
|
||||
*/
|
||||
void updateFailState(BaseException e, boolean needRetry);
|
||||
void updateFailState(AriaException e, boolean needRetry);
|
||||
|
||||
/**
|
||||
* 更新进度
|
||||
|
||||
@@ -20,16 +20,17 @@ import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.Process;
|
||||
import android.util.Log;
|
||||
import com.arialyy.aria.core.AriaConfig;
|
||||
import com.arialyy.aria.core.ThreadRecord;
|
||||
import com.arialyy.aria.core.common.AbsEntity;
|
||||
import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.inf.IThreadStateManager;
|
||||
import com.arialyy.aria.core.listener.ISchedulers;
|
||||
import com.arialyy.aria.core.manager.ThreadTaskManager;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.AriaException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
@@ -50,7 +51,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
*/
|
||||
private final int RETRY_NUM = 2;
|
||||
private final String TAG = CommonUtil.getClassName(getClass());
|
||||
private IEntity mEntity;
|
||||
private AbsEntity mEntity;
|
||||
protected AbsTaskWrapper mTaskWrapper;
|
||||
private int mFailTimes = 0;
|
||||
private long mLastSaveTime, mLastSendProgressTime;
|
||||
@@ -147,7 +148,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
/**
|
||||
* 获取实体
|
||||
*/
|
||||
protected IEntity getEntity() {
|
||||
protected AbsEntity getEntity() {
|
||||
return mEntity;
|
||||
}
|
||||
|
||||
@@ -244,7 +245,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
|
||||
@Override public String getThreadName() {
|
||||
return mThreadName == null ? (mThreadName =
|
||||
CommonUtil.getThreadName(getConfig().url, getThreadId())) : mThreadName;
|
||||
CommonUtil.getThreadName(getEntity().getKey(), getThreadId())) : mThreadName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -323,7 +324,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
*
|
||||
* @param needRetry 是否需要重试,一般是网络错误才需要重试
|
||||
*/
|
||||
@Override public synchronized void updateFailState(BaseException e, boolean needRetry) {
|
||||
@Override public synchronized void updateFailState(AriaException e, boolean needRetry) {
|
||||
fail(mRangeProgress, e, needRetry);
|
||||
}
|
||||
|
||||
@@ -396,7 +397,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
*
|
||||
* @param subCurrentLocation 当前子线程进度
|
||||
*/
|
||||
protected void fail(final long subCurrentLocation, BaseException ex, boolean needRetry) {
|
||||
protected void fail(final long subCurrentLocation, AriaException ex, boolean needRetry) {
|
||||
if (ex != null) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
@@ -457,7 +458,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
ThreadTaskManager.getInstance().retryThread(this);
|
||||
} else {
|
||||
ALog.e(TAG, String.format("任务【%s】执行失败", getFileName()));
|
||||
sendFailMsg(null, false);
|
||||
sendFailMsg(null, needRetry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,7 +506,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
/**
|
||||
* 发送失败信息
|
||||
*/
|
||||
private void sendFailMsg(BaseException e, boolean needRetry) {
|
||||
private void sendFailMsg(AriaException e, boolean needRetry) {
|
||||
Bundle b = new Bundle();
|
||||
b.putBoolean(IThreadStateManager.DATA_RETRY, needRetry);
|
||||
if (e != null) {
|
||||
|
||||
@@ -39,7 +39,7 @@ public class UploadTask extends AbsTask<UTaskWrapper> {
|
||||
}
|
||||
|
||||
@Override public String getKey() {
|
||||
return mTaskWrapper.getEntity().getFilePath();
|
||||
return mTaskWrapper.getEntity().getKey();
|
||||
}
|
||||
|
||||
public UploadEntity getEntity() {
|
||||
|
||||
@@ -15,14 +15,22 @@
|
||||
*/
|
||||
package com.arialyy.aria.exception;
|
||||
|
||||
public class AriaException extends BaseException {
|
||||
private static final String ARIA_NET_EXCEPTION = "Aria Exception:";
|
||||
public class AriaException extends Exception {
|
||||
|
||||
private String tag;
|
||||
|
||||
public AriaException(String tag, String message) {
|
||||
super(tag, String.format("%s%s", ARIA_NET_EXCEPTION, message));
|
||||
super(message);
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
public AriaException(String tag, String message, Exception e) {
|
||||
super(tag, message, e);
|
||||
super(String.format("%s, %s\n%s", tag, message == null ? "" : message,
|
||||
e == null ? "" : e.getMessage()));
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
package com.arialyy.aria.exception;
|
||||
|
||||
public class M3U8Exception extends BaseException{
|
||||
private static final String M3U8_EXCEPTION = "M3U8 Exception:";
|
||||
public class AriaFTPException extends AriaException {
|
||||
private static final String FTP_EXCEPTION = "Aria FTP Exception:";
|
||||
|
||||
public M3U8Exception(String tag, String message) {
|
||||
super(tag, String.format("%s%s", M3U8_EXCEPTION, message));
|
||||
public AriaFTPException(String tag, String message) {
|
||||
super(tag, String.format("%s\n%s", FTP_EXCEPTION, message));
|
||||
}
|
||||
|
||||
public M3U8Exception(String tag, String message, Exception e){
|
||||
public AriaFTPException(String tag, String message, Exception e) {
|
||||
super(tag, message, e);
|
||||
}
|
||||
}
|
||||
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
package com.arialyy.aria.exception;
|
||||
|
||||
public class AriaLoginException extends BaseException{
|
||||
private static final String ARIA_NET_EXCEPTION = "Aria Login Exception:";
|
||||
public class AriaHTTPException extends AriaException {
|
||||
private static final String HTTP_EXCEPTION = "Aria HTTP Exception:";
|
||||
|
||||
public AriaLoginException(String tag, String message) {
|
||||
super(tag, String.format("%s%s", ARIA_NET_EXCEPTION, message));
|
||||
public AriaHTTPException(String tag, String message) {
|
||||
super(tag, String.format("%s\n%s", HTTP_EXCEPTION, message));
|
||||
}
|
||||
|
||||
public AriaLoginException(String tag, String message, Exception e){
|
||||
public AriaHTTPException(String tag, String message, Exception e) {
|
||||
super(tag, message, e);
|
||||
}
|
||||
}
|
||||
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
package com.arialyy.aria.exception;
|
||||
|
||||
public class AriaIOException extends BaseException{
|
||||
private static final String ARIA_NET_EXCEPTION = "Aria Net Exception:";
|
||||
public class AriaM3U8Exception extends AriaException {
|
||||
private static final String M3U8_EXCEPTION = "Aria M3U8 Exception:";
|
||||
|
||||
public AriaIOException(String tag, String message) {
|
||||
super(tag, String.format("%s%s", ARIA_NET_EXCEPTION, message));
|
||||
public AriaM3U8Exception(String tag, String message) {
|
||||
super(tag, String.format("%s\n%s", M3U8_EXCEPTION, message));
|
||||
}
|
||||
|
||||
public AriaIOException(String tag, String message, Exception e){
|
||||
public AriaM3U8Exception(String tag, String message, Exception e){
|
||||
super(tag, message, e);
|
||||
}
|
||||
}
|
||||
@@ -15,17 +15,14 @@
|
||||
*/
|
||||
package com.arialyy.aria.exception;
|
||||
|
||||
/**
|
||||
* 任务异常
|
||||
*/
|
||||
public class TaskException extends BaseException {
|
||||
private static final String ARIA_TASK_EXCEPTION = "Aria Task Exception:";
|
||||
public class AriaSFTPException extends AriaException {
|
||||
private static final String SFTP_EXCEPTION = "Aria SFTP Exception:";
|
||||
|
||||
public TaskException(String tag, String detailMessage) {
|
||||
super(tag, String.format("%s, %s", ARIA_TASK_EXCEPTION, detailMessage));
|
||||
public AriaSFTPException(String tag, String message) {
|
||||
super(tag, String.format("%s\n%s", SFTP_EXCEPTION, message));
|
||||
}
|
||||
|
||||
public TaskException(String tag, String message, Exception e){
|
||||
public AriaSFTPException(String tag, String message, Exception e) {
|
||||
super(tag, message, e);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +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.exception;
|
||||
|
||||
public abstract class BaseException extends Exception {
|
||||
|
||||
private String tag;
|
||||
|
||||
public BaseException(String tag, String message) {
|
||||
super(message);
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
public BaseException(String tag, String message, Exception e) {
|
||||
super(String.format("%s\n%s", message == null ? "" : message, e == null ? "" : e.getMessage()));
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
@@ -1,32 +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.exception;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2017/1/18.
|
||||
* Aria 文件异常
|
||||
*/
|
||||
public class FileException extends BaseException {
|
||||
private static final String ARIA_FILE_EXCEPTION = "Aria File Exception:";
|
||||
|
||||
public FileException(String tag, String detailMessage) {
|
||||
super(tag, String.format("%s%s", ARIA_FILE_EXCEPTION, detailMessage));
|
||||
}
|
||||
|
||||
public FileException(String tag, String message, Exception e){
|
||||
super(tag, message, e);
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -98,7 +99,7 @@ class DelegateFind extends AbsDelegate {
|
||||
*/
|
||||
<T extends AbsDbWrapper> List<T> findRelationData(SQLiteDatabase db, Class<T> clazz,
|
||||
String... expression) {
|
||||
return exeRelationSql(db, clazz, 1, 10, expression);
|
||||
return exeRelationSql(db, clazz, 1, Integer.MAX_VALUE, expression);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,8 +139,8 @@ class DelegateFind extends AbsDelegate {
|
||||
Class parentClazz = Class.forName(one.getType().getName());
|
||||
Class childClazz = Class.forName(CommonUtil.getListParamType(many).getName());
|
||||
// 检查表
|
||||
SqlUtil.checkTable(db, parentClazz);
|
||||
SqlUtil.checkTable(db, childClazz);
|
||||
SqlUtil.checkOrCreateTable(db, parentClazz);
|
||||
SqlUtil.checkOrCreateTable(db, childClazz);
|
||||
final String pTableName = parentClazz.getSimpleName();
|
||||
final String cTableName = childClazz.getSimpleName();
|
||||
List<Field> pColumn = SqlUtil.getAllNotIgnoreField(parentClazz);
|
||||
@@ -215,12 +216,17 @@ class DelegateFind extends AbsDelegate {
|
||||
} else {
|
||||
sql = sb.toString();
|
||||
}
|
||||
boolean paged = false;
|
||||
if (page != -1 && num != -1) {
|
||||
sql = sql.concat(String.format(" LIMIT %s,%s", (page - 1) * num, num));
|
||||
paged = true;
|
||||
sql = sql.concat(String.format(" Group by %s LIMIT %s,%s",
|
||||
pTableName.concat(".").concat(m.parentColumn()), (page - 1) * num, num));
|
||||
}
|
||||
Cursor cursor = db.rawQuery(sql, null);
|
||||
List<T> data =
|
||||
newInstanceEntity(wrapperClazz, parentClazz, childClazz, cursor, pColumn, cColumn);
|
||||
newInstanceEntity(wrapperClazz, parentClazz, childClazz, cursor, pColumn, cColumn,
|
||||
paged, db, m.entityColumn(), m.parentColumn());
|
||||
|
||||
closeCursor(cursor);
|
||||
return data;
|
||||
} catch (ClassNotFoundException e) {
|
||||
@@ -243,7 +249,8 @@ class DelegateFind extends AbsDelegate {
|
||||
Class<T> wrapperClazz, Class<P> parentClazz,
|
||||
Class<C> childClazz,
|
||||
Cursor cursor,
|
||||
List<Field> pColumn, List<Field> cColumn) {
|
||||
List<Field> pColumn, List<Field> cColumn, boolean paged, SQLiteDatabase db,
|
||||
String entityColumn, String parentColumn) {
|
||||
List<T> wrappers = new ArrayList<>();
|
||||
SparseArray<List<DbEntity>> childs = new SparseArray<>(); // 所有子表数据
|
||||
SparseArray<DbEntity> parents = new SparseArray<>(); // 所有父表数据
|
||||
@@ -255,7 +262,15 @@ class DelegateFind extends AbsDelegate {
|
||||
childs.put(pRowId, new ArrayList<DbEntity>());
|
||||
parents.put(pRowId, createParent(pRowId, parentClazz, pColumn, cursor));
|
||||
}
|
||||
childs.get(pRowId).add(createChild(childClazz, cColumn, cursor));
|
||||
if (paged) {
|
||||
List<C> list = createChildren(db, childClazz, pColumn, entityColumn, parentColumn,
|
||||
parents.get(pRowId));
|
||||
if (list != null) {
|
||||
childs.get(pRowId).addAll(list);
|
||||
}
|
||||
} else {
|
||||
childs.get(pRowId).add(createChild(childClazz, cColumn, cursor));
|
||||
}
|
||||
}
|
||||
|
||||
List<Field> wFields = SqlUtil.getAllNotIgnoreField(wrapperClazz);
|
||||
@@ -286,6 +301,27 @@ class DelegateFind extends AbsDelegate {
|
||||
return wrappers;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建子对象集合
|
||||
*/
|
||||
private <T extends DbEntity> List<T> createChildren(SQLiteDatabase db, Class<T> childClazz,
|
||||
List<Field> pColumn,
|
||||
String entityColumn, String parentColumn, DbEntity parents)
|
||||
throws IllegalAccessException {
|
||||
|
||||
for (Field field : pColumn) {
|
||||
field.setAccessible(true);
|
||||
if (field.getName().equals(parentColumn)) {
|
||||
Object o = field.get(parents);
|
||||
if (o instanceof String) {
|
||||
o = URLEncoder.encode((String) o);
|
||||
}
|
||||
return findData(db, childClazz, entityColumn + "='" + o + "'");
|
||||
}
|
||||
}
|
||||
return new ArrayList<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建子对象
|
||||
*/
|
||||
@@ -424,7 +460,7 @@ class DelegateFind extends AbsDelegate {
|
||||
*/
|
||||
private <T extends DbEntity> List<T> exeNormalDataSql(SQLiteDatabase db, Class<T> clazz,
|
||||
String sql, String[] selectionArgs) {
|
||||
SqlUtil.checkTable(db, clazz);
|
||||
SqlUtil.checkOrCreateTable(db, clazz);
|
||||
Cursor cursor;
|
||||
if (selectionArgs != null) {
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class DelegateUpdate extends AbsDelegate {
|
||||
*/
|
||||
synchronized <T extends DbEntity> void delData(SQLiteDatabase db, Class<T> clazz,
|
||||
String... expression) {
|
||||
SqlUtil.checkTable(db, clazz);
|
||||
SqlUtil.checkOrCreateTable(db, clazz);
|
||||
db = checkDb(db);
|
||||
if (!CommonUtil.checkSqlExpression(expression)) {
|
||||
return;
|
||||
@@ -58,7 +58,7 @@ class DelegateUpdate extends AbsDelegate {
|
||||
* 修改某行数据
|
||||
*/
|
||||
synchronized void updateData(SQLiteDatabase db, DbEntity dbEntity) {
|
||||
SqlUtil.checkTable(db, dbEntity.getClass());
|
||||
SqlUtil.checkOrCreateTable(db, dbEntity.getClass());
|
||||
db = checkDb(db);
|
||||
ContentValues values = createValues(dbEntity);
|
||||
if (values != null) {
|
||||
@@ -111,7 +111,7 @@ class DelegateUpdate extends AbsDelegate {
|
||||
if (oldClazz == null || oldClazz != entity.getClass() || table == null) {
|
||||
oldClazz = entity.getClass();
|
||||
table = CommonUtil.getClassName(oldClazz);
|
||||
SqlUtil.checkTable(db, oldClazz);
|
||||
SqlUtil.checkOrCreateTable(db, oldClazz);
|
||||
}
|
||||
|
||||
ContentValues value = createValues(entity);
|
||||
@@ -133,7 +133,7 @@ class DelegateUpdate extends AbsDelegate {
|
||||
* 插入数据
|
||||
*/
|
||||
synchronized void insertData(SQLiteDatabase db, DbEntity dbEntity) {
|
||||
SqlUtil.checkTable(db, dbEntity.getClass());
|
||||
SqlUtil.checkOrCreateTable(db, dbEntity.getClass());
|
||||
db = checkDb(db);
|
||||
ContentValues values = createValues(dbEntity);
|
||||
if (values != null) {
|
||||
@@ -150,7 +150,7 @@ class DelegateUpdate extends AbsDelegate {
|
||||
*/
|
||||
private ContentValues createValues(DbEntity dbEntity) {
|
||||
List<Field> fields = CommonUtil.getAllFields(dbEntity.getClass());
|
||||
if (fields != null && fields.size() > 0) {
|
||||
if (fields.size() > 0) {
|
||||
ContentValues values = new ContentValues();
|
||||
try {
|
||||
for (Field field : fields) {
|
||||
|
||||
@@ -22,7 +22,11 @@ import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.ThreadRecord;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.M3U8Entity;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import java.io.File;
|
||||
@@ -40,6 +44,7 @@ import java.util.Set;
|
||||
final class SqlHelper extends SQLiteOpenHelper {
|
||||
private static final String TAG = "SqlHelper";
|
||||
private static volatile SqlHelper INSTANCE = null;
|
||||
private static boolean mainTmpDirSet = false;
|
||||
private Context mContext;
|
||||
|
||||
synchronized static SqlHelper init(Context context) {
|
||||
@@ -143,6 +148,39 @@ final class SqlHelper extends SQLiteOpenHelper {
|
||||
return db;
|
||||
}
|
||||
|
||||
@Override public SQLiteDatabase getWritableDatabase() {
|
||||
if (!mainTmpDirSet) {
|
||||
createDbCacheDir();
|
||||
return super.getWritableDatabase();
|
||||
}
|
||||
return super.getWritableDatabase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于修复 Too many open files 的问题
|
||||
* https://github.com/AriaLyy/Aria/issues/664
|
||||
*/
|
||||
@Override
|
||||
public SQLiteDatabase getReadableDatabase() {
|
||||
if (!mainTmpDirSet) {
|
||||
createDbCacheDir();
|
||||
return super.getReadableDatabase();
|
||||
}
|
||||
return super.getReadableDatabase();
|
||||
}
|
||||
|
||||
private void createDbCacheDir() {
|
||||
String cacheDir = mContext.getCacheDir().getPath() + "/AriaDbCacheDir";
|
||||
File cacheFile = new File(cacheDir);
|
||||
if (!cacheFile.exists()){
|
||||
boolean rs = cacheFile.mkdirs();
|
||||
ALog.d(TAG, rs + "");
|
||||
}
|
||||
super.getReadableDatabase()
|
||||
.execSQL("PRAGMA temp_store_directory = '" + cacheDir + "'");
|
||||
mainTmpDirSet = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理数据库升级
|
||||
*
|
||||
@@ -308,6 +346,11 @@ final class SqlHelper extends SQLiteOpenHelper {
|
||||
*/
|
||||
private void addTaskRecordType(SQLiteDatabase db) {
|
||||
try {
|
||||
SqlUtil.checkOrCreateTable(db, ThreadRecord.class);
|
||||
SqlUtil.checkOrCreateTable(db, TaskRecord.class);
|
||||
SqlUtil.checkOrCreateTable(db, UploadEntity.class);
|
||||
SqlUtil.checkOrCreateTable(db, DownloadEntity.class);
|
||||
|
||||
db.beginTransaction();
|
||||
/*
|
||||
* 增加下载实体的类型
|
||||
@@ -380,6 +423,7 @@ final class SqlHelper extends SQLiteOpenHelper {
|
||||
* 删除重复的repeat数据
|
||||
*/
|
||||
private void delRepeatThreadRecord(SQLiteDatabase db) {
|
||||
SqlUtil.checkOrCreateTable(db, ThreadRecord.class);
|
||||
String repeatSql = "DELETE FROM ThreadRecord WHERE (rowid) "
|
||||
+ "IN (SELECT rowid FROM ThreadRecord GROUP BY taskKey, threadId, endLocation HAVING COUNT(*) > 1) "
|
||||
+ "AND rowid NOT IN (SELECT MIN(rowid) FROM ThreadRecord GROUP BY taskKey, threadId, endLocation HAVING COUNT(*)> 1)";
|
||||
@@ -406,6 +450,7 @@ final class SqlHelper extends SQLiteOpenHelper {
|
||||
* 处理365版本以下的升级
|
||||
*/
|
||||
private void handle365Update(SQLiteDatabase db) {
|
||||
SqlUtil.checkOrCreateTable(db, ThreadRecord.class);
|
||||
db.execSQL("UPDATE ThreadRecord SET threadId=0 WHERE threadId=-1");
|
||||
|
||||
Map<String, Map<String, String>> modifyMap = new HashMap<>();
|
||||
|
||||
@@ -49,7 +49,7 @@ final class SqlUtil {
|
||||
/**
|
||||
* 检查表是否存在,不存在则创建表
|
||||
*/
|
||||
static void checkTable(SQLiteDatabase db, Class<? extends DbEntity> clazz) {
|
||||
static void checkOrCreateTable(SQLiteDatabase db, Class<? extends DbEntity> clazz) {
|
||||
if (!tableExists(db, clazz)) {
|
||||
createTable(db, clazz);
|
||||
}
|
||||
|
||||
@@ -63,10 +63,8 @@ public class ALog {
|
||||
return println(Log.ERROR, tag, msg);
|
||||
}
|
||||
|
||||
public static int e(String tag, Throwable e) {
|
||||
String msg = getExceptionString(e);
|
||||
ErrorHelp.saveError(tag, "", msg);
|
||||
return println(Log.ERROR, tag, msg);
|
||||
public static void e(String tag, String msg, Throwable e) {
|
||||
Log.e(tag, msg, e);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,8 +19,8 @@ package com.arialyy.aria.util;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.HttpURLConnection;
|
||||
@@ -78,16 +78,17 @@ public class CheckUtil {
|
||||
*
|
||||
* @param isForceDownload true,如果路径冲突,将删除其它任务的记录的
|
||||
* @param filePath 文件保存路径
|
||||
* @param type {@link AbsTaskWrapper#getRequestType()}
|
||||
* @return false 任务不再执行,true 任务继续执行
|
||||
*/
|
||||
public static boolean checkDPathConflicts(boolean isForceDownload, String filePath) {
|
||||
public static boolean checkDPathConflicts(boolean isForceDownload, String filePath, int type) {
|
||||
if (DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=?", filePath)) {
|
||||
if (!isForceDownload) {
|
||||
ALog.e(TAG, String.format("下载失败,保存路径【%s】已经被其它任务占用,请设置其它保存路径", filePath));
|
||||
return false;
|
||||
} else {
|
||||
ALog.w(TAG, String.format("保存路径【%s】已经被其它任务占用,当前任务将覆盖该路径的文件", filePath));
|
||||
RecordUtil.delTaskRecord(filePath, IRecordHandler.TYPE_DOWNLOAD);
|
||||
RecordUtil.delTaskRecord(filePath, type, false, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -99,16 +100,17 @@ public class CheckUtil {
|
||||
*
|
||||
* @param isForceUpload true,如果路径冲突,将删除其它任务的记录的
|
||||
* @param filePath 文件保存路径
|
||||
* @param type {@link AbsTaskWrapper#getRequestType()}
|
||||
* @return false 任务不再执行,true 任务继续执行
|
||||
*/
|
||||
public static boolean checkUPathConflicts(boolean isForceUpload, String filePath) {
|
||||
public static boolean checkUPathConflicts(boolean isForceUpload, String filePath, int type) {
|
||||
if (DbEntity.checkDataExist(UploadEntity.class, "filePath=?", filePath)) {
|
||||
if (!isForceUpload) {
|
||||
ALog.e(TAG, String.format("上传失败,文件路径【%s】已经被其它任务占用,请设置其它文件路径", filePath));
|
||||
return false;
|
||||
} else {
|
||||
ALog.w(TAG, String.format("文件路径【%s】已经被其它任务占用,当前任务将覆盖该路径的文件", filePath));
|
||||
RecordUtil.delTaskRecord(filePath, IRecordHandler.TYPE_UPLOAD);
|
||||
RecordUtil.delTaskRecord(filePath, type, false, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -129,7 +131,7 @@ public class CheckUtil {
|
||||
return false;
|
||||
} else {
|
||||
ALog.w(TAG, String.format("文件夹路径【%s】已经被其它任务占用,当前任务将覆盖该路径", dirPath));
|
||||
RecordUtil.delGroupTaskRecordByPath(dirPath, false);
|
||||
DeleteDGRecord.getInstance().deleteRecord(dirPath, false, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,7 +534,7 @@ public class CommonUtil {
|
||||
try {
|
||||
is = new FileInputStream(updateFile);
|
||||
} catch (FileNotFoundException e) {
|
||||
ALog.e(TAG, e);
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -549,7 +549,7 @@ public class CommonUtil {
|
||||
try {
|
||||
digest = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
ALog.e(TAG, e);
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -571,7 +571,7 @@ public class CommonUtil {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
ALog.e(TAG, e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,11 @@ public class DbDataHelper {
|
||||
entity.setUrl(url);
|
||||
entity.setFilePath(groupHash + "_" + i);
|
||||
int lastIndex = url.lastIndexOf(File.separator);
|
||||
entity.setFileName(url.substring(lastIndex + 1));
|
||||
//去除url末尾携带的的参数
|
||||
int endIndex = url.lastIndexOf("?");
|
||||
|
||||
if(endIndex<0||endIndex<lastIndex)endIndex=url.length();
|
||||
entity.setFileName(url.substring(lastIndex + 1,endIndex));
|
||||
entity.setGroupHash(groupHash);
|
||||
entity.setGroupChild(true);
|
||||
list.add(entity);
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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 android.text.TextUtils;
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.ThreadRecord;
|
||||
import com.arialyy.aria.core.common.AbsEntity;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.wrapper.RecordWrapper;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 删除组合任务记录
|
||||
*/
|
||||
public class DeleteDGRecord implements IDeleteRecord {
|
||||
private String TAG = CommonUtil.getClassName(this);
|
||||
|
||||
private static volatile DeleteDGRecord INSTANCE = null;
|
||||
|
||||
private DeleteDGRecord(){
|
||||
|
||||
}
|
||||
|
||||
public static DeleteDGRecord getInstance() {
|
||||
if (INSTANCE == null){
|
||||
synchronized (DeleteDGRecord.class){
|
||||
if (INSTANCE == null){
|
||||
INSTANCE = new DeleteDGRecord();
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dirPath 组合任务保存路径
|
||||
* @param needRemoveFile true,无论下载成功以否,都将删除下载下来的文件。false,只会删除下载任务没有完成的文件
|
||||
* @param needRemoveEntity 是否需要删除实体,true 删除实体
|
||||
*/
|
||||
@Override
|
||||
public void deleteRecord(String dirPath, boolean needRemoveFile, boolean needRemoveEntity) {
|
||||
if (TextUtils.isEmpty(dirPath)) {
|
||||
ALog.e(TAG, "删除下载任务组记录失败,组合任务路径为空");
|
||||
return;
|
||||
}
|
||||
deleteRecord(DbDataHelper.getDGEntityByPath(dirPath), needRemoveFile, needRemoveEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRecord(AbsEntity absEntity, boolean needRemoveFile, boolean needRemoveEntity) {
|
||||
if (absEntity == null) {
|
||||
ALog.e(TAG, "删除组合任务记录失败,组合任务实体为空");
|
||||
return;
|
||||
}
|
||||
DownloadGroupEntity groupEntity = (DownloadGroupEntity) absEntity;
|
||||
|
||||
List<RecordWrapper> records =
|
||||
DbEntity.findRelationData(RecordWrapper.class, "dGroupHash=?", groupEntity.getGroupHash());
|
||||
|
||||
// 删除子任务记录
|
||||
if (records == null || records.isEmpty()) {
|
||||
ALog.w(TAG, "组任务记录已删除");
|
||||
} else {
|
||||
for (RecordWrapper record : records) {
|
||||
if (record == null || record.taskRecord == null) {
|
||||
continue;
|
||||
}
|
||||
// 删除分块文件
|
||||
if (record.taskRecord.isBlock) {
|
||||
removeBlockFile(record.taskRecord);
|
||||
}
|
||||
DbEntity.deleteData(ThreadRecord.class, "taskKey=?", record.taskRecord.filePath);
|
||||
record.taskRecord.deleteData();
|
||||
}
|
||||
}
|
||||
|
||||
// 删除组合任务子任务的文件
|
||||
List<DownloadEntity> subs = groupEntity.getSubEntities();
|
||||
if (subs != null) {
|
||||
for (DownloadEntity sub : subs) {
|
||||
if (needRemoveFile || !groupEntity.isComplete()) {
|
||||
FileUtil.deleteFile(sub.getFilePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除文件夹
|
||||
if (!TextUtils.isEmpty(groupEntity.getDirPath())) {
|
||||
if (needRemoveFile || !groupEntity.isComplete()) {
|
||||
FileUtil.deleteFile(groupEntity.getDirPath());
|
||||
}
|
||||
}
|
||||
|
||||
if (needRemoveEntity) {
|
||||
DbEntity.deleteData(DownloadEntity.class, "groupHash=?", groupEntity.getGroupHash());
|
||||
DbEntity.deleteData(DownloadGroupEntity.class, "groupHash=?", groupEntity.getGroupHash());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除多线程分块下载的分块文件
|
||||
*/
|
||||
private void removeBlockFile(TaskRecord record) {
|
||||
for (int i = 0, len = record.threadNum; i < len; i++) {
|
||||
FileUtil.deleteFile(String.format(IRecordHandler.SUB_PATH, record.filePath, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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 android.text.TextUtils;
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.ThreadRecord;
|
||||
import com.arialyy.aria.core.common.AbsEntity;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 删除下载记录
|
||||
*/
|
||||
public class DeleteDRecord implements IDeleteRecord {
|
||||
private String TAG = CommonUtil.getClassName(this);
|
||||
private static volatile DeleteDRecord INSTANCE = null;
|
||||
|
||||
private DeleteDRecord() {
|
||||
|
||||
}
|
||||
|
||||
public static DeleteDRecord getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (DeleteDRecord.class) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new DeleteDRecord();
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param filePath 文件保存路径
|
||||
* @param removeTarget true,无论下载成功以否,都将删除下载下来的文件。false,只会删除下载任务没有完成的文件
|
||||
* @param needRemoveEntity 是否需要删除实体
|
||||
*/
|
||||
@Override public void deleteRecord(String filePath, boolean removeTarget,
|
||||
boolean needRemoveEntity) {
|
||||
if (TextUtils.isEmpty(filePath)) {
|
||||
throw new NullPointerException("删除记录失败,文件路径为空");
|
||||
}
|
||||
if (!filePath.startsWith("/")) {
|
||||
throw new IllegalArgumentException(String.format("文件路径错误,filePath:%s", filePath));
|
||||
}
|
||||
DownloadEntity entity = DbEntity.findFirst(DownloadEntity.class, "downloadPath=?", filePath);
|
||||
if (entity == null) {
|
||||
ALog.e(TAG, "删除下载记录失败,没有在数据库中找到对应的实体文件,filePath:" + filePath);
|
||||
return;
|
||||
}
|
||||
deleteRecord(entity, removeTarget, needRemoveEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param absEntity 记录关联的实体
|
||||
* @param needRemoveFile true,无论下载成功以否,都将删除下载下来的文件。false,只会删除下载任务没有完成的文件
|
||||
* @param needRemoveEntity 是否需要删除实体
|
||||
*/
|
||||
@Override
|
||||
public void deleteRecord(AbsEntity absEntity, boolean needRemoveFile, boolean needRemoveEntity) {
|
||||
if (absEntity == null) {
|
||||
ALog.e(TAG, "删除下载记录失败,实体为空");
|
||||
return;
|
||||
}
|
||||
DownloadEntity entity = (DownloadEntity) absEntity;
|
||||
final String filePath = entity.getFilePath();
|
||||
File targetFile = new File(filePath);
|
||||
|
||||
// 兼容以前版本
|
||||
if (entity.getTaskType() == ITaskWrapper.M3U8_VOD
|
||||
|| entity.getTaskType() == ITaskWrapper.M3U8_LIVE) {
|
||||
DeleteM3u8Record.getInstance().deleteRecord(entity, needRemoveFile, needRemoveEntity);
|
||||
return;
|
||||
}
|
||||
|
||||
TaskRecord record = DbDataHelper.getTaskRecord(entity.getFilePath(), entity.getTaskType());
|
||||
if (record == null) {
|
||||
ALog.e(TAG, "删除下载记录失败,记录为空,filePath:" + entity.getFilePath());
|
||||
FileUtil.deleteFile(targetFile);
|
||||
DbEntity.deleteData(DownloadEntity.class, "downloadPath=?", filePath);
|
||||
return;
|
||||
}
|
||||
|
||||
// 删除下载的线程记录和任务记录
|
||||
DbEntity.deleteData(ThreadRecord.class, "taskKey=? AND threadType=?", filePath,
|
||||
String.valueOf(entity.getTaskType()));
|
||||
DbEntity.deleteData(TaskRecord.class, "filePath=? AND taskType=?", filePath,
|
||||
String.valueOf(entity.getTaskType()));
|
||||
|
||||
if (needRemoveFile || !entity.isComplete()) {
|
||||
FileUtil.deleteFile(targetFile);
|
||||
if (record.isBlock) {
|
||||
removeBlockFile(record);
|
||||
}
|
||||
}
|
||||
|
||||
if (needRemoveEntity) {
|
||||
DbEntity.deleteData(DownloadEntity.class, "downloadPath=?", filePath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除多线程分块下载的分块文件
|
||||
*/
|
||||
private void removeBlockFile(TaskRecord record) {
|
||||
for (int i = 0, len = record.threadNum; i < len; i++) {
|
||||
FileUtil.deleteFile(String.format(IRecordHandler.SUB_PATH, record.filePath, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user