41 Commits
3.8.5 ... 3.8.9

Author SHA1 Message Date
laoyuyu
418ec74b7b fix bug https://github.com/AriaLyy/Aria/issues/688
fix bug https://github.com/AriaLyy/Aria/issues/690
m3u8任务增加`setUseDefConvert()`方法,用于处理默认的m3u8任务
2020-06-14 15:03:15 +08:00
laoyuyu
29f9bdcdbd - 修复设置了cancel(false),文件还是被删除的问题 https://github.com/AriaLyy/Aria/issues/686
- 修复错误url的下载任务,无法删除的问题 https://github.com/AriaLyy/Aria/issues/684
2020-06-07 10:35:23 +08:00
laoyuyu
9a5e491e37 3.8.7 2020-05-25 08:49:44 +08:00
laoyuyu
e64f3b1240 Merge branch 'master' of github.com:AriaLyy/Aria 2020-05-16 16:19:18 +08:00
laoyuyu
dcde3f07b8 fix bug https://github.com/AriaLyy/Aria/issues/664 2020-05-16 10:07:52 +08:00
laoyuyu
290e58c58b fix bug https://github.com/AriaLyy/Aria/issues/670 2020-05-14 19:51:03 +08:00
lyy
b109726c7c Merge pull request #661 from DaveBoy/aria
子任务失败的问题处理
2020-04-26 09:11:35 +08:00
mxm
4d9a887076 子任务失败的问题处理 2020-04-24 16:54:46 +08:00
laoyuyu
a1c294bcbd Merge branch 'master' of github.com:AriaLyy/Aria 2020-04-18 11:31:04 +08:00
laoyuyu
1f2ac36580 fix bug https://github.com/AriaLyy/Aria/issues/646 2020-04-18 11:30:55 +08:00
lyy
203eeb10ad Merge pull request #657 from DaveBoy/aria
组合子任务多线程下载
2020-04-18 08:57:47 +08:00
mxm
06a0d764ed 分组子任务多线程下载 2020-04-16 09:56:06 +08:00
mxm
baf4bac091 子任务多线程 2020-04-15 18:05:45 +08:00
DaveBoy
4951dda5b0 Merge pull request #1 from AriaLyy/master
从主项目合并
2020-04-15 17:13:37 +08:00
lyy
ba0162e413 Update README.md 2020-04-14 13:25:22 +08:00
laoyuyu
0476c3a941 Merge branch 'master' of github.com:AriaLyy/Aria 2020-03-24 21:05:43 +08:00
laoyuyu
73292b6405 修复组合任务不执行 onPre的问题 2020-03-24 21:05:24 +08:00
lyy
e99d4a3d7e Merge pull request #640 from DaveBoy/aria
失败回调stop/fail设置完善
2020-03-19 10:42:42 +08:00
DaveBoy1994
e0dc7f3644 失败回调stop/fail设置完善 2020-03-19 09:26:48 +08:00
lyy
cd31276591 Merge pull request #633 from DaveBoy/aria
组合下载子任务失败Exception为空,单个任务下载失败后最终组任务回调stop/fail开关设置
2020-03-13 16:13:51 +08:00
DaveBoy1994
a65b2e31f9 修复下载路径中?后面存在/导致的崩溃问题 2020-03-13 10:40:33 +08:00
laoyuyu
de09add3a3 修复组任务中,其中一个子任务是30x地址,导致调度器无法出现该子任务状态的问题
增加组任务groupHash冲突检查 https://github.com/AriaLyy/Aria/issues/635
2020-03-11 21:46:26 +08:00
DaveBoy1994
41088dfa23 增加组任务中单个任务下载失败后,最终组任务回调stop/fail设置 2020-03-05 14:00:28 +08:00
DaveBoy1994
14901d4c0c 组合下载子任务失败Exception为空 2020-03-05 13:38:14 +08:00
laoyuyu
9cb6490da9 修复组任务进度为0的问题 2020-03-04 20:48:32 +08:00
laoyuyu
a1fd63b5c6 Merge branch 'master' of github.com:AriaLyy/Aria 2020-03-04 13:45:37 +08:00
lyy
b90450f1cd Merge pull request #632 from DaveBoy/aria
修复关联分页逻辑空指针异常
2020-03-04 13:45:17 +08:00
DaveBoy1994
370dca27ff 修复关联分页逻辑空指针异常 2020-03-04 13:23:00 +08:00
laoyuyu
669ac6b09c - 修复组任务,其中一个子任务在获取文件长度失败后,重新恢复组合任务,组合任务状态变为完成的问题 https://github.com/AriaLyy/Aria/issues/628 2020-03-03 21:03:50 +08:00
lyy
54cbdb7ee0 Merge pull request #631 from DaveBoy/aria
修改任务组分页逻辑
2020-03-02 20:56:28 +08:00
DaveBoy1994
e770818cee 修改任务组分页逻辑 2020-03-02 19:47:16 +08:00
laoyuyu
d92f1bba94 修复now模式下的一些问题 https://github.com/AriaLyy/Aria/issues/620
修复wait模式下,resume(true)无效问题
2020-02-22 13:08:47 +08:00
laoyuyu
ea2e27f3e9 修复40x错误,会继续重试并且无法重试成功的问题 https://github.com/AriaLyy/Aria/issues/619 2020-02-20 22:01:12 +08:00
laoyuyu
ad58dce395 修复组合任务单个子任务失败后,重新恢复组合任务,组合任务状态变为完成的问题 2020-02-20 19:58:48 +08:00
laoyuyu
472006ef61 3.8.6 2020-02-18 23:16:47 +08:00
lyy
604fb91800 Merge pull request #617 from DaveBoy/master
添加文件名适配器接口,修复group中useServerFileName未同步到子task的问题
2020-02-18 10:19:47 +08:00
DaveBoy1994
63ec23f241 添加文件名适配器接口,修复group中useServerFileName未同步到子task的问题 2020-02-18 10:01:10 +08:00
laoyuyu
2f2d783655 fix bug https://github.com/AriaLyy/Aria/issues/579#issuecomment-586665035
https://github.com/AriaLyy/Aria/issues/610
https://github.com/AriaLyy/Aria/issues/614
2020-02-17 23:49:20 +08:00
laoyuyu
e015c2a2f7 fix bug https://github.com/AriaLyy/Aria/issues/608
优化异常提示
2020-02-06 22:22:20 +08:00
laoyuyu
96efa35c4e demo 例子优化 2020-01-19 21:53:55 +08:00
laoyuyu
7f81995bd8 修改readme 2020-01-18 10:18:26 +08:00
147 changed files with 3116 additions and 2573 deletions

View File

@@ -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;
}
}

View File

@@ -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()));
}

View File

@@ -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());
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}
/**

View File

@@ -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文件为一个
*/

View File

@@ -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"

View File

@@ -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"

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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服务器错误码为%smsg:%s", reply, client.getReplyString())), false);
return null;
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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("获取文件信息错误,错误码为:%smsg%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("获取流失败,错误码为:%smsg%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) {

View File

@@ -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);
}
});

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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;
}
}

View File

@@ -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("任务下载失败errorCode404, 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);
}

View File

@@ -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());

View File

@@ -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);
}
});

View File

@@ -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;
}
}

View File

@@ -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 {

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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;
}
}

View File

@@ -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);
}
/**

View File

@@ -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);
}
}
}

View File

@@ -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;
}

View File

@@ -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错误码%surl%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 {

View File

@@ -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);
}
/**

View File

@@ -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;
}
}

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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 {

View File

@@ -36,6 +36,7 @@ public class SubThreadConfig {
public boolean isBlock = false;
// 启动的线程
public int startThreadNum;
// 真正的下载地址如果是30x则是30x后的地址
public String url;
public File tempFile;
// 线程记录

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -97,6 +97,7 @@ public abstract class AbsGroupLoaderUtil implements IUtil {
ALog.w(TAG, "启动组合任务失败,任务已停止或已取消");
return;
}
mListener.onPre();
buildLoaderStructure();
new Thread(mLoader).start();

View File

@@ -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();
}
/**

View File

@@ -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();
}
}

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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();

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
/**
* 子任务取消下载

View File

@@ -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);
}

View File

@@ -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() {

View File

@@ -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;
}

View File

@@ -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: %sfileSize: %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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
});

View File

@@ -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;

View File

@@ -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;
}
/**

View File

@@ -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) {

View File

@@ -255,7 +255,7 @@ public class ThreadTaskManager {
return;
}
} catch (Exception e) {
ALog.e(TAG, e);
ALog.e(TAG, "", e);
return;
}
mExePool.submit(task);

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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() {

View File

@@ -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);
/**
* 更新进度

View File

@@ -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) {

View File

@@ -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() {

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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<>();

View File

@@ -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);
}

View File

@@ -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);
}
/**

View File

@@ -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;
}
}

View File

@@ -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();
}
}
}

View File

@@ -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);

View File

@@ -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));
}
}
}

View File

@@ -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