27 Commits
3.7.3 ... 3.8.1

Author SHA1 Message Date
laoyuyu
0cb5d3e684 修改图标 2019-12-22 11:39:37 +08:00
laoyuyu
8dc16ce302 修复一个表创建失败的问题 https://github.com/AriaLyy/Aria/issues/570
修复一个非分块模式下导致下载失败的问题 https://github.com/AriaLyy/Aria/issues/571
修复一个服务器端无法创建socket连接,却没有返回码导致客户端卡住的问题 https://github.com/AriaLyy/Aria/issues/569
修复文件删除后,组合任务没有重新下载的问题 https://github.com/AriaLyy/Aria/issues/574
优化缓存队列和执行队列
2019-12-22 11:30:36 +08:00
laoyuyu
27c889e171 修复ftp服务器无法响应abor命令导致的无法停止上传的问题
修复ftp上传时,服务器有长度为0的文件导致上传失败的问题
修复下载任务和上传任务的文件路径是同一个时,导致的记录混乱问题
2019-12-17 22:04:25 +08:00
laoyuyu
0d93953cd9 修复组合任务初始化失败时,无法删除的问题
修复`reStart()`后,无法停止的问题
ftp增加主动模式,开启主动模式:https://aria.laoyuyu.me/aria_doc/api/ftp_params.html
优化提示
2019-12-16 20:18:51 +08:00
laoyuyu
f3d5e0135a m3u8增加了ignoreFailureTs方法,忽略虾类失败的ts切片
修复在dialogFragment的`onCreateDialog()`注册导致的注解不生效问题
2019-12-15 21:52:54 +08:00
laoyuyu
d9ed7f87d2 移除androidx、support依赖,现在哪个版本的appcompat库都可以导入Aria
修复一个在xml中使用fragment导致的内存泄漏问题
2019-12-08 11:09:11 +08:00
laoyuyu
3871d8f056 3.7.10 2019-12-03 19:42:37 +08:00
laoyuyu
669aa6981c fix bug https://github.com/AriaLyy/Aria/issues/543#issuecomment-559733124
fix bug https://github.com/AriaLyy/Aria/issues/542
fix bug https://github.com/AriaLyy/Aria/issues/547
修复下载失败时,中断重试无效的问题
增加忽略权限检查的api,`ignoreCheckPermissions()`
2019-12-02 19:31:45 +08:00
laoyuyu
91daecd039 Merge branch 'master' of github.com:AriaLyy/Aria 2019-11-28 19:49:26 +08:00
laoyuyu
297cc99f2b fix bug https://github.com/AriaLyy/Aria/issues/537 2019-11-28 19:48:50 +08:00
lyy
f5f8e9b528 Update Custom.md 2019-11-28 16:39:46 +08:00
lyy
94c3e8bb58 Update Custom.md 2019-11-28 16:37:04 +08:00
laoyuyu
ee5ee6e080 增加m3u8密钥url转换器 2019-11-28 09:59:08 +08:00
laoyuyu
c4cc804c67 增加立即恢复任务的接口,正常来说,当执行队列满时,调用恢复任务接口,只能将任务放到缓存队列中。如果希望调用恢复接口,马上进入执行队列,需要调用resume(true)这个重载方法。
修复一个非分块模式下,无法恢复下载的问题
增加M3U8加密密钥的下载地址转换器 https://github.com/AriaLyy/Aria/issues/522
2019-11-27 21:38:25 +08:00
laoyuyu
c9c00c38c6 Merge branch 'master' of github.com:AriaLyy/Aria 2019-11-26 19:32:16 +08:00
laoyuyu
846235a826 fix bug https://github.com/AriaLyy/Aria/issues/533
fix bug https://github.com/AriaLyy/Aria/issues/535
2019-11-26 19:28:06 +08:00
lyy
06dd6b35e0 Update README.md 2019-11-26 15:39:47 +08:00
lyy
944d69a1af Update README.md 2019-11-21 10:37:21 +08:00
laoyuyu
1ee36e0bc1 fix bug https://github.com/AriaLyy/Aria/issues/526 2019-11-20 21:33:56 +08:00
laoyuyu
0765ab67f7 3.7.7 2019-11-20 10:17:08 +08:00
laoyuyu
1b54bfc4ac 3.7.6 2019-11-19 20:03:25 +08:00
laoyuyu
846e6c0720 fix bug https://github.com/AriaLyy/Aria/issues/516
fix bug https://github.com/AriaLyy/Aria/issues/505
增加上传任务强制上传的功能
2019-11-18 19:35:12 +08:00
laoyuyu
5ad485890c fix bug https://github.com/AriaLyy/Aria/issues/500
fix bug https://github.com/AriaLyy/Aria/issues/508
fix bug https://github.com/AriaLyy/Aria/issues/503
修复m3u8创建索引不成功的问题
2019-11-10 13:26:00 +08:00
lyy
012f94511b Update README.md 2019-11-04 09:34:43 +08:00
lyy
e41d2f8578 Add files via upload 2019-11-04 09:23:47 +08:00
laoyuyu
a6ecaadea4 3.7.4 2019-11-02 11:06:49 +08:00
laoyuyu
c1b1cc1390 fix bug https://github.com/AriaLyy/Aria/issues/493 2019-11-02 10:58:49 +08:00
210 changed files with 3519 additions and 2174 deletions

View File

@@ -1,17 +1,26 @@
---
name: 问题描述
about: 请详细描述你遇到的问题
about: 提交问题前请先阅读文档和搜索issue
---
## Aria版本
<!-- 提交问题前请先阅读文档和搜索相应问题的issue -->
## 版本
* 框架版本
* 系统版本
## 错误日志
<!-- 请提供详细的错误日志 -->
## 什么问题
## 重现步骤
<!-- 请提供明确的步骤 -->
1.
2.
3.
4.
## 如何复现此问题
## 控制台日志

View File

@@ -35,7 +35,7 @@ dependencies {
api 'com.google.code.gson:gson:2.8.2'
api 'io.reactivex:rxandroid:1.2.0'
api 'io.reactivex:rxjava:1.1.5'
implementation 'com.squareup.okhttp3:okhttp:3.2.0'
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
implementation 'com.squareup.retrofit2:retrofit:2.1.0'
implementation 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'

View File

@@ -92,5 +92,6 @@ public class RegularExpression {
/**
* IP
*/
public static String IP = "\\d+\\.\\d+\\.\\d+\\.\\d+";
public static String IP =
"([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}";
}

View File

@@ -23,7 +23,7 @@ android {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
testImplementation 'junit:junit:4.12'
implementation "androidx.appcompat:appcompat:${rootProject.ext.XAppcompatVersion}"
// implementation "androidx.appcompat:appcompat:${rootProject.ext.XAppcompatVersion}"
api project(':AriaAnnotations')
api project(path: ':PublicComponent')
api project(path: ':HttpComponent')

View File

@@ -23,8 +23,6 @@ import android.app.Dialog;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.widget.PopupWindow;
import com.arialyy.aria.core.command.CommandManager;
import com.arialyy.aria.core.common.QueueMod;
@@ -76,7 +74,6 @@ import java.util.concurrent.ConcurrentHashMap;
*/
private Map<String, List<String>> mSubClass = new ConcurrentHashMap<>();
private static Context APP;
private Handler mAriaHandler;
private DelegateWrapper mDbWrapper;
private AriaConfig mConfig;
@@ -98,9 +95,6 @@ import java.util.concurrent.ConcurrentHashMap;
}
public static AriaManager getInstance() {
if (INSTANCE == null) {
throw new NullPointerException("请使用AriaManager.init(context)初始化管理器");
}
return INSTANCE;
}
@@ -171,13 +165,6 @@ import java.util.concurrent.ConcurrentHashMap;
}
}
public synchronized Handler getAriaHandler() {
if (mAriaHandler == null) {
mAriaHandler = new Handler(Looper.getMainLooper());
}
return mAriaHandler;
}
public Map<String, AbsReceiver> getReceiver() {
return mReceivers;
}
@@ -295,7 +282,7 @@ import java.util.concurrent.ConcurrentHashMap;
RecordUtil.delTaskRecord(key, IRecordHandler.TYPE_DOWNLOAD, removeFile, true);
break;
case 2:
RecordUtil.delGroupTaskRecord(key, removeFile);
RecordUtil.delGroupTaskRecordByHash(key, removeFile);
break;
case 3:
RecordUtil.delTaskRecord(key, IRecordHandler.TYPE_UPLOAD);
@@ -303,19 +290,31 @@ import java.util.concurrent.ConcurrentHashMap;
}
}
private IReceiver putReceiver(@ReceiverType String type, Object obj) {
private IReceiver putReceiver(String type, Object obj) {
final String key = getKey(type, obj);
IReceiver receiver = mReceivers.get(key);
boolean needRmReceiver = false;
// 监控Dialog、fragment、popupWindow的生命周期
final WidgetLiftManager widgetLiftManager = new WidgetLiftManager();
Context subParenActivity = null;
if (obj instanceof Dialog) {
needRmReceiver = widgetLiftManager.handleDialogLift((Dialog) obj);
subParenActivity = ((Dialog) obj).getOwnerActivity();
} else if (obj instanceof PopupWindow) {
needRmReceiver = widgetLiftManager.handlePopupWindowLift((PopupWindow) obj);
subParenActivity = ((PopupWindow) obj).getContentView().getContext();
} else if (isDialogFragment(obj.getClass())) {
needRmReceiver = widgetLiftManager.handleDialogFragmentLift(getDialog(obj));
subParenActivity = getFragmentActivity(obj);
} else if (isFragment(obj.getClass())) {
subParenActivity = getFragmentActivity(obj);
}
if (subParenActivity instanceof Activity) {
relateSubClass(type, obj, (Activity) subParenActivity);
}
if (receiver == null) {
AbsReceiver absReceiver =
type.equals(ReceiverType.DOWNLOAD) ? new DownloadReceiver() : new UploadReceiver();
@@ -328,30 +327,6 @@ import java.util.concurrent.ConcurrentHashMap;
return receiver;
}
/**
* 根据功能类型和控件类型获取对应的key
*
* @param type {@link ReceiverType}
* @param obj 观察者对象
* @return {@link #createKey(String, Object)}
*/
private String getKey(@ReceiverType String type, Object obj) {
if (isFragment(obj.getClass())) {
relateSubClass(type, obj, getFragmentActivity(obj));
} else if (obj instanceof Dialog) {
Activity activity = ((Dialog) obj).getOwnerActivity();
if (activity != null) {
relateSubClass(type, obj, activity);
}
} else if (obj instanceof PopupWindow) {
Context context = ((PopupWindow) obj).getContentView().getContext();
if (context instanceof Activity) {
relateSubClass(type, obj, (Activity) context);
}
}
return createKey(type, obj);
}
/**
* 获取fragment的activity
*
@@ -434,14 +409,17 @@ import java.util.concurrent.ConcurrentHashMap;
* @param sub Fragment或dialog类
* @param activity activity寄主类
*/
private void relateSubClass(@ReceiverType String type, Object sub, Activity activity) {
String key = createKey(type, activity);
List<String> list = mSubClass.get(key);
if (list == null) {
list = new ArrayList<>();
mSubClass.put(key, list);
private void relateSubClass(String type, Object sub, Activity activity) {
String key = getKey(type, activity);
List<String> subClass = mSubClass.get(key);
if (subClass == null) {
subClass = new ArrayList<>();
mSubClass.put(key, subClass);
}
subClass.add(getKey(type, sub));
if (mReceivers.get(key) == null) { // 将activity填充进去
mReceivers.put(key, new DownloadReceiver());
}
list.add(createKey(type, sub));
}
/**
@@ -452,7 +430,7 @@ import java.util.concurrent.ConcurrentHashMap;
* @return key的格式为{@code String.format("%s_%s_%s", obj.getClass().getName(), type,
* obj.hashCode());}
*/
private String createKey(@ReceiverType String type, Object obj) {
private String getKey(String type, Object obj) {
return String.format("%s_%s_%s", obj.getClass().getName(), type, obj.hashCode());
}

View File

@@ -73,8 +73,16 @@ final class WidgetLiftManager {
/**
* 处理对话框取消或dismiss
*
* @return true 设置了dialog的销毁事件。false 没有设置dialog的销毁事件
*/
boolean handleDialogLift(Dialog dialog) {
if (dialog == null) {
ALog.w(TAG,
"dialog 为空没有设置自动销毁事件为了防止内存泄露请在dismiss方法中调用Aria.download(this).unRegister();来注销事件\n"
+ "如果你使用的是DialogFragment那么你需要在onDestroy()中进行销毁Aria事件操作");
return false;
}
try {
Field dismissField = CommonUtil.getField(dialog.getClass(), "mDismissMessage");
Message dismissMsg = (Message) dismissField.get(dialog);

View File

@@ -15,6 +15,7 @@
*/
package com.arialyy.aria.core.command;
import com.arialyy.aria.core.task.ITask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
/**
@@ -25,8 +26,7 @@ public abstract class AbsCmdFactory<TASK_ENTITY extends AbsTaskWrapper, CMD exte
/**
* @param entity 下载实体
* @param taskType {@link ICmd#TASK_TYPE_DOWNLOAD}、{@link ICmd#TASK_TYPE_DOWNLOAD_GROUP}、{@link
* ICmd#TASK_TYPE_UPLOAD}
* {@link ITask#DOWNLOAD}、{@link ITask#DOWNLOAD_GROUP}、{@link ITask#UPLOAD}
*/
public abstract CMD createCmd(TASK_ENTITY entity, int type, int taskType);
}

View File

@@ -157,14 +157,6 @@ public abstract class AbsNormalCmd<T extends AbsTaskWrapper> extends AbsCmd<T> {
mQueue.resumeTask(task);
}
/**
* 启动指定任务
*
* @param task 指定任务
*/
void startTask(AbsTask task) {
mQueue.startTask(task);
}
/**
* 从队列中获取任务

View File

@@ -30,7 +30,7 @@ public class CommandManager {
EventMsgUtil.getDefault().register(this);
}
public static CommandManager init() {
public static void init() {
if (instance == null) {
synchronized (CommandManager.class) {
if (instance == null) {
@@ -38,7 +38,6 @@ public class CommandManager {
}
}
}
return instance;
}
@Event
@@ -51,9 +50,6 @@ public class CommandManager {
@Event
public void start(StartCmd cmd) {
if (CommonUtil.isFastDoubleClick()) {
return;
}
cmd.executeCmd();
}

View File

@@ -15,6 +15,7 @@
*/
package com.arialyy.aria.core.command;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.task.DownloadTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
@@ -41,7 +42,7 @@ final class HighestPriorityCmd<T extends AbsTaskWrapper> extends AbsNormalCmd<T>
@Override public void executeCmd() {
if (!canExeCmd) return;
if (!NetUtils.isConnected(AriaManager.getInstance().getAPP())){
if (!NetUtils.isConnected(AriaConfig.getInstance().getAPP())){
ALog.e(TAG, "启动任务失败,网络未连接");
return;
}

View File

@@ -16,6 +16,7 @@
package com.arialyy.aria.core.command;
import com.arialyy.aria.core.task.ITask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
/**
@@ -83,8 +84,7 @@ public class NormalCmdFactory extends AbsCmdFactory<AbsTaskWrapper, AbsNormalCmd
* @param entity 下载实体
* @param type 命令类型{@link #TASK_CREATE}、{@link #TASK_START}、{@link #TASK_CANCEL}、{@link
* #TASK_STOP}、{@link #TASK_HIGHEST_PRIORITY}、{@link #TASK_STOP_ALL}、{@link #TASK_RESUME_ALL}
* @param taskType {@link ICmd#TASK_TYPE_DOWNLOAD}、{@link ICmd#TASK_TYPE_DOWNLOAD_GROUP}、{@link
* ICmd#TASK_TYPE_UPLOAD}
* @param taskType {@link ITask#DOWNLOAD}、{@link ITask#DOWNLOAD_GROUP}、{@link ITask#UPLOAD}
*/
public AbsNormalCmd createCmd(AbsTaskWrapper entity, int type, int taskType) {
switch (type) {

View File

@@ -15,9 +15,9 @@
*/
package com.arialyy.aria.core.command;
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.inf.TaskSchedulerType;
/**
* 重新开始任务命令
@@ -34,8 +34,8 @@ final class ReStartCmd<T extends AbsTaskWrapper> extends AbsNormalCmd<T> {
task = createTask();
}
if (task != null) {
task.cancel(TaskSchedulerType.TYPE_CANCEL_AND_NOT_NOTIFY);
task.start(TaskSchedulerType.TYPE_START_AND_RESET_STATE);
mQueue.cancelTask(task, TaskSchedulerType.TYPE_CANCEL_AND_NOT_NOTIFY);
mQueue.startTask(task, TaskSchedulerType.TYPE_START_AND_RESET_STATE);
}
}
}

View File

@@ -1,25 +1,25 @@
/*
* 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.command;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DGTaskWrapper;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.common.AbsEntity;
import com.arialyy.aria.core.task.AbsTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.manager.TaskWrapperManager;
import com.arialyy.aria.core.queue.DGroupTaskQueue;
import com.arialyy.aria.core.queue.DTaskQueue;
import com.arialyy.aria.core.queue.UTaskQueue;
import com.arialyy.aria.core.upload.UTaskWrapper;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.NetUtils;
import java.util.ArrayList;
import java.util.List;
/**
* Created by AriaL on 2017/6/13.
@@ -30,105 +30,17 @@ import java.util.List;
* 4.恢复下载的任务规则是停止时间越晚的任务启动越早按照DESC来进行排序
*/
final class ResumeAllCmd<T extends AbsTaskWrapper> extends AbsNormalCmd<T> {
private List<AbsTaskWrapper> mWaitList = new ArrayList<>();
ResumeAllCmd(T entity, int taskType) {
super(entity, taskType);
}
@Override public void executeCmd() {
if (!NetUtils.isConnected(AriaManager.getInstance().getAPP())) {
if (!NetUtils.isConnected(AriaConfig.getInstance().getAPP())) {
ALog.w(TAG, "恢复任务失败,网络未连接");
return;
}
if (isDownloadCmd) {
findTaskData(1);
findTaskData(2);
} else {
findTaskData(3);
}
resumeWaitTask();
}
/**
* 查找数据库中的所有任务数据
*
* @param type {@code 1}单任务下载任务;{@code 2}任务组下载任务;{@code 3} 单任务上传任务
*/
private void findTaskData(int type) {
if (type == 1) {
List<DownloadEntity> entities =
DbEntity.findDatas(DownloadEntity.class,
"isGroupChild=? AND state!=? ORDER BY stopTime DESC", "false", "1");
if (entities != null && !entities.isEmpty()) {
for (DownloadEntity entity : entities) {
addResumeEntity(TaskWrapperManager.getInstance()
.getNormalTaskWrapper(DTaskWrapper.class, entity.getId()));
}
}
} else if (type == 2) {
List<DownloadGroupEntity> entities =
DbEntity.findDatas(DownloadGroupEntity.class, "state!=? ORDER BY stopTime DESC", "1");
if (entities != null && !entities.isEmpty()) {
for (DownloadGroupEntity entity : entities) {
addResumeEntity(
TaskWrapperManager.getInstance()
.getGroupWrapper(DGTaskWrapper.class, entity.getId()));
}
}
} else if (type == 3) {
List<UploadEntity> entities =
DbEntity.findDatas(UploadEntity.class, "state!=? ORDER BY stopTime DESC", "1");
if (entities != null && !entities.isEmpty()) {
for (UploadEntity entity : entities) {
addResumeEntity(TaskWrapperManager.getInstance()
.getNormalTaskWrapper(UTaskWrapper.class, entity.getId()));
}
}
}
}
/**
* 添加恢复实体
*/
private void addResumeEntity(AbsTaskWrapper te) {
if (te == null || te.getEntity() == null) {
return;
}
if (!mQueue.taskExists(te.getKey())) {
mWaitList.add(te);
}
}
/**
* 处理等待状态的任务
*/
private void resumeWaitTask() {
int maxTaskNum = mQueue.getMaxTaskNum();
if (mWaitList == null || mWaitList.isEmpty()) {
return;
}
List<AbsEntity> resumeEntities = new ArrayList<>();
for (AbsTaskWrapper te : mWaitList) {
if (te instanceof DTaskWrapper) {
mQueue = DTaskQueue.getInstance();
} else if (te instanceof UTaskWrapper) {
mQueue = UTaskQueue.getInstance();
} else if (te instanceof DGTaskWrapper) {
mQueue = DGroupTaskQueue.getInstance();
}
if (mQueue.getCurrentExePoolNum() < maxTaskNum) {
startTask(createTask(te));
} else {
te.getEntity().setState(IEntity.STATE_WAIT);
AbsTask task = createTask(te);
sendWaitState(task);
resumeEntities.add(te.getEntity());
}
}
if (!resumeEntities.isEmpty()) {
DbEntity.updateManyData(resumeEntities);
}
new Thread(new ResumeThread(isDownloadCmd,
String.format("state!=%s", IEntity.STATE_COMPLETE))).start();
}
}

View File

@@ -0,0 +1,200 @@
/*
* 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.command;
import android.text.TextUtils;
import com.arialyy.aria.core.common.AbsEntity;
import com.arialyy.aria.core.download.DGTaskWrapper;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.IOptionConstant;
import com.arialyy.aria.core.listener.ISchedulers;
import com.arialyy.aria.core.manager.TaskWrapperManager;
import com.arialyy.aria.core.queue.AbsTaskQueue;
import com.arialyy.aria.core.queue.DGroupTaskQueue;
import com.arialyy.aria.core.queue.DTaskQueue;
import com.arialyy.aria.core.queue.UTaskQueue;
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.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.util.ArrayList;
import java.util.List;
/**
* 恢复任务工具
*/
public class ResumeThread implements Runnable {
private String TAG = CommonUtil.getClassName(getClass());
private List<AbsTaskWrapper> mWaitList = new ArrayList<>();
private boolean isDownloadCmd;
private String sqlCondition;
ResumeThread(boolean isDownload, String sqlCondition) {
this.isDownloadCmd = isDownload;
this.sqlCondition = sqlCondition;
}
/**
* 查找数据库中的所有任务数据
*
* @param type {@code 1}单任务下载任务;{@code 2}任务组下载任务;{@code 3} 单任务上传任务
*/
private void findTaskData(int type) {
if (type == 1) {
List<DownloadEntity> entities =
DbEntity.findDatas(DownloadEntity.class,
String.format("NOT(isGroupChild) AND NOT(isComplete) AND %s ORDER BY stopTime DESC",
sqlCondition));
if (entities != null && !entities.isEmpty()) {
for (DownloadEntity entity : entities) {
addResumeEntity(TaskWrapperManager.getInstance()
.getNormalTaskWrapper(DTaskWrapper.class, entity.getId()));
}
}
} else if (type == 2) {
List<DownloadGroupEntity> entities =
DbEntity.findDatas(DownloadGroupEntity.class,
String.format("NOT(isComplete) AND %s ORDER BY stopTime DESC",
sqlCondition));
if (entities != null && !entities.isEmpty()) {
for (DownloadGroupEntity entity : entities) {
addResumeEntity(
TaskWrapperManager.getInstance()
.getGroupWrapper(DGTaskWrapper.class, entity.getId()));
}
}
} else if (type == 3) {
List<UploadEntity> entities =
DbEntity.findDatas(UploadEntity.class,
String.format("NOT(isComplete) AND %s ORDER BY stopTime DESC",
sqlCondition));
if (entities != null && !entities.isEmpty()) {
for (UploadEntity entity : entities) {
addResumeEntity(TaskWrapperManager.getInstance()
.getNormalTaskWrapper(UTaskWrapper.class, entity.getId()));
}
}
}
}
/**
* 添加恢复实体
*/
private void addResumeEntity(AbsTaskWrapper te) {
if (te == null || te.getEntity() == null || TextUtils.isEmpty(te.getKey())) {
return;
}
mWaitList.add(te);
}
/**
* 处理等待状态的任务
*/
private void resumeWaitTask() {
if (mWaitList == null || mWaitList.isEmpty()) {
return;
}
List<AbsEntity> resumeEntities = new ArrayList<>();
for (AbsTaskWrapper wrapper : mWaitList) {
AbsTaskQueue queue = null;
if (wrapper instanceof DTaskWrapper) {
queue = DTaskQueue.getInstance();
} else if (wrapper instanceof UTaskWrapper) {
queue = UTaskQueue.getInstance();
} else if (wrapper instanceof DGTaskWrapper) {
queue = DGroupTaskQueue.getInstance();
}
if (queue == null) {
ALog.e(TAG, "任务类型错误");
continue;
}
if (wrapper.getEntity() == null || TextUtils.isEmpty(wrapper.getKey())) {
ALog.e(TAG, "任务实体为空或key为空");
continue;
}
AbsTask task = queue.getTask(wrapper.getKey());
if (task != null) {
ALog.w(TAG, "任务已存在");
continue;
}
int maxTaskNum = queue.getMaxTaskNum();
task = queue.createTask(wrapper);
if (task == null) {
continue;
}
handleWrapper(wrapper);
if (queue.getCurrentExePoolNum() < maxTaskNum) {
queue.startTask(task);
} else {
wrapper.getEntity().setState(IEntity.STATE_WAIT);
sendWaitState(task);
resumeEntities.add(wrapper.getEntity());
}
}
if (!resumeEntities.isEmpty()) {
DbEntity.updateManyData(resumeEntities);
}
}
/**
* 处理ftp的wrapper
*/
private void handleWrapper(AbsTaskWrapper wrapper) {
int requestType = wrapper.getRequestType();
if (requestType == ITaskWrapper.D_FTP
|| requestType == ITaskWrapper.U_FTP
|| requestType == ITaskWrapper.D_FTP_DIR) {
wrapper.getOptionParams()
.setParams(IOptionConstant.ftpUrlEntity,
CommonUtil.getFtpUrlInfo(wrapper.getEntity().getKey()));
}
}
/**
* 发送等待状态
*/
private void sendWaitState(AbsTask task) {
if (task != null) {
task.getTaskWrapper().setState(IEntity.STATE_WAIT);
task.getOutHandler().obtainMessage(ISchedulers.WAIT, task).sendToTarget();
}
}
@Override public void run() {
if (isDownloadCmd) {
findTaskData(1);
findTaskData(2);
} else {
findTaskData(3);
}
resumeWaitTask();
}
}

View File

@@ -16,52 +16,47 @@
package com.arialyy.aria.core.command;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.common.QueueMod;
import com.arialyy.aria.core.download.DGTaskWrapper;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.task.AbsTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.IOptionConstant;
import com.arialyy.aria.core.manager.TaskWrapperManager;
import com.arialyy.aria.core.queue.DGroupTaskQueue;
import com.arialyy.aria.core.queue.DTaskQueue;
import com.arialyy.aria.core.queue.UTaskQueue;
import com.arialyy.aria.core.upload.UTaskWrapper;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.NetUtils;
import java.util.ArrayList;
import java.util.List;
/**
* Created by lyy on 2016/8/22. 开始命令 队列模型{@link QueueMod#NOW}、{@link QueueMod#WAIT}
*/
final class StartCmd<T extends AbsTaskWrapper> extends AbsNormalCmd<T> {
final public class StartCmd<T extends AbsTaskWrapper> extends AbsNormalCmd<T> {
private boolean newStart = false;
StartCmd(T entity, int taskType) {
super(entity, taskType);
}
/**
* 立即执行任务
*
* @param newStart true 立即执行任务,无论执行队列是否满了
*/
public void setNewStart(boolean newStart) {
this.newStart = newStart;
}
@Override public void executeCmd() {
if (!canExeCmd) return;
if (!NetUtils.isConnected(AriaManager.getInstance().getAPP())) {
if (!NetUtils.isConnected(AriaConfig.getInstance().getAPP())) {
ALog.e(TAG, "启动任务失败,网络未连接");
return;
}
String mod;
int maxTaskNum = mQueue.getMaxTaskNum();
AriaManager manager = AriaManager.getInstance();
AriaConfig config = AriaConfig.getInstance();
if (isDownloadCmd) {
mod = manager.getDownloadConfig().getQueueMod();
mod = config.getDConfig().getQueueMod();
} else {
mod = manager.getUploadConfig().getQueueMod();
mod = config.getUConfig().getQueueMod();
}
AbsTask task = getTask();
@@ -87,7 +82,11 @@ final class StartCmd<T extends AbsTaskWrapper> extends AbsNormalCmd<T> {
startTask();
}
} else {
sendWaitState(task);
if (newStart) {
startTask();
} else {
sendWaitState(task);
}
}
}
} else {
@@ -107,75 +106,7 @@ final class StartCmd<T extends AbsTaskWrapper> extends AbsNormalCmd<T> {
* 当缓冲队列为null时查找数据库中所有等待中的任务
*/
private void findAllWaitTask() {
new Thread(new WaitTaskThread()).start();
}
private class WaitTaskThread implements Runnable {
@Override public void run() {
if (isDownloadCmd) {
handleTask(findWaitData(1));
handleTask(findWaitData(2));
} else {
handleTask(findWaitData(3));
}
}
private List<AbsTaskWrapper> findWaitData(int type) {
List<AbsTaskWrapper> waitList = new ArrayList<>();
TaskWrapperManager tManager = TaskWrapperManager.getInstance();
if (type == 1) { // 普通下载任务
List<DownloadEntity> dEntities = DbEntity.findDatas(DownloadEntity.class,
"isGroupChild=? and state=?", "false", "3");
if (dEntities != null && !dEntities.isEmpty()) {
for (DownloadEntity e : dEntities) {
waitList.add(tManager.getNormalTaskWrapper(DTaskWrapper.class, e.getId()));
}
}
} else if (type == 2) { // 组合任务
List<DownloadGroupEntity> dEntities =
DbEntity.findDatas(DownloadGroupEntity.class, "state=?", "3");
if (dEntities != null && !dEntities.isEmpty()) {
for (DownloadGroupEntity e : dEntities) {
if (e.getTaskType() == ITaskWrapper.DG_HTTP) {
waitList.add(tManager.getGroupWrapper(DGTaskWrapper.class, e.getId()));
} else if (e.getTaskType() == ITaskWrapper.D_FTP_DIR) {
waitList.add(tManager.getGroupWrapper(DGTaskWrapper.class, e.getId()));
}
}
}
} else if (type == 3) { //普通上传任务
List<UploadEntity> dEntities = DbEntity.findDatas(UploadEntity.class, "state=?", "3");
if (dEntities != null && !dEntities.isEmpty()) {
for (UploadEntity e : dEntities) {
waitList.add(tManager.getNormalTaskWrapper(UTaskWrapper.class, e.getId()));
}
}
}
return waitList;
}
private void handleTask(List<AbsTaskWrapper> waitList) {
for (AbsTaskWrapper wrapper : waitList) {
if (wrapper.getEntity() == null) continue;
AbsTask task = getTask(wrapper.getKey());
if (task != null) continue;
if (wrapper instanceof DTaskWrapper) {
if (wrapper.getRequestType() == ITaskWrapper.D_FTP
|| wrapper.getRequestType() == ITaskWrapper.U_FTP) {
wrapper.getOptionParams()
.setParams(IOptionConstant.ftpUrlEntity,
CommonUtil.getFtpUrlInfo(wrapper.getEntity().getKey()));
}
mQueue = DTaskQueue.getInstance();
} else if (wrapper instanceof UTaskWrapper) {
mQueue = UTaskQueue.getInstance();
} else if (wrapper instanceof DGTaskWrapper) {
mQueue = DGroupTaskQueue.getInstance();
}
createTask(wrapper);
}
}
new Thread(
new ResumeThread(isDownloadCmd, String.format("state=%s", IEntity.STATE_WAIT))).start();
}
}

View File

@@ -15,12 +15,12 @@
*/
package com.arialyy.aria.core.common;
import com.arialyy.aria.core.common.controller.IStartFeature;
import com.arialyy.aria.core.common.controller.BuilderController;
import com.arialyy.aria.core.common.controller.IStartFeature;
import com.arialyy.aria.core.inf.AbsTarget;
/**
* 处理第一次下载
* 处理第一次创建的任务
*/
public abstract class AbsBuilderTarget<TARGET extends AbsBuilderTarget> extends AbsTarget<TARGET>
implements IStartFeature {
@@ -34,6 +34,23 @@ public abstract class AbsBuilderTarget<TARGET extends AbsBuilderTarget> extends
return mStartController;
}
/**
* 是否忽略权限检查
*/
public TARGET ignoreCheckPermissions() {
getController().ignoreCheckPermissions();
return (TARGET) this;
}
/**
* 忽略文件占用,不管文件路径是否被其它任务占用,都执行上传\下载任务
* 需要注意的是:如果文件被其它任务占用,并且还调用了该方法,将自动删除占用了该文件路径的任务
*/
public TARGET ignoreFilePathOccupy() {
getController().ignoreFilePathOccupy();
return (TARGET) this;
}
/**
* 添加任务
*

View File

@@ -31,6 +31,14 @@ import com.arialyy.aria.util.RecordUtil;
public abstract class AbsNormalTarget<TARGET extends AbsNormalTarget> extends AbsTarget<TARGET>
implements INormalFeature {
/**
* 是否忽略权限检查
*/
public TARGET ignoreCheckPermissions() {
getController().ignoreCheckPermissions();
return (TARGET) this;
}
/**
* 任务是否在执行
*
@@ -150,7 +158,17 @@ public abstract class AbsNormalTarget<TARGET extends AbsNormalTarget> extends Ab
*/
@Override
public void resume() {
getController().resume();
resume(false);
}
/**
* 正常来说,当执行队列满时,调用恢复任务接口,只能将任务放到缓存队列中。
* 如果希望调用恢复接口,马上进入执行队列,需要使用该方法
*
* @param newStart true 立即将任务恢复到执行队列中
*/
@Override public void resume(boolean newStart) {
getController().resume(newStart);
}
/**
@@ -184,8 +202,8 @@ public abstract class AbsNormalTarget<TARGET extends AbsNormalTarget> extends Ab
* 重新下载
*/
@Override
public void reStart() {
getController().reStart();
public long reStart() {
return getController().reStart();
}
@Override

View File

@@ -33,6 +33,9 @@ public class FtpOption extends BaseOption {
private String protocol, keyAlias, storePass, storePath;
private boolean isImplicit = true;
private IFtpUploadInterceptor uploadInterceptor;
private int connMode = FtpConnectionMode.DATA_CONNECTION_MODE_PASV;
private int minPort, maxPort;
private String activeExternalIPAddress;
public FtpOption() {
super();
@@ -70,7 +73,7 @@ public class FtpOption extends BaseOption {
*
* @param protocol {@link ProtocolType}
*/
public FtpOption setProtocol(@ProtocolType String protocol) {
public FtpOption setProtocol(String protocol) {
if (TextUtils.isEmpty(protocol)) {
ALog.e(TAG, "设置协议失败,协议信息为空");
return this;
@@ -143,6 +146,63 @@ public class FtpOption extends BaseOption {
return this;
}
/**
* 设置数据传输模式,默认为被动模式。
* 主动模式传输文件时客户端开启一个端口ftp服务器连接到客户端的该端口ftp服务器推送数据到客户端
* 被动模式传输文件时ftp服务器开启一个端口客户端连接到ftp服务器的这个端口客户端请求ftp服务器的数据
* 请注意主动模式是服务器主动连接到android如果使用住的模式请确保ftp服务器能ping通android
*
* @param connMode {@link FtpConnectionMode#DATA_CONNECTION_MODE_PASV},
* {@link FtpConnectionMode#DATA_CONNECTION_MODE_ACTIVITY}
*/
public FtpOption setConnectionMode(int connMode) {
if (connMode != FtpConnectionMode.DATA_CONNECTION_MODE_PASV
&& connMode != FtpConnectionMode.DATA_CONNECTION_MODE_ACTIVITY) {
ALog.e(TAG, "连接模式设置失败,默认启用被动模式");
return this;
}
this.connMode = connMode;
return this;
}
/**
* 主动模式下的端口范围
*/
public FtpOption setActivePortRange(int minPort, int maxPort) {
if (minPort > maxPort) {
ALog.e(TAG, "设置端口范围错误minPort > maxPort");
return this;
}
if (minPort <= 0 || minPort >= 65535) {
ALog.e(TAG, "端口范围错误");
return this;
}
if (maxPort >= 65535) {
ALog.e(TAG, "端口范围错误");
return this;
}
this.minPort = minPort;
this.maxPort = maxPort;
return this;
}
/**
* 主动模式下对外ip可被Ftp服务器访问的ip
*/
public FtpOption setActiveExternalIPAddress(String ip) {
if (TextUtils.isEmpty(ip)) {
ALog.e(TAG, "ip为空");
return this;
}
if (!CheckUtil.checkIp(ip)) {
ALog.e(TAG, "ip地址错误" + ip);
return this;
}
this.activeExternalIPAddress = ip;
return this;
}
public void setUrlEntity(FtpUrlEntity urlEntity) {
this.urlEntity = urlEntity;
urlEntity.needLogin = isNeedLogin;

View File

@@ -16,11 +16,6 @@
package com.arialyy.aria.core.common;
import android.text.TextUtils;
import androidx.annotation.CheckResult;
import androidx.annotation.NonNull;
import com.arialyy.aria.core.download.target.HttpBuilderTarget;
import com.arialyy.aria.core.inf.IOptionConstant;
import com.arialyy.aria.core.inf.Suggest;
import com.arialyy.aria.core.processor.IHttpFileLenAdapter;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
@@ -50,7 +45,6 @@ public class HttpOption extends BaseOption {
*
* @param requestEnum {@link RequestEnum}
*/
@CheckResult(suggest = Suggest.TO_CONTROLLER)
public HttpOption setRequestType(RequestEnum requestEnum) {
this.requestEnum = requestEnum;
return this;
@@ -97,7 +91,7 @@ public class HttpOption extends BaseOption {
* @param key header对应的key
* @param value header对应的value
*/
public HttpOption addHeader(@NonNull String key, @NonNull String value) {
public HttpOption addHeader(String key, String value) {
if (TextUtils.isEmpty(key)) {
ALog.w(TAG, "设置header失败header对应的key不能为null");
return this;
@@ -118,7 +112,7 @@ public class HttpOption extends BaseOption {
*
* @param headers 一组http header数据
*/
public HttpOption addHeaders(@NonNull Map<String, String> headers) {
public HttpOption addHeaders(Map<String, String> headers) {
if (headers.size() == 0) {
ALog.w(TAG, "设置header失败map没有header数据");
return this;

View File

@@ -75,50 +75,23 @@ public class ProxyHelper {
return result;
}
result = new HashSet<>();
try {
if (getClass().getClassLoader()
.loadClass(className.concat(TaskEnum.DOWNLOAD_GROUP.proxySuffix))
!= null) {
result.add(PROXY_TYPE_DOWNLOAD_GROUP);
}
} catch (ClassNotFoundException e) {
//e.printStackTrace();
if (checkProxyExist(className, TaskEnum.DOWNLOAD_GROUP.proxySuffix)) {
result.add(PROXY_TYPE_DOWNLOAD_GROUP);
}
try {
if (getClass().getClassLoader().loadClass(className.concat(TaskEnum.DOWNLOAD.proxySuffix))
!= null) {
result.add(PROXY_TYPE_DOWNLOAD);
}
} catch (ClassNotFoundException e) {
//e.printStackTrace();
if (checkProxyExist(className, TaskEnum.DOWNLOAD.proxySuffix)) {
result.add(PROXY_TYPE_DOWNLOAD);
}
try {
if (getClass().getClassLoader().loadClass(className.concat(TaskEnum.UPLOAD.proxySuffix))
!= null) {
result.add(PROXY_TYPE_UPLOAD);
}
} catch (ClassNotFoundException e) {
//e.printStackTrace();
if (checkProxyExist(className, TaskEnum.UPLOAD.proxySuffix)) {
result.add(PROXY_TYPE_UPLOAD);
}
try {
if (getClass().getClassLoader().loadClass(className.concat(TaskEnum.M3U8_PEER.proxySuffix))
!= null) {
result.add(PROXY_TYPE_M3U8_PEER);
}
} catch (ClassNotFoundException e) {
//e.printStackTrace();
if (checkProxyExist(className, TaskEnum.M3U8_PEER.proxySuffix)) {
result.add(PROXY_TYPE_M3U8_PEER);
}
try {
if (getClass().getClassLoader()
.loadClass(className.concat(TaskEnum.DOWNLOAD_GROUP_SUB.proxySuffix))
!= null) {
result.add(PROXY_TYPE_DOWNLOAD_GROUP_SUB);
}
} catch (ClassNotFoundException e) {
//e.printStackTrace();
if (checkProxyExist(className, TaskEnum.DOWNLOAD_GROUP_SUB.proxySuffix)) {
result.add(PROXY_TYPE_DOWNLOAD_GROUP_SUB);
}
if (!result.isEmpty()) {
@@ -126,4 +99,20 @@ public class ProxyHelper {
}
return result;
}
private boolean checkProxyExist(String className, String proxySuffix) {
String clsName = className.concat(proxySuffix);
try {
if (getClass().getClassLoader().loadClass(clsName) != null) {
return true;
}
if (Class.forName(clsName) != null) {
return true;
}
} catch (ClassNotFoundException e) {
//e.printStackTrace();
}
return false;
}
}

View File

@@ -15,10 +15,10 @@
*/
package com.arialyy.aria.core.common.controller;
import com.arialyy.aria.core.command.CmdHelper;
import com.arialyy.aria.core.command.NormalCmdFactory;
import com.arialyy.aria.core.event.EventMsgUtil;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.command.CmdHelper;
/**
* 创建任务时使用的控制器
@@ -35,6 +35,7 @@ public final class BuilderController extends FeatureController implements IStart
* @return 正常添加返回任务id否则返回-1
*/
public long add() {
setAction(ACTION_ADD);
if (checkConfig()) {
EventMsgUtil.getDefault()
.post(CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_CREATE,
@@ -50,17 +51,18 @@ public final class BuilderController extends FeatureController implements IStart
* @return 正常启动返回任务id否则返回-1
*/
public long create() {
setAction(ACTION_CREATE);
if (checkConfig()) {
EventMsgUtil.getDefault()
.post(CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_START,
checkTaskType()));
return getEntity().getId();
}
return -1;
}
@Override public long setHighestPriority() {
setAction(ACTION_PRIORITY);
if (checkConfig()) {
EventMsgUtil.getDefault()
.post(CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_HIGHEST_PRIORITY,

View File

@@ -19,21 +19,21 @@ import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Looper;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.common.AbsEntity;
import com.arialyy.aria.core.download.CheckDEntityUtil;
import com.arialyy.aria.core.download.CheckDGEntityUtil;
import com.arialyy.aria.core.download.CheckFtpDirEntityUtil;
import com.arialyy.aria.core.download.DGTaskWrapper;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.common.AbsEntity;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.inf.ICheckEntityUtil;
import com.arialyy.aria.core.task.ITask;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.core.listener.ISchedulers;
import com.arialyy.aria.core.scheduler.TaskSchedulers;
import com.arialyy.aria.core.task.ITask;
import com.arialyy.aria.core.upload.CheckUEntityUtil;
import com.arialyy.aria.core.upload.UTaskWrapper;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.Constructor;
@@ -43,9 +43,25 @@ import java.lang.reflect.InvocationTargetException;
* 功能控制器
*/
public abstract class FeatureController {
private static final int ACTION_DEF = 0;
public static final int ACTION_CREATE = 1;
public static final int ACTION_RESUME = 2;
public static final int ACTION_STOP = 3;
public static final int ACTION_CANCEL = 4;
public static final int ACTION_ADD = 5;
public static final int ACTION_PRIORITY = 6;
public static final int ACTION_RETRY = 7;
public static final int ACTION_RESTART = 8;
public static final int ACTION_SAVE = 9;
private final String TAG;
private AbsTaskWrapper mTaskWrapper;
/**
* 是否忽略权限检查 true 忽略权限检查
*/
private boolean ignoreCheckPermissions = false;
private int action = ACTION_DEF;
FeatureController(AbsTaskWrapper wrapper) {
mTaskWrapper = wrapper;
@@ -87,6 +103,24 @@ public abstract class FeatureController {
return null;
}
void setAction(int action) {
this.action = action;
}
/**
* 是否忽略权限检查
*/
public void ignoreCheckPermissions() {
this.ignoreCheckPermissions = true;
}
/**
* 强制执行任务,不管文件路径是否被占用
*/
public void ignoreFilePathOccupy() {
mTaskWrapper.setIgnoreFilePathOccupy(true);
}
protected AbsTaskWrapper getTaskWrapper() {
return mTaskWrapper;
}
@@ -111,7 +145,7 @@ public abstract class FeatureController {
* 如果检查实体失败,将错误回调
*/
boolean checkConfig() {
if (!checkPermission()) {
if (!ignoreCheckPermissions && !checkPermission()) {
return false;
}
boolean b = checkEntity();
@@ -134,21 +168,21 @@ public abstract class FeatureController {
*/
private boolean checkPermission() {
if (AriaManager.getInstance()
if (AriaConfig.getInstance()
.getAPP()
.checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ALog.e(TAG, "启动失败缺少权限Manifest.permission.WRITE_EXTERNAL_STORAGE");
return false;
}
if (AriaManager.getInstance()
if (AriaConfig.getInstance()
.getAPP()
.checkCallingOrSelfPermission(Manifest.permission.INTERNET)
!= PackageManager.PERMISSION_GRANTED) {
ALog.e(TAG, "启动失败缺少权限Manifest.permission.INTERNET");
return false;
}
if (AriaManager.getInstance()
if (AriaConfig.getInstance()
.getAPP()
.checkCallingOrSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
@@ -162,15 +196,15 @@ public abstract class FeatureController {
private boolean checkEntity() {
ICheckEntityUtil checkUtil = null;
if (mTaskWrapper instanceof DTaskWrapper) {
checkUtil = CheckDEntityUtil.newInstance((DTaskWrapper) mTaskWrapper);
checkUtil = CheckDEntityUtil.newInstance((DTaskWrapper) mTaskWrapper, action);
} else if (mTaskWrapper instanceof DGTaskWrapper) {
if (mTaskWrapper.getRequestType() == ITaskWrapper.D_FTP_DIR) {
checkUtil = CheckFtpDirEntityUtil.newInstance((DGTaskWrapper) mTaskWrapper);
checkUtil = CheckFtpDirEntityUtil.newInstance((DGTaskWrapper) mTaskWrapper, action);
} else if (mTaskWrapper.getRequestType() == ITaskWrapper.DG_HTTP) {
checkUtil = CheckDGEntityUtil.newInstance((DGTaskWrapper) mTaskWrapper);
checkUtil = CheckDGEntityUtil.newInstance((DGTaskWrapper) mTaskWrapper, action);
}
} else if (mTaskWrapper instanceof UTaskWrapper) {
checkUtil = CheckUEntityUtil.newInstance((UTaskWrapper) mTaskWrapper);
checkUtil = CheckUEntityUtil.newInstance((UTaskWrapper) mTaskWrapper, action);
}
return checkUtil != null && checkUtil.checkEntity();
}

View File

@@ -30,6 +30,14 @@ public interface INormalFeature {
*/
void resume();
/**
* 正常来说,当执行队列满时,调用恢复任务接口,只能将任务放到缓存队列中。
* 如果希望调用恢复接口,马上进入执行队列,需要使用该方法
*
* @param newStart true 立即将任务恢复到执行队列中
*/
void resume(boolean newStart);
/**
* 删除任务
*/
@@ -51,7 +59,7 @@ public interface INormalFeature {
/**
* 重新下载
*/
void reStart();
long reStart();
/**
* 保存数据

View File

@@ -16,11 +16,12 @@
package com.arialyy.aria.core.common.controller;
import com.arialyy.aria.core.command.CancelCmd;
import com.arialyy.aria.core.command.CmdHelper;
import com.arialyy.aria.core.command.NormalCmdFactory;
import com.arialyy.aria.core.command.StartCmd;
import com.arialyy.aria.core.event.EventMsgUtil;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.core.command.CmdHelper;
/**
* 启动控制器
@@ -37,6 +38,7 @@ public final class NormalController extends FeatureController implements INormal
*/
@Override
public void stop() {
setAction(ACTION_STOP);
if (checkConfig()) {
EventMsgUtil.getDefault()
.post(CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_STOP,
@@ -49,10 +51,24 @@ public final class NormalController extends FeatureController implements INormal
*/
@Override
public void resume() {
resume(false);
}
/**
* 正常来说,当执行队列满时,调用恢复任务接口,只能将任务放到缓存队列中。
* 如果希望调用恢复接口,马上进入执行队列,需要使用该方法
*
* @param newStart true 立即将任务恢复到执行队列中
*/
@Override public void resume(boolean newStart) {
setAction(ACTION_RESUME);
if (checkConfig()) {
StartCmd cmd =
(StartCmd) CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_START,
checkTaskType());
cmd.setNewStart(newStart);
EventMsgUtil.getDefault()
.post(CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_START,
checkTaskType()));
.post(cmd);
}
}
@@ -61,11 +77,7 @@ public final class NormalController extends FeatureController implements INormal
*/
@Override
public void cancel() {
if (checkConfig()) {
EventMsgUtil.getDefault()
.post(CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_CANCEL,
checkTaskType()));
}
cancel(false);
}
/**
@@ -73,6 +85,7 @@ public final class NormalController extends FeatureController implements INormal
*/
@Override
public void reTry() {
setAction(ACTION_RETRY);
if (checkConfig()) {
int taskType = checkTaskType();
EventMsgUtil.getDefault()
@@ -91,6 +104,7 @@ public final class NormalController extends FeatureController implements INormal
*/
@Override
public void cancel(boolean removeFile) {
setAction(ACTION_CANCEL);
if (checkConfig()) {
CancelCmd cancelCmd =
(CancelCmd) CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_CANCEL,
@@ -104,15 +118,19 @@ public final class NormalController extends FeatureController implements INormal
* 重新下载
*/
@Override
public void reStart() {
public long reStart() {
setAction(ACTION_RESTART);
if (checkConfig()) {
EventMsgUtil.getDefault()
.post(CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_RESTART,
checkTaskType()));
return getEntity().getId();
}
return -1;
}
@Override public void save() {
setAction(ACTION_SAVE);
if (!checkConfig()) {
ALog.e(TAG, "保存修改失败");
} else {

View File

@@ -16,16 +16,15 @@
package com.arialyy.aria.core.download;
import android.text.TextUtils;
import com.arialyy.aria.core.common.ErrorCode;
import com.arialyy.aria.core.common.controller.FeatureController;
import com.arialyy.aria.core.inf.ICheckEntityUtil;
import com.arialyy.aria.core.inf.IOptionConstant;
import com.arialyy.aria.core.inf.IRecordHandler;
import com.arialyy.aria.core.inf.ITargetHandler;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
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.FileUtil;
import com.arialyy.aria.util.RecordUtil;
import java.io.File;
@@ -36,12 +35,14 @@ public class CheckDEntityUtil implements ICheckEntityUtil {
private final String TAG = CommonUtil.getClassName(getClass());
private DTaskWrapper mWrapper;
private DownloadEntity mEntity;
private int action;
public static CheckDEntityUtil newInstance(DTaskWrapper wrapper) {
return new CheckDEntityUtil(wrapper);
public static CheckDEntityUtil newInstance(DTaskWrapper wrapper, int action) {
return new CheckDEntityUtil(wrapper, action);
}
private CheckDEntityUtil(DTaskWrapper wrapper) {
private CheckDEntityUtil(DTaskWrapper wrapper, int action) {
this.action = action;
mWrapper = wrapper;
mEntity = mWrapper.getEntity();
}
@@ -68,38 +69,36 @@ public class CheckDEntityUtil implements ICheckEntityUtil {
File file = new File(mWrapper.getTempFilePath());
Object bw = mWrapper.getM3U8Params().getParam(IOptionConstant.bandWidth);
int bandWidth = bw == null ? 0 : (int) bw;
// 缓存文件夹格式:问文件夹/.文件名_码率
String cacheDir = String.format("%s/.%s_%s", file.getParent(), file.getName(), bandWidth);
String cacheDir = FileUtil.getTsCacheDir(file.getPath(), bandWidth);
mWrapper.getM3U8Params().setParams(IOptionConstant.cacheDir, cacheDir);
M3U8Entity m3U8Entity = mEntity.getM3U8Entity();
Object temp = mWrapper.getM3U8Params().getParam(IOptionConstant.generateIndexFileTemp);
boolean generateIndexFileTemp = temp != null && (boolean) temp;
if (m3U8Entity == null) {
m3U8Entity = new M3U8Entity();
m3U8Entity.setFilePath(mEntity.getFilePath());
m3U8Entity.setPeerIndex(0);
m3U8Entity.setCacheDir(cacheDir);
m3U8Entity.setGenerateIndexFile(generateIndexFileTemp);
m3U8Entity.insert();
} else {
m3U8Entity.setGenerateIndexFile(generateIndexFileTemp);
m3U8Entity.update();
}
if (mWrapper.getRequestType() == ITaskWrapper.M3U8_VOD) {
if (mWrapper.getRequestType() == ITaskWrapper.M3U8_VOD
&& action == FeatureController.ACTION_CREATE) {
if (mEntity.getFileSize() == 0) {
ALog.w(TAG,
"由于m3u8协议的特殊性质无法有效快速获取到正确到文件长度如果你需要显示文件中长度你需要自行设置文件长度.asM3U8().asVod().setFileSize(xxx)");
}
} else if (mWrapper.getRequestType() == ITaskWrapper.M3U8_LIVE) {
} else if (mWrapper.getRequestType() == ITaskWrapper.M3U8_LIVE
&& action != FeatureController.ACTION_CANCEL) {
if (file.exists()) {
ALog.w(TAG, "对于直播来说每次下载都是一个新文件所以你需要设置新都文件路径否则Aria框架将会覆盖已下载的文件");
file.delete();
}
}
if (mWrapper.getM3U8Params().getHandler(IOptionConstant.bandWidthUrlConverter) != null
if (action != FeatureController.ACTION_CANCEL
&& mWrapper.getM3U8Params().getHandler(IOptionConstant.bandWidthUrlConverter) != null
&& bandWidth == 0) {
ALog.w(TAG, "你已经设置了码率url转换器但是没有设置码率Aria框架将采用第一个获取到的码率");
}
@@ -141,14 +140,8 @@ public class CheckDEntityUtil implements ICheckEntityUtil {
//设置文件保存路径,如果新文件路径和旧文件路径不同,则修改路径
if (!filePath.equals(mEntity.getFilePath())) {
// 检查路径冲突
if (DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=?", filePath)) {
if (!mWrapper.isForceDownload()) {
ALog.e(TAG, String.format("下载失败,保存路径【%s】已经被其它任务占用请设置其它保存路径", filePath));
return false;
} else {
ALog.w(TAG, String.format("保存路径【%s】已经被其它任务占用当前任务将覆盖该路径的文件", filePath));
RecordUtil.delTaskRecord(filePath, IRecordHandler.TYPE_DOWNLOAD);
}
if (!CheckUtil.checkDPathConflicts(mWrapper.isIgnoreFilePathOccupy(), filePath)) {
return false;
}
File newFile = new File(filePath);
@@ -164,11 +157,11 @@ public class CheckDEntityUtil implements ICheckEntityUtil {
File oldFile = new File(mEntity.getFilePath());
if (oldFile.exists()) {
// 处理普通任务的重命名
RecordUtil.modifyTaskRecord(oldFile.getPath(), newFile.getPath());
RecordUtil.modifyTaskRecord(oldFile.getPath(), newFile.getPath(), mEntity.getTaskType());
ALog.i(TAG, String.format("将任务重命名为:%s", newFile.getName()));
} else if (RecordUtil.blockTaskExists(oldFile.getPath())) {
// 处理分块任务的重命名
RecordUtil.modifyTaskRecord(oldFile.getPath(), newFile.getPath());
RecordUtil.modifyTaskRecord(oldFile.getPath(), newFile.getPath(), mEntity.getTaskType());
ALog.i(TAG, String.format("将分块任务重命名为:%s", newFile.getName()));
}
}

View File

@@ -16,12 +16,13 @@
package com.arialyy.aria.core.download;
import android.text.TextUtils;
import com.arialyy.aria.core.common.ErrorCode;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.common.controller.FeatureController;
import com.arialyy.aria.core.inf.ICheckEntityUtil;
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;
@@ -41,12 +42,14 @@ public class CheckDGEntityUtil implements ICheckEntityUtil {
* 是否需要修改路径
*/
private boolean needModifyPath = false;
private int action;
public static CheckDGEntityUtil newInstance(DGTaskWrapper wrapper) {
return new CheckDGEntityUtil(wrapper);
public static CheckDGEntityUtil newInstance(DGTaskWrapper wrapper, int action) {
return new CheckDGEntityUtil(wrapper, action);
}
private CheckDGEntityUtil(DGTaskWrapper wrapper) {
private CheckDGEntityUtil(DGTaskWrapper wrapper, int action) {
this.action = action;
mWrapper = wrapper;
mEntity = mWrapper.getEntity();
}
@@ -70,10 +73,9 @@ public class CheckDGEntityUtil implements ICheckEntityUtil {
return false;
}
if ((mEntity.getDirPath() == null || !mEntity.getDirPath().equals(mWrapper.getDirPathTemp()))
&& DbEntity.checkDataExist(DownloadGroupEntity.class, "dirPath=?",
// 检查路径冲突
if (mWrapper.isNewTask() && !CheckUtil.checkDGPathConflicts(mWrapper.isIgnoreFilePathOccupy(),
mWrapper.getDirPathTemp())) {
ALog.e(TAG, String.format("文件夹路径【%s】已被其它任务占用请重新设置文件夹路径", mWrapper.getDirPathTemp()));
return false;
}
@@ -130,7 +132,9 @@ public class CheckDGEntityUtil implements ICheckEntityUtil {
return false;
}
if (!mWrapper.isUnknownSize() && mEntity.getFileSize() == 0) {
if (action != FeatureController.ACTION_CANCEL
&& !mWrapper.isUnknownSize()
&& mEntity.getFileSize() == 0) {
ALog.e(TAG, "组合任务必须设置文件文件大小,默认需要强制设置文件大小。如果无法获取到总长度,请调用#unknownSize()来标志该组合任务");
return false;
}
@@ -170,13 +174,12 @@ public class CheckDGEntityUtil implements ICheckEntityUtil {
if (!newName.equals(entity.getFileName())) {
String oldPath = mEntity.getDirPath() + "/" + entity.getFileName();
String newPath = mEntity.getDirPath() + "/" + newName;
if (DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=? or isComplete='true'",
newPath)) {
ALog.w(TAG, String.format("更新文件名失败,路径【%s】已存在或文件已下载", newPath));
if (DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=?", newPath)) {
ALog.w(TAG, String.format("更新文件名失败,路径【%s】被其它任务占用", newPath));
return;
}
RecordUtil.modifyTaskRecord(oldPath, newPath);
RecordUtil.modifyTaskRecord(oldPath, newPath, mEntity.getTaskType());
entity.setFilePath(newPath);
entity.setFileName(newName);
}

View File

@@ -17,7 +17,6 @@ package com.arialyy.aria.core.download;
import android.text.TextUtils;
import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.ErrorCode;
import com.arialyy.aria.core.inf.ICheckEntityUtil;
import com.arialyy.aria.core.inf.IOptionConstant;
import com.arialyy.aria.orm.DbEntity;
@@ -28,12 +27,14 @@ public class CheckFtpDirEntityUtil implements ICheckEntityUtil {
private final String TAG = "CheckFtpDirEntityUtil";
private DGTaskWrapper mWrapper;
private DownloadGroupEntity mEntity;
private int action;
public static CheckFtpDirEntityUtil newInstance(DGTaskWrapper wrapper) {
return new CheckFtpDirEntityUtil(wrapper);
public static CheckFtpDirEntityUtil newInstance(DGTaskWrapper wrapper, int action) {
return new CheckFtpDirEntityUtil(wrapper, action);
}
private CheckFtpDirEntityUtil(DGTaskWrapper wrapper) {
private CheckFtpDirEntityUtil(DGTaskWrapper wrapper, int action) {
this.action = action;
mWrapper = wrapper;
mEntity = mWrapper.getEntity();
}

View File

@@ -15,9 +15,8 @@
*/
package com.arialyy.aria.core.download;
import androidx.annotation.CheckResult;
import androidx.annotation.NonNull;
import com.arialyy.annotations.TaskEnum;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.CancelAllCmd;
import com.arialyy.aria.core.command.CmdHelper;
@@ -64,7 +63,7 @@ public class DownloadReceiver extends AbsReceiver {
*/
@Deprecated
public DownloadReceiver setMaxSpeed(int maxSpeed) {
AriaManager.getInstance().getDownloadConfig().setMaxSpeed(maxSpeed);
AriaConfig.getInstance().getDConfig().setMaxSpeed(maxSpeed);
return this;
}
@@ -73,8 +72,7 @@ public class DownloadReceiver extends AbsReceiver {
*
* @param url 下载地址
*/
@CheckResult
public HttpBuilderTarget load(@NonNull String url) {
public HttpBuilderTarget load(String url) {
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_HTTP);
return DTargetFactory.getInstance()
.generateBuilderTarget(HttpBuilderTarget.class, url);
@@ -86,7 +84,6 @@ public class DownloadReceiver extends AbsReceiver {
* @param taskId 任务id可从{@link AbsBuilderTarget#create()}、{@link AbsBuilderTarget#add()}、{@link
* AbsEntity#getId()}读取任务id
*/
@CheckResult
public HttpNormalTarget load(long taskId) {
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_HTTP);
return DTargetFactory.getInstance()
@@ -98,7 +95,6 @@ public class DownloadReceiver extends AbsReceiver {
*
* @param urls 组合任务只任务列被,如果任务组的中的下载地址改变了,则任务从新的一个任务组
*/
@CheckResult
public GroupBuilderTarget loadGroup(List<String> urls) {
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_HTTP);
return DTargetFactory.getInstance().generateGroupBuilderTarget(urls);
@@ -110,7 +106,7 @@ public class DownloadReceiver extends AbsReceiver {
* @param taskId 任务id可从{@link AbsBuilderTarget#create()}、{@link AbsBuilderTarget#add()}、{@link
* * AbsEntity#getId()}读取任务id
*/
@CheckResult
public GroupNormalTarget loadGroup(long taskId) {
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_HTTP);
return DTargetFactory.getInstance()
@@ -120,8 +116,8 @@ public class DownloadReceiver extends AbsReceiver {
/**
* 加载ftp单任务下载地址用于任务第一次下载如果需要控制任务停止或删除等操作请使用{@link #loadFtp(long)}
*/
@CheckResult
public FtpBuilderTarget loadFtp(@NonNull String url) {
public FtpBuilderTarget loadFtp(String url) {
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_FTP);
return DTargetFactory.getInstance()
.generateBuilderTarget(FtpBuilderTarget.class, url);
@@ -133,7 +129,7 @@ public class DownloadReceiver extends AbsReceiver {
* @param taskId 任务id可从{@link AbsBuilderTarget#create()}、{@link AbsBuilderTarget#add()}、{@link
* AbsEntity#getId()}读取任务id
*/
@CheckResult
public FtpNormalTarget loadFtp(long taskId) {
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_FTP);
return DTargetFactory.getInstance()
@@ -143,8 +139,8 @@ public class DownloadReceiver extends AbsReceiver {
/**
* 加载ftp文件夹下载地址用于任务第一次下载如果需要控制任务停止或删除等操作请使用{@link #loadFtpDir(long)}
*/
@CheckResult
public FtpDirBuilderTarget loadFtpDir(@NonNull String dirUrl) {
public FtpDirBuilderTarget loadFtpDir(String dirUrl) {
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_FTP);
return DTargetFactory.getInstance().generateDirBuilderTarget(dirUrl);
}
@@ -155,7 +151,7 @@ public class DownloadReceiver extends AbsReceiver {
* @param taskId 任务id可从{@link AbsBuilderTarget#create()}、{@link AbsBuilderTarget#add()}、{@link
* AbsEntity#getId()}读取任务id
*/
@CheckResult
public FtpDirNormalTarget loadFtpDir(long taskId) {
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_FTP);
return DTargetFactory.getInstance()
@@ -287,10 +283,10 @@ public class DownloadReceiver extends AbsReceiver {
* @return 如果实体不存在返回null
*/
public DownloadGroupEntity getGroupEntity(List<String> urls) {
if (CheckUtil.checkDownloadUrlsIsEmpty(urls)){
if (CheckUtil.checkDownloadUrlsIsEmpty(urls)) {
return null;
}
return DbDataHelper.getDGEntity(CommonUtil.getMd5Code(urls));
return DbDataHelper.getDGEntityByHash(CommonUtil.getMd5Code(urls));
}
/**
@@ -303,7 +299,7 @@ public class DownloadReceiver extends AbsReceiver {
if (!CheckUtil.checkUrl(url)) {
return null;
}
return DbDataHelper.getDGEntity(url);
return DbDataHelper.getDGEntityByHash(url);
}
/**

View File

@@ -17,8 +17,8 @@ package com.arialyy.aria.core.download.m3u8;
import com.arialyy.aria.core.common.BaseOption;
import com.arialyy.aria.core.processor.IBandWidthUrlConverter;
import com.arialyy.aria.core.processor.IKeyUrlConverter;
import com.arialyy.aria.core.processor.ITsMergeHandler;
import com.arialyy.aria.core.processor.IVodTsUrlConverter;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.ComponentUtil;
@@ -27,23 +27,34 @@ import com.arialyy.aria.util.ComponentUtil;
*/
public class M3U8Option<OP extends M3U8Option> extends BaseOption {
private boolean generateIndexFileTemp = false;
private boolean mergeFile = false;
private boolean generateIndexFile = false;
private boolean mergeFile = true;
private int bandWidth;
private ITsMergeHandler mergeHandler;
private IBandWidthUrlConverter bandWidthUrlConverter;
private IKeyUrlConverter keyUrlConverter;
private boolean ignoreFailureTs = false;
M3U8Option() {
super();
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_M3U8);
}
/**
* 忽略下载失败的ts切片即使有失败的切片下载完成后也要合并所有切片并进入complete回调
*/
public OP ignoreFailureTs() {
this.ignoreFailureTs = true;
return (OP) this;
}
/**
* 生成m3u8索引文件
* 注意:创建索引文件,{@link #merge(boolean)}方法设置与否都不再合并文件
* 如果是直播文件下载,创建索引文件的操作将导致只能同时下载一个切片!!
*/
public OP generateIndexFile() {
this.generateIndexFileTemp = true;
this.generateIndexFile = true;
return (OP) this;
}
@@ -88,4 +99,15 @@ public class M3U8Option<OP extends M3U8Option> extends BaseOption {
this.bandWidthUrlConverter = bandWidthUrlConverter;
return (OP) this;
}
/**
* M3U8 密钥url转换器对于某些服务器密钥的下载地址是被加密的因此需要使用该方法将被加密的密钥解密成可被识别的http地址
*
* @param keyUrlConverter {@link IKeyUrlConverter}
*/
public OP setKeyUrlConverter(IKeyUrlConverter keyUrlConverter) {
CheckUtil.checkMemberClass(keyUrlConverter.getClass());
this.keyUrlConverter = keyUrlConverter;
return (OP) this;
}
}

View File

@@ -16,9 +16,7 @@
package com.arialyy.aria.core.download.target;
import android.text.TextUtils;
import androidx.annotation.CheckResult;
import com.arialyy.aria.core.common.AbsNormalTarget;
import com.arialyy.aria.core.common.ErrorCode;
import com.arialyy.aria.core.download.DGTaskWrapper;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.event.ErrorEvent;
@@ -66,7 +64,6 @@ abstract class AbsGroupConfigHandler<TARGET extends AbsTarget> implements IConfi
*
* @return 子任务管理器
*/
@CheckResult
SubTaskManager getSubTaskManager() {
if (mSubTaskManager == null) {
mSubTaskManager = new SubTaskManager(getTaskWrapper());
@@ -89,7 +86,6 @@ abstract class AbsGroupConfigHandler<TARGET extends AbsTarget> implements IConfi
return task != null && task.isRunning();
}
@CheckResult
TARGET setDirPath(String dirPath) {
mWrapper.setDirPathTemp(dirPath);
return mTarget;

View File

@@ -93,7 +93,7 @@ class DNormalConfigHandler<TARGET extends AbsTarget> implements IConfigHandler {
}
void setForceDownload(boolean forceDownload) {
getWrapper().setForceDownload(forceDownload);
getWrapper().setIgnoreFilePathOccupy(forceDownload);
}
void setUrl(String url) {

View File

@@ -15,12 +15,9 @@
*/
package com.arialyy.aria.core.download.target;
import androidx.annotation.CheckResult;
import androidx.annotation.NonNull;
import com.arialyy.aria.core.common.AbsBuilderTarget;
import com.arialyy.aria.core.common.FtpOption;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.inf.Suggest;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.util.CommonUtil;
@@ -34,12 +31,13 @@ public class FtpBuilderTarget extends AbsBuilderTarget<FtpBuilderTarget> {
mConfigHandler = new DNormalConfigHandler<>(this, -1);
mConfigHandler.setUrl(url);
getTaskWrapper().setRequestType(ITaskWrapper.D_FTP);
getEntity().setTaskType(ITaskWrapper.D_FTP);
getTaskWrapper().setNewTask(true);
}
/**
* 设置登陆、字符串编码、ftps等参数
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public FtpBuilderTarget option(FtpOption option) {
if (option == null) {
throw new NullPointerException("ftp 任务配置为空");
@@ -55,8 +53,7 @@ public class FtpBuilderTarget extends AbsBuilderTarget<FtpBuilderTarget> {
* 1、如果保存路径是该文件的保存路径/mnt/sdcard/file.zip则使用路径中的文件名file.zip
* 2、如果保存路径是文件夹路径/mnt/sdcard/则使用FTP服务器该文件的文件名
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public FtpBuilderTarget setFilePath(@NonNull String filePath) {
public FtpBuilderTarget setFilePath(String filePath) {
int lastIndex = mConfigHandler.getUrl().lastIndexOf("/");
getEntity().setFileName(mConfigHandler.getUrl().substring(lastIndex + 1));
mConfigHandler.setTempFilePath(filePath);
@@ -70,9 +67,10 @@ public class FtpBuilderTarget extends AbsBuilderTarget<FtpBuilderTarget> {
*
* @param filePath 路径必须为文件路径,不能为文件夹路径
* @param forceDownload {@code true}强制下载,不考虑文件路径是否被占用
* @deprecated 使用 {@link #ignoreFilePathOccupy()}
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public FtpBuilderTarget setFilePath(@NonNull String filePath, boolean forceDownload) {
@Deprecated
public FtpBuilderTarget setFilePath(String filePath, boolean forceDownload) {
mConfigHandler.setTempFilePath(filePath);
mConfigHandler.setForceDownload(forceDownload);
return this;

View File

@@ -15,11 +15,9 @@
*/
package com.arialyy.aria.core.download.target;
import androidx.annotation.CheckResult;
import com.arialyy.aria.core.common.AbsBuilderTarget;
import com.arialyy.aria.core.common.FtpOption;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.inf.Suggest;
import com.arialyy.aria.core.manager.SubTaskManager;
import com.arialyy.aria.util.CommonUtil;
@@ -35,6 +33,7 @@ public class FtpDirBuilderTarget extends AbsBuilderTarget<FtpDirBuilderTarget> {
this.url = url;
mConfigHandler = new FtpDirConfigHandler<>(this, -1);
getEntity().setGroupHash(url);
getTaskWrapper().setNewTask(true);
}
/**
@@ -56,7 +55,6 @@ public class FtpDirBuilderTarget extends AbsBuilderTarget<FtpDirBuilderTarget> {
*
* @param dirPath 任务组保存文件夹路径
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public FtpDirBuilderTarget setDirPath(String dirPath) {
return mConfigHandler.setDirPath(dirPath);
}
@@ -64,7 +62,6 @@ public class FtpDirBuilderTarget extends AbsBuilderTarget<FtpDirBuilderTarget> {
/**
* 设置任务组别名
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public FtpDirBuilderTarget setGroupAlias(String alias) {
mConfigHandler.setGroupAlias(alias);
return this;
@@ -73,7 +70,6 @@ public class FtpDirBuilderTarget extends AbsBuilderTarget<FtpDirBuilderTarget> {
/**
* 设置登陆、字符串编码、ftps等参数
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public FtpDirBuilderTarget option(FtpOption option) {
if (option == null) {
throw new NullPointerException("ftp 任务配置为空");
@@ -92,7 +88,6 @@ public class FtpDirBuilderTarget extends AbsBuilderTarget<FtpDirBuilderTarget> {
*
* @return 子任务管理器
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public SubTaskManager getSubTaskManager() {
return mConfigHandler.getSubTaskManager();
}

View File

@@ -33,11 +33,12 @@ class FtpDirConfigHandler<TARGET extends AbsTarget> extends AbsGroupConfigHandle
}
private void init() {
getTaskWrapper().setRequestType(AbsTaskWrapper.D_FTP_DIR);
getTaskWrapper().setRequestType(ITaskWrapper.D_FTP_DIR);
List<DTaskWrapper> wrappers = getTaskWrapper().getSubTaskWrapper();
if (!wrappers.isEmpty()) {
for (DTaskWrapper subWrapper : wrappers) {
subWrapper.setRequestType(ITaskWrapper.D_FTP);
subWrapper.getEntity().setTaskType(ITaskWrapper.D_FTP);
}
}
}

View File

@@ -15,11 +15,9 @@
*/
package com.arialyy.aria.core.download.target;
import androidx.annotation.CheckResult;
import com.arialyy.aria.core.common.AbsNormalTarget;
import com.arialyy.aria.core.common.FtpOption;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.inf.Suggest;
import com.arialyy.aria.core.manager.SubTaskManager;
import com.arialyy.aria.util.CommonUtil;
@@ -32,6 +30,7 @@ public class FtpDirNormalTarget extends AbsNormalTarget<FtpDirNormalTarget> {
FtpDirNormalTarget(long taskId) {
mConfigHandler = new FtpDirConfigHandler<>(this, taskId);
getTaskWrapper().setNewTask(false);
}
@Override public boolean isRunning() {
@@ -61,7 +60,6 @@ public class FtpDirNormalTarget extends AbsNormalTarget<FtpDirNormalTarget> {
*
* @param dirPath 任务组保存文件夹路径
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public FtpDirNormalTarget modifyDirPath(String dirPath) {
return mConfigHandler.setDirPath(dirPath);
}
@@ -69,7 +67,6 @@ public class FtpDirNormalTarget extends AbsNormalTarget<FtpDirNormalTarget> {
/**
* 设置登陆、字符串编码、ftps等参数
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public FtpDirNormalTarget option(FtpOption option) {
if (option == null) {
throw new NullPointerException("ftp 任务配置为空");
@@ -88,7 +85,6 @@ public class FtpDirNormalTarget extends AbsNormalTarget<FtpDirNormalTarget> {
*
* @return 子任务管理器
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public SubTaskManager getSubTaskManager() {
return mConfigHandler.getSubTaskManager();
}

View File

@@ -15,12 +15,9 @@
*/
package com.arialyy.aria.core.download.target;
import androidx.annotation.CheckResult;
import androidx.annotation.NonNull;
import com.arialyy.aria.core.common.AbsNormalTarget;
import com.arialyy.aria.core.common.FtpOption;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.inf.Suggest;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.util.CommonUtil;
@@ -34,12 +31,12 @@ public class FtpNormalTarget extends AbsNormalTarget<FtpNormalTarget> {
FtpNormalTarget(long taskId) {
mConfigHandler = new DNormalConfigHandler<>(this, taskId);
getTaskWrapper().setRequestType(ITaskWrapper.D_FTP);
getTaskWrapper().setNewTask(false);
}
/**
* 设置登陆、字符串编码、ftps等参数
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public FtpNormalTarget option(FtpOption option) {
if (option == null) {
throw new NullPointerException("ftp 任务配置为空");
@@ -55,8 +52,7 @@ public class FtpNormalTarget extends AbsNormalTarget<FtpNormalTarget> {
* 1、如果保存路径是该文件的保存路径/mnt/sdcard/file.zip则使用路径中的文件名file.zip
* 2、如果保存路径是文件夹路径/mnt/sdcard/则使用FTP服务器该文件的文件名
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public FtpNormalTarget modifyFilePath(@NonNull String filePath) {
public FtpNormalTarget modifyFilePath(String filePath) {
int lastIndex = mConfigHandler.getUrl().lastIndexOf("/");
getEntity().setFileName(mConfigHandler.getUrl().substring(lastIndex + 1));
mConfigHandler.setTempFilePath(filePath);
@@ -66,7 +62,6 @@ public class FtpNormalTarget extends AbsNormalTarget<FtpNormalTarget> {
/**
* 更新下载地址
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public FtpNormalTarget updateUrl(String newUrl) {
return mConfigHandler.updateUrl(newUrl);
}

View File

@@ -15,11 +15,9 @@
*/
package com.arialyy.aria.core.download.target;
import androidx.annotation.CheckResult;
import com.arialyy.aria.core.common.AbsBuilderTarget;
import com.arialyy.aria.core.common.HttpOption;
import com.arialyy.aria.core.download.DGTaskWrapper;
import com.arialyy.aria.core.inf.Suggest;
import com.arialyy.aria.core.manager.SubTaskManager;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.util.ALog;
@@ -34,14 +32,14 @@ public class GroupBuilderTarget extends AbsBuilderTarget<GroupBuilderTarget> {
GroupBuilderTarget(List<String> urls) {
mConfigHandler = new HttpGroupConfigHandler<>(this, -1);
getTaskWrapper().setRequestType(ITaskWrapper.DG_HTTP);
mConfigHandler.setGroupUrl(urls);
getTaskWrapper().setRequestType(ITaskWrapper.DG_HTTP);
getTaskWrapper().setNewTask(true);
}
/**
* 设置http请求参数header等信息
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public GroupBuilderTarget option(HttpOption option) {
if (option == null) {
throw new NullPointerException("任务配置为空");
@@ -58,7 +56,6 @@ public class GroupBuilderTarget extends AbsBuilderTarget<GroupBuilderTarget> {
*
* @param fileSize 任务组总大小
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public GroupBuilderTarget setFileSize(long fileSize) {
if (fileSize <= 0) {
ALog.e(TAG, "文件大小不能小于 0");
@@ -77,7 +74,6 @@ public class GroupBuilderTarget extends AbsBuilderTarget<GroupBuilderTarget> {
* 2、如果你的知道组合任务的总长度请使用{@link #setFileSize(long)}设置组合任务的长度。
* 3、由于网络或其它原因的存在这种方式获取的组合任务大小有可能是不准确的。
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public GroupBuilderTarget unknownSize() {
((DGTaskWrapper) getTaskWrapper()).setUnknownSize(true);
return this;
@@ -88,7 +84,6 @@ public class GroupBuilderTarget extends AbsBuilderTarget<GroupBuilderTarget> {
*
* @return 子任务管理器
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public SubTaskManager getSubTaskManager() {
return mConfigHandler.getSubTaskManager();
}
@@ -98,7 +93,6 @@ public class GroupBuilderTarget extends AbsBuilderTarget<GroupBuilderTarget> {
*
* @deprecated {@link #setSubFileName(List)} 请使用该api
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
@Deprecated public GroupBuilderTarget setSubTaskFileName(List<String> subTaskFileName) {
return setSubFileName(subTaskFileName);
}
@@ -106,7 +100,6 @@ public class GroupBuilderTarget extends AbsBuilderTarget<GroupBuilderTarget> {
/**
* 设置任务组别名
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public GroupBuilderTarget setGroupAlias(String alias) {
mConfigHandler.setGroupAlias(alias);
return this;
@@ -131,7 +124,6 @@ public class GroupBuilderTarget extends AbsBuilderTarget<GroupBuilderTarget> {
*
* @param dirPath 任务组保存文件夹路径
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public GroupBuilderTarget setDirPath(String dirPath) {
return mConfigHandler.setDirPath(dirPath);
}
@@ -139,7 +131,6 @@ public class GroupBuilderTarget extends AbsBuilderTarget<GroupBuilderTarget> {
/**
* 设置子任务文件名,该方法必须在{@link #setDirPath(String)}之后调用,否则不生效
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public GroupBuilderTarget setSubFileName(List<String> subTaskFileName) {
return mConfigHandler.setSubFileName(subTaskFileName);
}

View File

@@ -15,10 +15,8 @@
*/
package com.arialyy.aria.core.download.target;
import androidx.annotation.CheckResult;
import com.arialyy.aria.core.common.AbsNormalTarget;
import com.arialyy.aria.core.common.HttpOption;
import com.arialyy.aria.core.inf.Suggest;
import com.arialyy.aria.core.manager.SubTaskManager;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import java.util.List;
@@ -33,12 +31,12 @@ public class GroupNormalTarget extends AbsNormalTarget<GroupNormalTarget> {
GroupNormalTarget(long taskId) {
mConfigHandler = new HttpGroupConfigHandler<>(this, taskId);
getTaskWrapper().setRequestType(ITaskWrapper.DG_HTTP);
getTaskWrapper().setNewTask(false);
}
/**
* 设置http请求参数header等信息
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public GroupNormalTarget option(HttpOption option) {
if (option == null) {
throw new NullPointerException("任务配置为空");
@@ -52,7 +50,6 @@ public class GroupNormalTarget extends AbsNormalTarget<GroupNormalTarget> {
*
* @return 子任务管理器
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public SubTaskManager getSubTaskManager() {
return mConfigHandler.getSubTaskManager();
}
@@ -60,7 +57,6 @@ public class GroupNormalTarget extends AbsNormalTarget<GroupNormalTarget> {
/**
* 设置任务组别名
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public GroupNormalTarget setGroupAlias(String alias) {
mConfigHandler.setGroupAlias(alias);
return this;
@@ -71,7 +67,6 @@ public class GroupNormalTarget extends AbsNormalTarget<GroupNormalTarget> {
*
* @param urls 新的组合任务下载地址列表
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public GroupNormalTarget updateUrls(List<String> urls) {
return mConfigHandler.updateUrls(urls);
}
@@ -95,7 +90,6 @@ public class GroupNormalTarget extends AbsNormalTarget<GroupNormalTarget> {
*
* @param dirPath 任务组保存文件夹路径
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public GroupNormalTarget modifyDirPath(String dirPath) {
return mConfigHandler.setDirPath(dirPath);
}
@@ -103,7 +97,6 @@ public class GroupNormalTarget extends AbsNormalTarget<GroupNormalTarget> {
/**
* 更新子任务文件名,该方法必须在{@link #modifyDirPath(String)}之后调用,否则不生效
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public GroupNormalTarget modifySubFileName(List<String> subTaskFileName) {
return mConfigHandler.setSubFileName(subTaskFileName);
}

View File

@@ -15,19 +15,14 @@
*/
package com.arialyy.aria.core.download.target;
import androidx.annotation.CheckResult;
import androidx.annotation.NonNull;
import com.arialyy.aria.core.common.AbsBuilderTarget;
import com.arialyy.aria.core.common.HttpOption;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.m3u8.M3U8LiveOption;
import com.arialyy.aria.core.download.m3u8.M3U8VodOption;
import com.arialyy.aria.core.inf.IOptionConstant;
import com.arialyy.aria.core.inf.Suggest;
import com.arialyy.aria.core.processor.IHttpFileLenAdapter;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.util.CheckUtil;
public class HttpBuilderTarget extends AbsBuilderTarget<HttpBuilderTarget> {
@@ -35,13 +30,14 @@ public class HttpBuilderTarget extends AbsBuilderTarget<HttpBuilderTarget> {
HttpBuilderTarget(String url) {
mConfigHandler = new DNormalConfigHandler<>(this, -1);
getTaskWrapper().setRequestType(ITaskWrapper.D_HTTP);
mConfigHandler.setUrl(url);
getTaskWrapper().setRequestType(ITaskWrapper.D_HTTP);
getTaskWrapper().setNewTask(true);
((DownloadEntity)getEntity()).setTaskType(ITaskWrapper.D_HTTP);
}
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public HttpBuilderTarget m3u8VodOption(M3U8VodOption m3U8VodOption) {
if (m3U8VodOption == null){
if (m3U8VodOption == null) {
throw new NullPointerException("m3u8任务设置为空");
}
getTaskWrapper().setRequestType(AbsTaskWrapper.M3U8_VOD);
@@ -50,9 +46,8 @@ public class HttpBuilderTarget extends AbsBuilderTarget<HttpBuilderTarget> {
return this;
}
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public HttpBuilderTarget m3u8LiveOption(M3U8LiveOption m3U8LiveOption) {
if (m3U8LiveOption == null){
if (m3U8LiveOption == null) {
throw new NullPointerException("m3u8任务设置为空");
}
getTaskWrapper().setRequestType(AbsTaskWrapper.M3U8_LIVE);
@@ -63,7 +58,6 @@ public class HttpBuilderTarget extends AbsBuilderTarget<HttpBuilderTarget> {
/**
* 设置http请求参数header等信息
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public HttpBuilderTarget option(HttpOption option) {
if (option == null) {
throw new NullPointerException("任务配置为空");
@@ -79,8 +73,7 @@ public class HttpBuilderTarget extends AbsBuilderTarget<HttpBuilderTarget> {
*
* @param filePath 路径必须为文件路径,不能为文件夹路径
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public HttpBuilderTarget setFilePath(@NonNull String filePath) {
public HttpBuilderTarget setFilePath(String filePath) {
mConfigHandler.setTempFilePath(filePath);
return this;
}
@@ -92,9 +85,10 @@ public class HttpBuilderTarget extends AbsBuilderTarget<HttpBuilderTarget> {
*
* @param filePath 路径必须为文件路径,不能为文件夹路径
* @param forceDownload {@code true}强制下载,不考虑文件路径是否被占用
* @deprecated 使用 {@link #ignoreFilePathOccupy()}
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public HttpBuilderTarget setFilePath(@NonNull String filePath, boolean forceDownload) {
@Deprecated
public HttpBuilderTarget setFilePath(String filePath, boolean forceDownload) {
mConfigHandler.setTempFilePath(filePath);
mConfigHandler.setForceDownload(forceDownload);
return this;

View File

@@ -15,10 +15,10 @@
*/
package com.arialyy.aria.core.download.target;
import androidx.annotation.CheckResult;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
@@ -59,6 +59,7 @@ class HttpGroupConfigHandler<TARGET extends AbsTarget> extends AbsGroupConfigHan
List<DownloadEntity> subEntities = DbDataHelper.createHttpSubTask(groupHash, mUrls);
List<DTaskWrapper> wrappers = new ArrayList<>();
for (DownloadEntity subEntity : subEntities) {
subEntity.setTaskType(ITaskWrapper.D_HTTP);
wrappers.add(new DTaskWrapper(subEntity));
}
getEntity().setUrls(urls);
@@ -69,7 +70,6 @@ class HttpGroupConfigHandler<TARGET extends AbsTarget> extends AbsGroupConfigHan
/**
* 设置子任务文件名,该方法必须在{@link #setDirPath(String)}之后调用,否则不生效
*/
@CheckResult
TARGET setSubFileName(List<String> subTaskFileName) {
if (subTaskFileName == null || subTaskFileName.isEmpty()) {
ALog.w(TAG, "修改子任务的文件名失败列表为null");
@@ -90,7 +90,6 @@ class HttpGroupConfigHandler<TARGET extends AbsTarget> extends AbsGroupConfigHan
*
* @param urls 新的组合任务下载地址列表
*/
@CheckResult
TARGET updateUrls(List<String> urls) {
if (urls == null || urls.isEmpty()) {
throw new NullPointerException("下载地址列表为空");

View File

@@ -15,14 +15,12 @@
*/
package com.arialyy.aria.core.download.target;
import androidx.annotation.CheckResult;
import com.arialyy.aria.core.common.AbsNormalTarget;
import com.arialyy.aria.core.common.HttpOption;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.m3u8.M3U8LiveOption;
import com.arialyy.aria.core.download.m3u8.M3U8VodOption;
import com.arialyy.aria.core.inf.Suggest;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
/**
@@ -35,9 +33,9 @@ public class HttpNormalTarget extends AbsNormalTarget<HttpNormalTarget> {
HttpNormalTarget(long taskId) {
mConfigHandler = new DNormalConfigHandler<>(this, taskId);
getTaskWrapper().setRequestType(getTaskWrapper().getEntity().getTaskType());
getTaskWrapper().setNewTask(false);
}
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public M3U8NormalTarget m3u8VodOption(M3U8VodOption m3U8VodOption) {
if (m3U8VodOption == null) {
throw new NullPointerException("m3u8任务设置为空");
@@ -48,12 +46,10 @@ public class HttpNormalTarget extends AbsNormalTarget<HttpNormalTarget> {
return new M3U8NormalTarget((DTaskWrapper) getTaskWrapper());
}
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public M3U8NormalTarget m3u8VodOption() {
return new M3U8NormalTarget((DTaskWrapper) getTaskWrapper());
}
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public HttpNormalTarget m3u8LiveOption(M3U8LiveOption m3U8LiveOption) {
if (m3U8LiveOption == null) {
throw new NullPointerException("m3u8任务设置为空");
@@ -66,7 +62,6 @@ public class HttpNormalTarget extends AbsNormalTarget<HttpNormalTarget> {
/**
* 设置http请求参数header等信息
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public HttpNormalTarget option(HttpOption option) {
if (option == null) {
throw new NullPointerException("任务配置为空");
@@ -80,7 +75,6 @@ public class HttpNormalTarget extends AbsNormalTarget<HttpNormalTarget> {
* 如:原文件路径 /mnt/sdcard/test.zip
* 如果需要将test.zip改为game.zip只需要重新设置文件路径为/mnt/sdcard/game.zip
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public HttpNormalTarget modifyFilePath(String filePath) {
mConfigHandler.setTempFilePath(filePath);
return this;
@@ -96,7 +90,6 @@ public class HttpNormalTarget extends AbsNormalTarget<HttpNormalTarget> {
/**
* 更新下载地址
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public HttpNormalTarget updateUrl(String newUrl) {
return mConfigHandler.updateUrl(newUrl);
}

View File

@@ -27,6 +27,7 @@ public class M3U8NormalTarget extends AbsNormalTarget<M3U8NormalTarget> {
M3U8NormalTarget(DTaskWrapper wrapper) {
setTaskWrapper(wrapper);
getTaskWrapper().setNewTask(false);
}
/**

View File

@@ -15,11 +15,8 @@
*/
package com.arialyy.aria.core.download.target;
import androidx.annotation.CheckResult;
import androidx.annotation.NonNull;
import com.arialyy.aria.core.common.AbsBuilderTarget;
import com.arialyy.aria.core.inf.Suggest;
import com.arialyy.aria.core.download.tcp.TcpDelegate;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
/**
@@ -33,6 +30,8 @@ public class TcpBuilderTarget extends AbsBuilderTarget<TcpBuilderTarget> {
TcpBuilderTarget(String ip, int port) {
mConfigHandler = new DNormalConfigHandler<>(this, -1);
getTaskWrapper().setRequestType(ITaskWrapper.D_TCP);
((DownloadEntity) getEntity()).setTaskType(ITaskWrapper.D_TCP);
getTaskWrapper().setNewTask(true);
}
//
///**
@@ -50,24 +49,8 @@ public class TcpBuilderTarget extends AbsBuilderTarget<TcpBuilderTarget> {
*
* @param filePath 路径必须为文件路径,不能为文件夹路径
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public TcpBuilderTarget setFilePath(@NonNull String filePath) {
public TcpBuilderTarget setFilePath(String filePath) {
mConfigHandler.setTempFilePath(filePath);
return this;
}
/**
* 设置文件存储路径,如果需要修改新的文件名,修改路径便可。
* 如:原文件路径 /mnt/sdcard/test.zip
* 如果需要将test.zip改为game.zip只需要重新设置文件路径为/mnt/sdcard/game.zip
*
* @param filePath 路径必须为文件路径,不能为文件夹路径
* @param forceDownload {@code true}强制下载,不考虑文件路径是否被占用
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public TcpBuilderTarget setFilePath(@NonNull String filePath, boolean forceDownload) {
mConfigHandler.setTempFilePath(filePath);
mConfigHandler.setForceDownload(forceDownload);
return this;
}
}

View File

@@ -16,11 +16,10 @@
package com.arialyy.aria.core.inf;
import android.text.TextUtils;
import androidx.annotation.CheckResult;
import com.arialyy.aria.core.common.AbsEntity;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.common.controller.BuilderController;
import com.arialyy.aria.core.common.controller.NormalController;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
@@ -61,7 +60,6 @@ public abstract class AbsTarget<TARGET extends AbsTarget> {
*
* @param str 扩展数据
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public TARGET setExtendField(String str) {
if (TextUtils.isEmpty(str)) return (TARGET) this;
if (TextUtils.isEmpty(mEntity.getStr()) || !mEntity.getStr().equals(str)) {
@@ -80,7 +78,6 @@ public abstract class AbsTarget<TARGET extends AbsTarget> {
* BuilderController#add()}
* 等操作任务的方法,那么你需要调用{@link NormalController#save()}才能将修改保存到数据库
*/
@CheckResult(suggest = "after use #create()、#stop()、#cancel()、#resume()、#save()?")
public TARGET resetState() {
getTaskWrapper().getEntity().setState(IEntity.STATE_WAIT);
getTaskWrapper().setRefreshInfo(true);

View File

@@ -49,5 +49,5 @@ public interface IReceiver {
*
* @return {@link ReceiverType}
*/
@ReceiverType String getType();
String getType();
}

View File

@@ -15,19 +15,10 @@
*/
package com.arialyy.aria.core.inf;
import androidx.annotation.StringDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* {@link AbsReceiver}类型
*/
@StringDef({
ReceiverType.DOWNLOAD,
ReceiverType.UPLOAD,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ReceiverType {
public interface ReceiverType {
String DOWNLOAD = "download";
String UPLOAD = "upload";
}

View File

@@ -42,14 +42,17 @@ class DGTaskWrapperFactory implements IGroupWrapperFactory<DownloadGroupEntity,
}
@Override public DGTaskWrapper getGroupWrapper(long taskId) {
DGTaskWrapper wrapper;
if (taskId == -1) {
return new DGTaskWrapper(new DownloadGroupEntity());
}
DownloadGroupEntity entity = getOrCreateHttpDGEntity(taskId);
DGTaskWrapper wrapper = new DGTaskWrapper(entity);
if (entity.getSubEntities() != null && !entity.getSubEntities().isEmpty()) {
wrapper.setSubTaskWrapper(DbDataHelper.createDGSubTaskWrapper(entity));
wrapper = new DGTaskWrapper(new DownloadGroupEntity());
}else {
DownloadGroupEntity entity = getOrCreateHttpDGEntity(taskId);
wrapper = new DGTaskWrapper(entity);
if (entity.getSubEntities() != null && !entity.getSubEntities().isEmpty()) {
wrapper.setSubTaskWrapper(DbDataHelper.createDGSubTaskWrapper(entity));
}
}
wrapper.setRequestType(wrapper.getEntity().getTaskType());
return wrapper;
}

View File

@@ -20,6 +20,7 @@ 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.inf.IRecordHandler;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import java.io.File;
/**
@@ -45,11 +46,14 @@ class DTaskWrapperFactory implements INormalTEFactory<DownloadEntity, DTaskWrapp
* 通过下载地址创建任务实体
*/
@Override public DTaskWrapper create(long taskId) {
DTaskWrapper wrapper;
if (taskId == -1) {
return new DTaskWrapper(new DownloadEntity());
wrapper = new DTaskWrapper(new DownloadEntity());
} else {
wrapper = new DTaskWrapper(getEntity(taskId));
}
return new DTaskWrapper(getEntity(taskId));
wrapper.setRequestType(wrapper.getEntity().getTaskType());
return wrapper;
}
/**
@@ -68,7 +72,7 @@ class DTaskWrapperFactory implements INormalTEFactory<DownloadEntity, DTaskWrapp
if (!entity.isComplete()) {
TaskRecord record =
TaskRecord.findFirst(TaskRecord.class, "filePath=?", entity.getDownloadPath());
TaskRecord.findFirst(TaskRecord.class, "filePath=?", entity.getFilePath());
if (record == null) {
resetEntity(entity);
} else {
@@ -84,7 +88,7 @@ class DTaskWrapperFactory implements INormalTEFactory<DownloadEntity, DTaskWrapp
resetEntity(entity);
}
} else if (!file.exists()
&& record.taskType != TaskRecord.TYPE_M3U8_VOD) { // 非分块文件需要判断文件是否存在
&& record.taskType != ITaskWrapper.M3U8_VOD) { // 非分块文件需要判断文件是否存在
resetEntity(entity);
}
}

View File

@@ -15,11 +15,11 @@
*/
package com.arialyy.aria.core.manager;
import androidx.collection.LruCache;
import android.util.LruCache;
import com.arialyy.aria.core.download.DGTaskWrapper;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.upload.UTaskWrapper;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.util.concurrent.locks.Lock;

View File

@@ -17,6 +17,7 @@ package com.arialyy.aria.core.manager;
import com.arialyy.aria.core.upload.UTaskWrapper;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.util.ALog;
/**
* Created by Aria.Lao on 2017/11/1. 任务实体工厂
@@ -38,10 +39,15 @@ class UTaskWrapperFactory implements INormalTEFactory<UploadEntity, UTaskWrapper
}
@Override public UTaskWrapper create(long taskId) {
UTaskWrapper wrapper;
if (taskId == -1) {
return new UTaskWrapper(new UploadEntity());
wrapper = new UTaskWrapper(new UploadEntity());
} else {
wrapper = new UTaskWrapper(getUploadEntity(taskId));
}
return new UTaskWrapper(getUploadEntity(taskId));
wrapper.setRequestType(wrapper.getEntity().getTaskType());
return wrapper;
}
/**

View File

@@ -16,10 +16,6 @@
package com.arialyy.aria.core.queue;
import com.arialyy.aria.core.task.DownloadGroupTask;
import com.arialyy.aria.core.task.DownloadTask;
import com.arialyy.aria.core.task.AbsTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.TaskSchedulerType;
import com.arialyy.aria.core.manager.TaskWrapperManager;
@@ -29,7 +25,11 @@ import com.arialyy.aria.core.queue.pool.BaseExecutePool;
import com.arialyy.aria.core.queue.pool.DGLoadSharePool;
import com.arialyy.aria.core.queue.pool.DLoadSharePool;
import com.arialyy.aria.core.queue.pool.UploadSharePool;
import com.arialyy.aria.core.task.AbsTask;
import com.arialyy.aria.core.task.DownloadGroupTask;
import com.arialyy.aria.core.task.DownloadTask;
import com.arialyy.aria.core.task.UploadTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.util.ALog;
/**
@@ -95,8 +95,7 @@ public abstract class AbsTaskQueue<TASK extends AbsTask, TASK_WRAPPER extends Ab
* 停止所有任务
*/
@Override public void stopAllTask() {
for (String key : mExecutePool.getAllTask().keySet()) {
TASK task = mExecutePool.getAllTask().get(key);
for (TASK task : mExecutePool.getAllTask()) {
if (task != null) {
int state = task.getState();
if (task.isRunning() || (state != IEntity.STATE_COMPLETE
@@ -106,8 +105,13 @@ public abstract class AbsTaskQueue<TASK extends AbsTask, TASK_WRAPPER extends Ab
}
}
for (String key : mCachePool.getAllTask().keySet()) {
TASK task = mCachePool.getAllTask().get(key);
//for (String key : mCachePool.getAllTask().keySet()) {
// TASK task = mCachePool.getAllTask().get(key);
// if (task != null) {
// task.stop(TaskSchedulerType.TYPE_STOP_NOT_NEXT);
// }
//}
for (TASK task : mCachePool.getAllTask()) {
if (task != null) {
task.stop(TaskSchedulerType.TYPE_STOP_NOT_NEXT);
}
@@ -213,6 +217,10 @@ public abstract class AbsTaskQueue<TASK extends AbsTask, TASK_WRAPPER extends Ab
}
@Override public void startTask(TASK task) {
startTask(task, TaskSchedulerType.TYPE_DEFAULT);
}
@Override public void startTask(TASK task, int action) {
if (task == null) {
ALog.w(TAG, "create fail, task is null");
}
@@ -223,7 +231,7 @@ public abstract class AbsTaskQueue<TASK extends AbsTask, TASK_WRAPPER extends Ab
mCachePool.removeTask(task);
mExecutePool.putTask(task);
task.getTaskWrapper().getEntity().setFailNum(0);
task.start();
task.start(action);
}
@Override public void stopTask(TASK task) {
@@ -312,7 +320,11 @@ public abstract class AbsTaskQueue<TASK extends AbsTask, TASK_WRAPPER extends Ab
}
@Override public void cancelTask(TASK task) {
task.cancel();
cancelTask(task, TaskSchedulerType.TYPE_DEFAULT);
}
@Override public void cancelTask(TASK task, int action) {
task.cancel(action);
}
@Override public TASK getNextTask() {

View File

@@ -16,13 +16,13 @@
package com.arialyy.aria.core.queue;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.download.DGTaskWrapper;
import com.arialyy.aria.core.task.DownloadGroupTask;
import com.arialyy.aria.core.event.DGMaxNumEvent;
import com.arialyy.aria.core.event.Event;
import com.arialyy.aria.core.event.EventMsgUtil;
import com.arialyy.aria.core.scheduler.TaskSchedulers;
import com.arialyy.aria.core.task.DownloadGroupTask;
import com.arialyy.aria.util.ALog;
/**
@@ -57,7 +57,7 @@ public class DGroupTaskQueue
}
@Override public int getMaxTaskNum() {
return AriaManager.getInstance().getDGroupConfig().getMaxTaskNum();
return AriaConfig.getInstance().getDConfig().getMaxTaskNum();
}
@Override public DownloadGroupTask createTask(DGTaskWrapper wrapper) {
@@ -74,6 +74,6 @@ public class DGroupTaskQueue
}
@Override public int getOldMaxNum() {
return AriaManager.getInstance().getDGroupConfig().oldMaxTaskNum;
return AriaConfig.getInstance().getDGConfig().oldMaxTaskNum;
}
}

View File

@@ -16,17 +16,17 @@
package com.arialyy.aria.core.queue;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.task.DownloadTask;
import com.arialyy.aria.core.event.DMaxNumEvent;
import com.arialyy.aria.core.event.Event;
import com.arialyy.aria.core.event.EventMsgUtil;
import com.arialyy.aria.core.inf.TaskSchedulerType;
import com.arialyy.aria.core.scheduler.TaskSchedulers;
import com.arialyy.aria.core.task.DownloadTask;
import com.arialyy.aria.util.ALog;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.List;
import java.util.Set;
/**
@@ -60,7 +60,7 @@ public class DTaskQueue extends AbsTaskQueue<DownloadTask, DTaskWrapper> {
}
@Override public int getOldMaxNum() {
return AriaManager.getInstance().getDownloadConfig().oldMaxTaskNum;
return AriaConfig.getInstance().getDConfig().oldMaxTaskNum;
}
/**
@@ -68,11 +68,10 @@ public class DTaskQueue extends AbsTaskQueue<DownloadTask, DTaskWrapper> {
*/
public void setTaskHighestPriority(DownloadTask task) {
task.setHighestPriority(true);
Map<String, DownloadTask> exeTasks = mExecutePool.getAllTask();
//Map<String, DownloadTask> exeTasks = mExecutePool.getAllTask();
List<DownloadTask> exeTasks = mExecutePool.getAllTask();
if (exeTasks != null && !exeTasks.isEmpty()) {
Set<String> keys = exeTasks.keySet();
for (String key : keys) {
DownloadTask temp = exeTasks.get(key);
for (DownloadTask temp : exeTasks) {
if (temp != null && temp.isRunning() && temp.isHighestPriorityTask() && !temp.getKey()
.equals(task.getKey())) {
ALog.e(TAG, "设置最高优先级任务失败,失败原因【任务中已经有最高优先级任务,请等待上一个最高优先级任务完成,或手动暂停该任务】");
@@ -80,28 +79,28 @@ public class DTaskQueue extends AbsTaskQueue<DownloadTask, DTaskWrapper> {
return;
}
}
}
int maxSize = AriaManager.getInstance().getDownloadConfig().getMaxTaskNum();
int currentSize = mExecutePool.size();
if (currentSize == 0 || currentSize < maxSize) {
startTask(task);
} else {
Set<DownloadTask> tempTasks = new LinkedHashSet<>();
for (int i = 0; i < maxSize; i++) {
DownloadTask oldTsk = mExecutePool.pollTask();
if (oldTsk != null && oldTsk.isRunning()) {
if (i == maxSize - 1) {
oldTsk.stop(TaskSchedulerType.TYPE_STOP_AND_WAIT);
mCachePool.putTaskToFirst(oldTsk);
break;
int maxSize = AriaConfig.getInstance().getDConfig().getMaxTaskNum();
int currentSize = mExecutePool.size();
if (currentSize == 0 || currentSize < maxSize) {
startTask(task);
} else {
Set<DownloadTask> tempTasks = new LinkedHashSet<>();
for (int i = 0; i < maxSize; i++) {
DownloadTask oldTsk = mExecutePool.pollTask();
if (oldTsk != null && oldTsk.isRunning()) {
if (i == maxSize - 1) {
oldTsk.stop(TaskSchedulerType.TYPE_STOP_AND_WAIT);
mCachePool.putTaskToFirst(oldTsk);
break;
}
tempTasks.add(oldTsk);
}
tempTasks.add(oldTsk);
}
}
startTask(task);
startTask(task);
for (DownloadTask temp : tempTasks) {
mExecutePool.putTask(temp);
for (DownloadTask temp : tempTasks) {
mExecutePool.putTask(temp);
}
}
}
}
@@ -126,6 +125,6 @@ public class DTaskQueue extends AbsTaskQueue<DownloadTask, DTaskWrapper> {
}
@Override public int getMaxTaskNum() {
return AriaManager.getInstance().getDownloadConfig().getMaxTaskNum();
return AriaConfig.getInstance().getDConfig().getMaxTaskNum();
}
}

View File

@@ -17,13 +17,14 @@
package com.arialyy.aria.core.queue;
import com.arialyy.aria.core.download.DGTaskWrapper;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.inf.TaskSchedulerType;
import com.arialyy.aria.core.task.DownloadGroupTask;
import com.arialyy.aria.core.task.DownloadTask;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.task.ITask;
import com.arialyy.aria.core.task.UploadTask;
import com.arialyy.aria.core.upload.UTaskWrapper;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
/**
* Created by lyy on 2016/8/16. 任务功能接口
@@ -65,6 +66,13 @@ public interface ITaskQueue<TASK extends ITask, TASK_WRAPPER extends AbsTaskWrap
*/
void startTask(TASK task);
/**
* 开始任务
*
* @param action {@link TaskSchedulerType}
*/
void startTask(TASK task, int action);
/**
* 停止任务
*
@@ -73,12 +81,19 @@ public interface ITaskQueue<TASK extends ITask, TASK_WRAPPER extends AbsTaskWrap
void stopTask(TASK task);
/**
* 取消下载任务
* 取消任务
*
* @param task {@link DownloadTask}、{@link UploadTask}、{@link DownloadGroupTask}
*/
void cancelTask(TASK task);
/**
* 取消任务
*
* @param action {@link TaskSchedulerType}
*/
void cancelTask(TASK task, int action);
/**
* 通过key从队列中删除任务
*

View File

@@ -16,6 +16,7 @@
package com.arialyy.aria.core.queue;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.event.Event;
import com.arialyy.aria.core.event.EventMsgUtil;
@@ -55,11 +56,11 @@ public class UTaskQueue extends AbsTaskQueue<UploadTask, UTaskWrapper> {
}
@Override public int getOldMaxNum() {
return AriaManager.getInstance().getUploadConfig().oldMaxTaskNum;
return AriaConfig.getInstance().getUConfig().oldMaxTaskNum;
}
@Override public int getMaxTaskNum() {
return AriaManager.getInstance().getUploadConfig().getMaxTaskNum();
return AriaConfig.getInstance().getUConfig().getMaxTaskNum();
}
@Override public UploadTask createTask(UTaskWrapper wrapper) {

View File

@@ -20,65 +20,43 @@ import android.text.TextUtils;
import com.arialyy.aria.core.task.AbsTask;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.concurrent.LinkedBlockingDeque;
/**
* Created by lyy on 2016/8/14. 任务缓存池,所有下载任务最先缓存在这个池中
*/
public class BaseCachePool<TASK extends AbsTask> implements IPool<TASK> {
private static final String TAG = "BaseCachePool";
private final String TAG = CommonUtil.getClassName(this);
private static final int MAX_NUM = Integer.MAX_VALUE; //最大下载任务数
private static final long TIME_OUT = 1000;
private static final Object LOCK = new Object();
private Map<String, TASK> mCacheMap;
private LinkedBlockingQueue<TASK> mCacheQueue;
private Deque<TASK> mCacheQueue;
BaseCachePool() {
mCacheQueue = new LinkedBlockingQueue<>(MAX_NUM);
mCacheMap = new ConcurrentHashMap<>();
mCacheQueue = new LinkedBlockingDeque<>(MAX_NUM);
}
/**
* 获取被缓存的任务
*/
public Map<String, TASK> getAllTask() {
return mCacheMap;
public List<TASK> getAllTask() {
return new ArrayList<>(mCacheQueue);
}
/**
* 清除所有缓存的任务
*/
public void clear() {
for (String key : mCacheMap.keySet()) {
TASK task = mCacheMap.get(key);
mCacheQueue.remove(task);
mCacheMap.remove(key);
}
mCacheQueue.clear();
}
/**
* 将任务放在队首
*/
public boolean putTaskToFirst(TASK task) {
if (mCacheQueue.isEmpty()) {
return putTask(task);
} else {
Set<TASK> temps = new LinkedHashSet<>();
temps.add(task);
for (int i = 0, len = size(); i < len; i++) {
TASK temp = pollTask();
temps.add(temp);
}
for (TASK t : temps) {
putTask(t);
}
return true;
}
return mCacheQueue.offerFirst(task);
}
@Override public boolean putTask(TASK task) {
@@ -87,16 +65,12 @@ public class BaseCachePool<TASK extends AbsTask> implements IPool<TASK> {
ALog.e(TAG, "任务不能为空!!");
return false;
}
String key = task.getKey();
if (mCacheQueue.contains(task)) {
ALog.w(TAG, "任务【" + task.getTaskName() + "】进入缓存队列失败,原因:已经在缓存队列中");
return false;
} else {
boolean s = mCacheQueue.offer(task);
ALog.d(TAG, "任务【" + task.getTaskName() + "】进入缓存队列" + (s ? "成功" : "失败"));
if (s) {
mCacheMap.put(CommonUtil.keyToHashKey(key), task);
}
return s;
}
}
@@ -104,19 +78,8 @@ public class BaseCachePool<TASK extends AbsTask> implements IPool<TASK> {
@Override public TASK pollTask() {
synchronized (LOCK) {
try {
TASK task;
task = mCacheQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
if (task != null) {
String url = task.getKey();
mCacheMap.remove(CommonUtil.keyToHashKey(url));
}
return task;
} catch (InterruptedException e) {
e.printStackTrace();
}
return mCacheQueue.pollFirst();
}
return null;
}
@Override public TASK getTask(String key) {
@@ -125,12 +88,17 @@ public class BaseCachePool<TASK extends AbsTask> implements IPool<TASK> {
ALog.e(TAG, "key 为null");
return null;
}
return mCacheMap.get(CommonUtil.keyToHashKey(key));
for (TASK task : mCacheQueue) {
if (task.getKey().equals(key)) {
return task;
}
}
}
return null;
}
@Override public boolean taskExits(String key) {
return mCacheMap.containsKey(CommonUtil.keyToHashKey(key));
return getTask(key) != null;
}
@Override public boolean removeTask(TASK task) {
@@ -139,8 +107,6 @@ public class BaseCachePool<TASK extends AbsTask> implements IPool<TASK> {
ALog.e(TAG, "任务不能为空");
return false;
} else {
String key = CommonUtil.keyToHashKey(task.getKey());
mCacheMap.remove(key);
return mCacheQueue.remove(task);
}
}
@@ -152,10 +118,7 @@ public class BaseCachePool<TASK extends AbsTask> implements IPool<TASK> {
ALog.e(TAG, "请传入有效的下载链接");
return false;
}
String temp = CommonUtil.keyToHashKey(key);
TASK task = mCacheMap.get(temp);
mCacheMap.remove(temp);
return mCacheQueue.remove(task);
return mCacheQueue.remove(getTask(key));
}
}

View File

@@ -21,26 +21,23 @@ import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.task.AbsTask;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.concurrent.LinkedBlockingDeque;
/**
* Created by lyy on 2016/8/15. 任务执行池所有当前下载任务都该任务池中默认下载大小为2
*/
public class BaseExecutePool<TASK extends AbsTask> implements IPool<TASK> {
private final String TAG = "BaseExecutePool";
private final String TAG = CommonUtil.getClassName(this);
private static final Object LOCK = new Object();
final long TIME_OUT = 1000;
ArrayBlockingQueue<TASK> mExecuteQueue;
Map<String, TASK> mExecuteMap;
Deque<TASK> mExecuteQueue;
int mSize;
BaseExecutePool() {
mSize = getMaxSize();
mExecuteQueue = new ArrayBlockingQueue<>(mSize);
mExecuteMap = new ConcurrentHashMap<>();
mExecuteQueue = new LinkedBlockingDeque<>(mSize);
}
/**
@@ -55,8 +52,8 @@ public class BaseExecutePool<TASK extends AbsTask> implements IPool<TASK> {
/**
* 获取所有正在执行的任务
*/
public Map<String, TASK> getAllTask() {
return mExecuteMap;
public List<TASK> getAllTask() {
return new ArrayList<>(mExecuteQueue);
}
@Override public boolean putTask(TASK task) {
@@ -88,17 +85,13 @@ public class BaseExecutePool<TASK extends AbsTask> implements IPool<TASK> {
*/
public void setMaxNum(int maxNum) {
synchronized (LOCK) {
try {
ArrayBlockingQueue<TASK> temp = new ArrayBlockingQueue<>(maxNum);
TASK task;
while ((task = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS)) != null) {
temp.offer(task);
}
mExecuteQueue = temp;
mSize = maxNum;
} catch (InterruptedException e) {
e.printStackTrace();
Deque<TASK> temp = new LinkedBlockingDeque<>(maxNum);
TASK task;
while ((task = mExecuteQueue.poll()) != null) {
temp.offer(task);
}
mExecuteQueue = temp;
mSize = maxNum;
}
}
@@ -109,12 +102,8 @@ public class BaseExecutePool<TASK extends AbsTask> implements IPool<TASK> {
*/
boolean putNewTask(TASK newTask) {
synchronized (LOCK) {
String url = newTask.getKey();
boolean s = mExecuteQueue.offer(newTask);
ALog.d(TAG, "任务【" + newTask.getTaskName() + "】进入执行队列" + (s ? "成功" : "失败"));
if (s) {
mExecuteMap.put(CommonUtil.keyToHashKey(url), newTask);
}
return s;
}
}
@@ -124,37 +113,19 @@ public class BaseExecutePool<TASK extends AbsTask> implements IPool<TASK> {
*/
boolean pollFirstTask() {
synchronized (LOCK) {
try {
TASK oldTask = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
if (oldTask == null) {
ALog.w(TAG, "移除任务失败原因任务为null");
return false;
}
oldTask.stop();
String key = CommonUtil.keyToHashKey(oldTask.getKey());
mExecuteMap.remove(key);
} catch (InterruptedException e) {
e.printStackTrace();
TASK oldTask = mExecuteQueue.pollFirst();
if (oldTask == null) {
ALog.w(TAG, "移除任务失败原因任务为null");
return false;
}
oldTask.stop();
return true;
}
}
@Override public TASK pollTask() {
synchronized (LOCK) {
try {
TASK task;
task = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
if (task != null) {
String url = task.getKey();
mExecuteMap.remove(CommonUtil.keyToHashKey(url));
}
return task;
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
return mExecuteQueue.poll();
}
}
@@ -164,12 +135,18 @@ public class BaseExecutePool<TASK extends AbsTask> implements IPool<TASK> {
ALog.e(TAG, "key为null");
return null;
}
return mExecuteMap.get(CommonUtil.keyToHashKey(key));
for (TASK task : mExecuteQueue) {
if (task.getKey().equals(key)) {
return task;
}
}
return null;
}
}
@Override public boolean taskExits(String key) {
return mExecuteMap.containsKey(CommonUtil.keyToHashKey(key));
return getTask(key) != null;
}
@Override public boolean removeTask(TASK task) {
@@ -189,16 +166,8 @@ public class BaseExecutePool<TASK extends AbsTask> implements IPool<TASK> {
ALog.e(TAG, "key 为null");
return false;
}
String convertKey = CommonUtil.keyToHashKey(key);
TASK task = mExecuteMap.get(convertKey);
final int oldQueueSize = mExecuteQueue.size();
boolean isSuccess = mExecuteQueue.remove(task);
final int newQueueSize = mExecuteQueue.size();
if (isSuccess && newQueueSize != oldQueueSize) {
mExecuteMap.remove(convertKey);
return true;
}
return false;
return mExecuteQueue.remove(getTask(key));
}
}

View File

@@ -15,17 +15,19 @@
*/
package com.arialyy.aria.core.queue.pool;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.task.AbsTask;
import com.arialyy.aria.util.CommonUtil;
/**
* Created by AriaL on 2017/6/29.
* 单个下载任务的执行池
*/
class DGLoadExecutePool<TASK extends AbsTask> extends DLoadExecutePool<TASK> {
private final String TAG = "DGLoadExecutePool";
private final String TAG = CommonUtil.getClassName(this);
@Override protected int getMaxSize() {
return AriaManager.getInstance().getDGroupConfig().getMaxTaskNum();
return AriaConfig.getInstance().getDGConfig().getMaxTaskNum();
}
}

View File

@@ -15,12 +15,9 @@
*/
package com.arialyy.aria.core.queue.pool;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.task.AbsTask;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* Created by AriaL on 2017/6/29.
@@ -30,7 +27,7 @@ class DLoadExecutePool<TASK extends AbsTask> extends BaseExecutePool<TASK> {
private final String TAG = "DownloadExecutePool";
@Override protected int getMaxSize() {
return AriaManager.getInstance().getDownloadConfig().getMaxTaskNum();
return AriaConfig.getInstance().getDConfig().getMaxTaskNum();
}
@Override public boolean putTask(TASK task) {
@@ -45,9 +42,10 @@ class DLoadExecutePool<TASK extends AbsTask> extends BaseExecutePool<TASK> {
return false;
} else {
if (mExecuteQueue.size() >= mSize) {
Set<String> keys = mExecuteMap.keySet();
for (String key : keys) {
if (mExecuteMap.get(key).isHighestPriorityTask()) return false;
for (TASK temp : mExecuteQueue) {
if (temp.isHighestPriorityTask()) {
return false;
}
}
if (pollFirstTask()) {
return putNewTask(task);
@@ -61,22 +59,15 @@ class DLoadExecutePool<TASK extends AbsTask> extends BaseExecutePool<TASK> {
}
@Override boolean pollFirstTask() {
try {
TASK oldTask = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
if (oldTask == null) {
ALog.w(TAG, "移除任务失败错误原因任务为null");
return false;
}
if (oldTask.isHighestPriorityTask()) {
return false;
}
oldTask.stop();
String key = CommonUtil.keyToHashKey(oldTask.getKey());
mExecuteMap.remove(key);
} catch (InterruptedException e) {
e.printStackTrace();
TASK oldTask = mExecuteQueue.pollFirst();
if (oldTask == null) {
ALog.w(TAG, "移除任务失败错误原因任务为null");
return false;
}
if (oldTask.isHighestPriorityTask()) {
return false;
}
oldTask.stop();
return true;
}
}

View File

@@ -15,7 +15,7 @@
*/
package com.arialyy.aria.core.queue.pool;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.task.AbsTask;
/**
@@ -23,6 +23,6 @@ import com.arialyy.aria.core.task.AbsTask;
*/
public class UploadExecutePool<TASK extends AbsTask> extends BaseExecutePool<TASK> {
@Override protected int getMaxSize() {
return AriaManager.getInstance().getUploadConfig().getMaxTaskNum();
return AriaConfig.getInstance().getUConfig().getMaxTaskNum();
}
}

View File

@@ -15,11 +15,11 @@
*/
package com.arialyy.aria.core.scheduler;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.common.AbsEntity;
import com.arialyy.aria.core.task.ITask;
import com.arialyy.aria.core.manager.TaskWrapperManager;
import com.arialyy.aria.core.queue.ITaskQueue;
import com.arialyy.aria.core.task.ITask;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.util.ArrayList;
@@ -42,7 +42,6 @@ class FailureTaskHandler<TASK extends ITask> {
private TaskSchedulers mSchedulers;
private final ReentrantLock LOCK = new ReentrantLock();
private Condition mCondition = LOCK.newCondition();
private AriaManager mAriaManager;
static FailureTaskHandler init(TaskSchedulers schedulers) {
if (INSTANCE == null) {
@@ -57,7 +56,6 @@ class FailureTaskHandler<TASK extends ITask> {
private FailureTaskHandler(TaskSchedulers schedulers) {
mSchedulers = schedulers;
mAriaManager = AriaManager.getInstance();
new Thread(new Runnable() {
@Override public void run() {
while (true) {
@@ -82,35 +80,46 @@ class FailureTaskHandler<TASK extends ITask> {
}
private void retryTask(final TASK task) {
long interval = task.getTaskWrapper().getConfig().getReTryInterval();
final int num = task.getTaskWrapper().getConfig().getReTryNum();
final ITaskQueue queue = mSchedulers.getQueue(task.getTaskType());
mAriaManager.getAriaHandler().postDelayed(new Runnable() {
@Override public void run() {
AbsEntity entity = task.getTaskWrapper().getEntity();
if (entity.getFailNum() <= num) {
ALog.d(TAG, String.format("任务【%s】开始重试", task.getTaskName()));
queue.reTryStart(task);
} else {
queue.removeTaskFormQueue(task.getKey());
mSchedulers.startNextTask(queue, task.getSchedulerType());
TaskWrapperManager.getInstance().removeTaskWrapper(task.getTaskWrapper());
}
mExeQueue.remove(task);
int index = mHashList.indexOf(task.hashCode());
if (index != -1) {
mHashList.remove(index);
}
if (LOCK.isLocked()) {
try {
LOCK.lock();
mCondition.signalAll();
} finally {
LOCK.unlock();
if (task.isNeedRetry()){
long interval = task.getTaskWrapper().getConfig().getReTryInterval();
final int num = task.getTaskWrapper().getConfig().getReTryNum();
AriaConfig.getInstance().getAriaHandler().postDelayed(new Runnable() {
@Override public void run() {
AbsEntity entity = task.getTaskWrapper().getEntity();
if (entity.getFailNum() <= num) {
ALog.d(TAG, String.format("任务【%s】开始重试", task.getTaskName()));
queue.reTryStart(task);
} else {
queue.removeTaskFormQueue(task.getKey());
mSchedulers.startNextTask(queue, task.getSchedulerType());
TaskWrapperManager.getInstance().removeTaskWrapper(task.getTaskWrapper());
}
next(task);
}
}, interval);
}else {
queue.removeTaskFormQueue(task.getKey());
mSchedulers.startNextTask(queue, task.getSchedulerType());
TaskWrapperManager.getInstance().removeTaskWrapper(task.getTaskWrapper());
next(task);
}
}
private void next(TASK task){
mExeQueue.remove(task);
int index = mHashList.indexOf(task.hashCode());
if (index != -1) {
mHashList.remove(index);
}
if (LOCK.isLocked()) {
try {
LOCK.lock();
mCondition.signalAll();
} finally {
LOCK.unlock();
}
}, interval);
}
}
void offer(TASK task) {

View File

@@ -19,7 +19,7 @@ import android.content.Intent;
import android.os.Bundle;
import android.os.Message;
import com.arialyy.annotations.TaskEnum;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.common.AbsEntity;
import com.arialyy.aria.core.common.AbsNormalEntity;
import com.arialyy.aria.core.group.GroupSendParams;
@@ -53,10 +53,10 @@ public class TaskSchedulers<TASK extends ITask> implements ISchedulers {
private static FailureTaskHandler mFailureTaskHandler;
private Map<String, Map<TaskEnum, ISchedulerListener>> mObservers = new ConcurrentHashMap<>();
private AriaManager mAriaManager;
private AriaConfig mAriaConfig;
private TaskSchedulers() {
mAriaManager = AriaManager.getInstance();
mAriaConfig = AriaConfig.getInstance();
}
public static TaskSchedulers getInstance() {
@@ -230,11 +230,11 @@ public class TaskSchedulers<TASK extends ITask> implements ISchedulers {
}
}
boolean canSend = mAriaManager.getAppConfig().isUseBroadcast();
boolean canSend = mAriaConfig.getAConfig().isUseBroadcast();
if (canSend) {
Intent intent = new Intent(ISchedulers.ARIA_TASK_INFO_ACTION);
intent.putExtras(data);
mAriaManager.getAPP().sendBroadcast(intent);
mAriaConfig.getAPP().sendBroadcast(intent);
}
return true;
@@ -284,9 +284,9 @@ public class TaskSchedulers<TASK extends ITask> implements ISchedulers {
}
}
boolean canSend = mAriaManager.getAppConfig().isUseBroadcast();
boolean canSend = mAriaConfig.getAConfig().isUseBroadcast();
if (canSend) {
mAriaManager.getAPP().sendBroadcast(
mAriaConfig.getAPP().sendBroadcast(
createData(msg.what, ITask.DOWNLOAD_GROUP_SUB, params.entity));
}
@@ -353,13 +353,13 @@ public class TaskSchedulers<TASK extends ITask> implements ISchedulers {
startNextTask(getQueue(taskType), TaskSchedulerType.TYPE_DEFAULT);
// 发送广播
boolean canSend = mAriaManager.getAppConfig().isUseBroadcast();
boolean canSend = mAriaConfig.getAConfig().isUseBroadcast();
if (canSend) {
Intent intent = new Intent(ISchedulers.ARIA_TASK_INFO_ACTION);
Bundle b = new Bundle();
b.putInt(ISchedulers.TASK_TYPE, taskType);
b.putInt(ISchedulers.TASK_STATE, ISchedulers.FAIL);
mAriaManager.getAPP().sendBroadcast(intent);
mAriaConfig.getAPP().sendBroadcast(intent);
}
// 处理回调
@@ -470,16 +470,16 @@ public class TaskSchedulers<TASK extends ITask> implements ISchedulers {
* 发送普通任务的广播
*/
private void sendNormalBroadcast(int state, TASK task) {
boolean canSend = mAriaManager.getAppConfig().isUseBroadcast();
boolean canSend = mAriaConfig.getAConfig().isUseBroadcast();
if (!canSend) {
return;
}
int type = task.getTaskType();
if (type == ITask.DOWNLOAD || type == ITask.DOWNLOAD_GROUP) {
mAriaManager.getAPP().sendBroadcast(
mAriaConfig.getAPP().sendBroadcast(
createData(state, type, task.getTaskWrapper().getEntity()));
} else if (type == ITask.UPLOAD) {
mAriaManager.getAPP().sendBroadcast(
mAriaConfig.getAPP().sendBroadcast(
createData(state, type, task.getTaskWrapper().getEntity()));
} else {
ALog.w(TAG, "发送广播失败,没有对应的任务");
@@ -519,9 +519,9 @@ public class TaskSchedulers<TASK extends ITask> implements ISchedulers {
}
int num = task.getTaskWrapper().getConfig().getReTryNum();
boolean isNotNetRetry = mAriaManager.getAppConfig().isNotNetRetry();
boolean isNotNetRetry = mAriaConfig.getAConfig().isNotNetRetry();
if ((!NetUtils.isConnected(mAriaManager.getAPP()) && !isNotNetRetry)
if ((!NetUtils.isConnected(mAriaConfig.getAPP()) && !isNotNetRetry)
|| task.getTaskWrapper().getEntity().getFailNum() > num) {
queue.removeTaskFormQueue(task.getKey());
startNextTask(queue, task.getSchedulerType());

View File

@@ -16,7 +16,6 @@
package com.arialyy.aria.core.upload;
import android.text.TextUtils;
import com.arialyy.aria.core.common.ErrorCode;
import com.arialyy.aria.core.inf.ICheckEntityUtil;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
@@ -26,12 +25,14 @@ public class CheckUEntityUtil implements ICheckEntityUtil {
private final String TAG = "CheckUEntityUtil";
private UTaskWrapper mWrapper;
private UploadEntity mEntity;
private int action;
public static CheckUEntityUtil newInstance(UTaskWrapper wrapper) {
return new CheckUEntityUtil(wrapper);
public static CheckUEntityUtil newInstance(UTaskWrapper wrapper, int action) {
return new CheckUEntityUtil(wrapper, action);
}
private CheckUEntityUtil(UTaskWrapper wrapper) {
private CheckUEntityUtil(UTaskWrapper wrapper, int action) {
this.action = action;
mWrapper = wrapper;
mEntity = mWrapper.getEntity();
}
@@ -59,6 +60,11 @@ public class CheckUEntityUtil implements ICheckEntityUtil {
ALog.e(TAG, "上传失败,文件路径【" + filePath + "】不合法");
return false;
}
// 任务是新任务,并且路径冲突就不会继续执行
if (mWrapper.isNewTask() && !CheckUtil.checkUPathConflicts(
mWrapper.isIgnoreFilePathOccupy(), filePath)) {
return false;
}
File file = new File(mEntity.getFilePath());
if (!file.exists()) {
@@ -69,6 +75,7 @@ public class CheckUEntityUtil implements ICheckEntityUtil {
ALog.e(TAG, "上传失败,文件【" + filePath + "】不能是文件夹");
return false;
}
return true;
}

View File

@@ -16,9 +16,8 @@
package com.arialyy.aria.core.upload;
import android.text.TextUtils;
import androidx.annotation.CheckResult;
import androidx.annotation.NonNull;
import com.arialyy.annotations.TaskEnum;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.CancelAllCmd;
import com.arialyy.aria.core.command.CmdHelper;
@@ -58,7 +57,7 @@ public class UploadReceiver extends AbsReceiver {
*/
@Deprecated
public UploadReceiver setMaxSpeed(int maxSpeed) {
AriaManager.getInstance().getUploadConfig().setMaxSpeed(maxSpeed);
AriaConfig.getInstance().getUConfig().setMaxSpeed(maxSpeed);
return this;
}
@@ -67,8 +66,8 @@ public class UploadReceiver extends AbsReceiver {
*
* @param filePath 文件路径
*/
@CheckResult
public HttpBuilderTarget load(@NonNull String filePath) {
public HttpBuilderTarget load(String filePath) {
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_HTTP);
CheckUtil.checkUploadPathIsEmpty(filePath);
return UTargetFactory.getInstance()
@@ -81,7 +80,7 @@ public class UploadReceiver extends AbsReceiver {
* @param taskId 任务id可从{@link AbsBuilderTarget#create()}、{@link AbsBuilderTarget#add()}、{@link
* AbsEntity#getId()}读取任务id
*/
@CheckResult
public HttpNormalTarget load(long taskId) {
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_HTTP);
return UTargetFactory.getInstance()
@@ -93,8 +92,8 @@ public class UploadReceiver extends AbsReceiver {
*
* @param filePath 文件路径
*/
@CheckResult
public FtpBuilderTarget loadFtp(@NonNull String filePath) {
public FtpBuilderTarget loadFtp(String filePath) {
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_FTP);
CheckUtil.checkUploadPathIsEmpty(filePath);
return UTargetFactory.getInstance()
@@ -107,7 +106,7 @@ public class UploadReceiver extends AbsReceiver {
* @param taskId 任务id可从{@link AbsBuilderTarget#create()}、{@link AbsBuilderTarget#add()}、{@link
* AbsEntity#getId()}读取任务id
*/
@CheckResult
public FtpNormalTarget loadFtp(long taskId) {
ComponentUtil.getInstance().checkComponentExist(ComponentUtil.COMPONENT_TYPE_FTP);
return UTargetFactory.getInstance()

View File

@@ -15,11 +15,10 @@
*/
package com.arialyy.aria.core.upload.target;
import androidx.annotation.CheckResult;
import com.arialyy.aria.core.common.AbsBuilderTarget;
import com.arialyy.aria.core.common.FtpOption;
import com.arialyy.aria.core.inf.Suggest;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.util.CommonUtil;
/**
@@ -33,7 +32,9 @@ public class FtpBuilderTarget extends AbsBuilderTarget<FtpBuilderTarget> {
FtpBuilderTarget(String filePath) {
mConfigHandler = new UNormalConfigHandler<>(this, -1);
mConfigHandler.setFilePath(filePath);
getTaskWrapper().setRequestType(AbsTaskWrapper.U_FTP);
getTaskWrapper().setRequestType(ITaskWrapper.U_FTP);
((UploadEntity)getEntity()).setTaskType(ITaskWrapper.U_FTP);
getTaskWrapper().setNewTask(true);
}
/**
@@ -41,17 +42,26 @@ public class FtpBuilderTarget extends AbsBuilderTarget<FtpBuilderTarget> {
*
* @param tempUrl 上传路径
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public FtpBuilderTarget setUploadUrl(String tempUrl) {
url = tempUrl;
mConfigHandler.setTempUrl(tempUrl);
return this;
}
/**
* 如果文件路径被其它任务占用,删除其它任务
*
* @deprecated 使用 {@link #ignoreFilePathOccupy()}
*/
@Deprecated
public FtpBuilderTarget forceUpload() {
getTaskWrapper().setIgnoreFilePathOccupy(true);
return this;
}
/**
* 设置登陆、字符串编码、ftps等参数
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public FtpBuilderTarget option(FtpOption option) {
if (option == null) {
throw new NullPointerException("ftp 任务配置为空");

View File

@@ -15,12 +15,10 @@
*/
package com.arialyy.aria.core.upload.target;
import androidx.annotation.CheckResult;
import com.arialyy.aria.core.common.AbsNormalTarget;
import com.arialyy.aria.core.common.FtpOption;
import com.arialyy.aria.core.inf.Suggest;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.util.CommonUtil;
/**
@@ -32,13 +30,13 @@ public class FtpNormalTarget extends AbsNormalTarget<FtpNormalTarget> {
FtpNormalTarget(long taskId) {
mConfigHandler = new UNormalConfigHandler<>(this, taskId);
getTaskWrapper().setRequestType(AbsTaskWrapper.U_FTP);
getTaskWrapper().setRequestType(ITaskWrapper.U_FTP);
getTaskWrapper().setNewTask(false);
}
/**
* 设置登陆、字符串编码、ftps等参数
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public FtpNormalTarget option(FtpOption option) {
if (option == null) {
throw new NullPointerException("ftp 任务配置为空");

View File

@@ -15,11 +15,10 @@
*/
package com.arialyy.aria.core.upload.target;
import androidx.annotation.CheckResult;
import com.arialyy.aria.core.common.AbsBuilderTarget;
import com.arialyy.aria.core.common.HttpOption;
import com.arialyy.aria.core.inf.Suggest;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
/**
* Created by lyy on 2017/2/28.
@@ -29,12 +28,13 @@ public class HttpBuilderTarget extends AbsBuilderTarget<HttpBuilderTarget> {
private UNormalConfigHandler<HttpBuilderTarget> mConfigHandler;
HttpBuilderTarget(String filePath) {
mConfigHandler = new UNormalConfigHandler<>(this, -1);
mConfigHandler.setFilePath(filePath);
//http暂时不支持断点上传
getTaskWrapper().setSupportBP(false);
getTaskWrapper().setRequestType(AbsTaskWrapper.U_HTTP);
getTaskWrapper().setRequestType(ITaskWrapper.U_HTTP);
((UploadEntity) getEntity()).setTaskType(ITaskWrapper.U_HTTP);
getTaskWrapper().setNewTask(true);
}
/**
@@ -42,7 +42,6 @@ public class HttpBuilderTarget extends AbsBuilderTarget<HttpBuilderTarget> {
*
* @param tempUrl 上传路径
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public HttpBuilderTarget setUploadUrl(String tempUrl) {
mConfigHandler.setTempUrl(tempUrl);
return this;
@@ -51,7 +50,6 @@ public class HttpBuilderTarget extends AbsBuilderTarget<HttpBuilderTarget> {
/**
* 设置http请求参数header等信息
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public HttpBuilderTarget option(HttpOption option) {
if (option == null) {
@@ -60,4 +58,15 @@ public class HttpBuilderTarget extends AbsBuilderTarget<HttpBuilderTarget> {
getTaskWrapper().getOptionParams().setParams(option);
return this;
}
/**
* 如果文件路径被其它任务占用,删除其它任务
*
* @deprecated 使用 {@link #ignoreFilePathOccupy()}
*/
@Deprecated
public HttpBuilderTarget forceUpload() {
getTaskWrapper().setIgnoreFilePathOccupy(true);
return this;
}
}

View File

@@ -15,10 +15,8 @@
*/
package com.arialyy.aria.core.upload.target;
import androidx.annotation.CheckResult;
import com.arialyy.aria.core.common.AbsNormalTarget;
import com.arialyy.aria.core.common.HttpOption;
import com.arialyy.aria.core.inf.Suggest;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.util.ALog;
@@ -33,6 +31,7 @@ public class HttpNormalTarget extends AbsNormalTarget<HttpNormalTarget> {
mConfigHandler = new UNormalConfigHandler<>(this, taskId);
getTaskWrapper().setSupportBP(false);
getTaskWrapper().setRequestType(AbsTaskWrapper.U_HTTP);
getTaskWrapper().setNewTask(false);
}
/**
@@ -40,7 +39,6 @@ public class HttpNormalTarget extends AbsNormalTarget<HttpNormalTarget> {
*
* @param tempUrl 上传路径
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public HttpNormalTarget setUploadUrl(String tempUrl) {
mConfigHandler.setTempUrl(tempUrl);
return this;
@@ -49,7 +47,6 @@ public class HttpNormalTarget extends AbsNormalTarget<HttpNormalTarget> {
/**
* 设置http请求参数header等信息
*/
@CheckResult(suggest = Suggest.TASK_CONTROLLER)
public HttpNormalTarget option(HttpOption option) {
if (option == null) {
throw new NullPointerException("任务配置为空");

View File

@@ -1,6 +1,60 @@
## 开发日志
+ v_3.7.4
+ v_3.8.1 (2019/12/22)
- 修复一个表创建失败的问题 https://github.com/AriaLyy/Aria/issues/570
- 修复一个非分块模式下导致下载失败的问题 https://github.com/AriaLyy/Aria/issues/571
- 修复一个服务器端无法创建socket连接却没有返回码导致客户端卡住的问题 https://github.com/AriaLyy/Aria/issues/569
- 修复文件删除后,组合任务没有重新下载的问题 https://github.com/AriaLyy/Aria/issues/574
- 优化缓存队列和执行队列
+ v_3.8 (2019/12/17)
- 移除androidx和support的依赖现在无论是哪个版本的appcompat包都可以使用本框架
- 修复一个在xml中使用fragment导致的内存泄漏问题
- m3u8协议的key信息增加了`keyFormat``keyFormatVersion`字段
- m3u8增加了`ignoreFailureTs`方法忽略下载失败的ts切片
- 修复在dialogFragment的`onCreateDialog()`注册导致的注解不生效问题
- 修复组合任务初始化失败时,无法删除的问题
- 修复`reStart()`后,无法停止的问题
- ftp增加主动模式开启主动模式https://aria.laoyuyu.me/aria_doc/api/ftp_params.html
- 修复ftp服务器无法响应`abor`命令导致的无法停止上传的问题 https://github.com/AriaLyy/Aria/issues/564
- 修复ftp上传时服务器有长度为0的文件导致上传失败的问题
- 修复下载任务和上传任务的文件路径是同一个时,导致的记录混乱问题
- 优化提示
+ v_3.7.10 (2019/12/3)
- fix bug https://github.com/AriaLyy/Aria/issues/543#issuecomment-559733124
- fix bug https://github.com/AriaLyy/Aria/issues/542
- fix bug https://github.com/AriaLyy/Azria/issues/547
- 修复下载失败时,中断重试无效的问题
- 增加忽略权限检查的api`ignoreCheckPermissions()`
- 增加通用的的忽略文件路径被占用的api`isIgnoreFilePathOccupy()`
+ v_3.7.9 (2019/11/28)
- fix bug https://github.com/AriaLyy/Aria/issues/537
+ v_3.7.8 (2019/11/28)
- fix bug https://github.com/AriaLyy/Aria/issues/526
- fix bug https://github.com/AriaLyy/Aria/issues/533
- fix bug https://github.com/AriaLyy/Aria/issues/535
- 修复ftp无法完成下载的问题
- 修复一个非分块模式下,调用`updateUrl(newUrl)`后无法恢复下载的问题
- 增加立即恢复任务的接口,正常来说,当执行队列满时,调用恢复任务接口,只能将任务放到缓存队列中。如果希望调用恢复接口,马上进入执行队列,需要调用`resume(true)`这个重载方法。
- 增加M3U8加密密钥的下载地址转换器 https://github.com/AriaLyy/Aria/issues/522
+ v_3.7.7 (2019/11/20)
- 修复ftp无法完成下载的问题
- 修复一个http下载崩溃的问题
+ v_3.7.6 (2019/11/19)
- fix bug https://github.com/AriaLyy/Aria/issues/505
- fix bug https://github.com/AriaLyy/Aria/issues/516
- fix bug https://github.com/AriaLyy/Aria/issues/515
- 增加强制上传的api`forceUpload()`
- 修复for循环上传文件出现的问题
- 移除创建任务的500ms间隔限制
- 修复多线程读写时可能出现的`database is locked`的问题
+ v_3.7.5 (2019/11/10)
- fix bug https://github.com/AriaLyy/Aria/issues/500
- fix bug https://github.com/AriaLyy/Aria/issues/508
- fix bug https://github.com/AriaLyy/Aria/issues/503
- 修复m3u8创建索引不成功的问题
+ v_3.7.4 (2019/11/2)
- 修复一个class被莫名改变的问题
- 修复非分块模式下导致的一个下载失败问题
- fix bug https://github.com/AriaLyy/Aria/issues/493
+ v_3.7.3 (2019/10/31)
- fix bug https://github.com/AriaLyy/Aria/issues/495
- fix bug https://github.com/AriaLyy/Aria/issues/496
@@ -15,7 +69,7 @@
- fix bug https://github.com/AriaLyy/Aria/issues/482
- fix bug https://github.com/AriaLyy/Aria/issues/473
- 移除隐藏api的反射 https://github.com/AriaLyy/Aria/issues/456
- 新增ftp免证书登陆功能h ttps://github.com/AriaLyy/Aria/issues/455
- 新增ftp免证书登陆功能 https://github.com/AriaLyy/Aria/issues/455
- 适配androidX
- 修复组合任务恢复下载会出现进度显示为0的问题
- m3u8点播下载新增创建ts索引功能

View File

@@ -25,9 +25,6 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "androidx.appcompat:appcompat:${rootProject.ext.XAppcompatVersion}"
// implementation project(path: ':AriaFtpPlug')
implementation project(path: ':PublicComponent')
}

View File

@@ -16,8 +16,13 @@
*/
package aria.apache.commons.net.ftp;
import aria.apache.commons.net.MalformedServerReplyException;
import aria.apache.commons.net.SocketClient;
import aria.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory;
import aria.apache.commons.net.ftp.parser.FTPFileEntryParserFactory;
import aria.apache.commons.net.ftp.parser.MLSxEntryParser;
import aria.apache.commons.net.ftp.parser.ParserInitializationException;
import aria.apache.commons.net.io.CRLFLineReader;
import aria.apache.commons.net.io.CopyStreamAdapter;
import aria.apache.commons.net.io.CopyStreamEvent;
import aria.apache.commons.net.io.CopyStreamException;
@@ -53,12 +58,6 @@ import java.util.Properties;
import java.util.Random;
import java.util.Set;
import aria.apache.commons.net.MalformedServerReplyException;
import aria.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory;
import aria.apache.commons.net.ftp.parser.FTPFileEntryParserFactory;
import aria.apache.commons.net.ftp.parser.MLSxEntryParser;
import aria.apache.commons.net.io.CRLFLineReader;
/**
* FTPClient encapsulates all the functionality necessary to store and
* retrieve files from an FTP server. This class takes care of all
@@ -2263,8 +2262,8 @@ public class FTPClient extends FTP implements Configurable {
}
/*
* Create the feature map if not already created.
*/
* Create the feature map if not already created.
*/
private boolean initFeatureMap() throws IOException {
if (__featuresMap == null) {
// Don't create map here, because next line may throw exception
@@ -2375,10 +2374,10 @@ public class FTPClient extends FTP implements Configurable {
boolean success = FTPReply.isPositiveCompletion(sendCommand(FTPCmd.MLST, pathname));
if (success) {
String reply = getReplyStrings()[1];
/* check the response makes sense.
* Must have space before fact(s) and between fact(s) and filename
* Fact(s) can be absent, so at least 3 chars are needed.
*/
/* check the response makes sense.
* Must have space before fact(s) and between fact(s) and filename
* Fact(s) can be absent, so at least 3 chars are needed.
*/
if (reply.length() < 3 || reply.charAt(0) != ' ') {
throw new MalformedServerReplyException("Invalid server reply (MLST): '" + reply + "'");
}
@@ -3663,7 +3662,6 @@ public class FTPClient extends FTP implements Configurable {
private long time = System.currentTimeMillis();
private int notAcked;
private OnFtpInputStreamListener listener;
private long lTime = time;
CSL(FTPClient parent, long idleTime, int maxWait) throws SocketException {
this(parent, idleTime, maxWait, null);
@@ -3697,12 +3695,9 @@ public class FTPClient extends FTP implements Configurable {
time = now;
}
//if (now - lTime > 100) {
if (listener != null) {
listener.onFtpInputStream(parent, totalBytesTransferred, bytesTransferred, streamSize);
}
//lTime = now;
//}
}
void cleanUp() throws IOException {

View File

@@ -27,24 +27,21 @@ import aria.apache.commons.net.ftp.FTPSClient;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.AbsEntity;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.common.FtpConnectionMode;
import com.arialyy.aria.core.inf.OnFileInfoCallback;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.exception.AriaIOException;
import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.exception.FileNotFoundException;
import com.arialyy.aria.exception.TaskException;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.Regular;
import com.arialyy.aria.util.SSLContextUtil;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.SSLContext;
/**
@@ -53,7 +50,7 @@ import javax.net.ssl.SSLContext;
public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER extends AbsTaskWrapper<ENTITY>>
implements Runnable {
private final String TAG = "AbsFtpInfoThread";
protected final String TAG = CommonUtil.getClassName(getClass());
protected ENTITY mEntity;
protected TASK_WRAPPER mTaskWrapper;
protected FtpTaskOption mTaskOption;
@@ -117,16 +114,16 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER ex
}
closeClient(client);
failDownload(new FileNotFoundException(TAG,
failDownload(client,
String.format("文件不存在url: %s, remotePath%s", mTaskOption.getUrlEntity().url,
remotePath)), false);
remotePath), null, false);
return;
}
// 处理拦截功能
if (!onInterceptor(client, files)) {
closeClient(client);
ALog.d(TAG, "拦截器处理完成任务,任务将不再执行");
ALog.d(TAG, "拦截器处理完成任务");
return;
}
@@ -139,9 +136,7 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER ex
mTaskWrapper.setNewTask(true);
} else {
closeClient(client);
failDownload(new AriaIOException(TAG,
String.format("获取文件信息错误url: %s, errorCode%s, errorMsg%s",
mTaskOption.getUrlEntity().url, reply, client.getReplyString())), true);
failDownload(client, "获取文件信息错误url: " + mTaskOption.getUrlEntity().url, null, true);
return;
}
}
@@ -152,9 +147,11 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER ex
onPreComplete(reply);
mEntity.update();
} catch (IOException e) {
failDownload(new AriaIOException(TAG,
String.format("FTP错误信息code%smsg%s", client.getReplyCode(), client.getReplyString()),
e), true);
e.printStackTrace();
failDownload(client, "FTP错误信息", e, true);
} catch (InterruptedException e) {
e.printStackTrace();
failDownload(client, "FTP错误信息", e, true);
} finally {
closeClient(client);
}
@@ -191,88 +188,83 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER ex
/**
* 创建FTP客户端
*/
private FTPClient createFtpClient() {
private FTPClient createFtpClient() throws IOException, InterruptedException {
FTPClient client = null;
final FtpUrlEntity urlEntity = mTaskOption.getUrlEntity();
try {
Pattern p = Pattern.compile(Regular.REG_IP_V4);
Matcher m = p.matcher(urlEntity.hostName);
if (m.find() && m.groupCount() > 0) {
client = newInstanceClient(urlEntity);
client.setConnectTimeout(mConnectTimeOut); // 连接10s超时
InetAddress ip = InetAddress.getByName(urlEntity.hostName);
if (CheckUtil.checkIp(urlEntity.hostName)) {
client = newInstanceClient(urlEntity);
client.setConnectTimeout(mConnectTimeOut); // 连接10s超时
InetAddress ip = InetAddress.getByName(urlEntity.hostName);
client = connect(client, new InetAddress[] { ip }, 0, Integer.parseInt(urlEntity.port));
mTaskOption.getUrlEntity().validAddr = ip;
} else {
DNSQueryThread dnsThread = new DNSQueryThread(urlEntity.hostName);
dnsThread.start();
dnsThread.join(mConnectTimeOut);
InetAddress[] ips = dnsThread.getIps();
client = connect(newInstanceClient(urlEntity), ips, 0, Integer.parseInt(urlEntity.port));
}
if (client == null) {
failDownload(new AriaIOException(TAG,
String.format("链接失败, url: %s", mTaskOption.getUrlEntity().url)), false);
return null;
}
boolean loginSuccess = true;
if (urlEntity.needLogin) {
try {
if (TextUtils.isEmpty(urlEntity.account)) {
loginSuccess = client.login(urlEntity.user, urlEntity.password);
} else {
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));
return null;
}
}
if (!loginSuccess) {
failDownload(
new TaskException(TAG, String.format("登录失败,错误码为:%s msg%s", client.getReplyCode(),
client.getReplyString())),
false);
client.disconnect();
return null;
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
failDownload(new AriaIOException(TAG,
String.format("无法连接到ftp服务器filePath: %s, url: %s, errorCode: %s, errorMsg%s",
mEntity.getKey(), mTaskOption.getUrlEntity().url, reply,
client.getReplyString())),
true);
return null;
}
// 开启服务器对UTF-8的支持如果服务器支持就用UTF-8编码
charSet = "UTF-8";
reply = client.sendCommand("OPTS UTF8", "ON");
if (reply != FTPReply.COMMAND_IS_SUPERFLUOUS) {
ALog.i(TAG, "D_FTP 服务器不支持开启UTF8编码尝试使用Aria手动设置的编码");
if (!TextUtils.isEmpty(mTaskOption.getCharSet())) {
charSet = mTaskOption.getCharSet();
}
}
client.setControlEncoding(charSet);
client.setDataTimeout(10 * 1000);
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
} catch (IOException e) {
closeClient(client);
e.printStackTrace();
} catch (InterruptedException e) {
closeClient(client);
e.printStackTrace();
client = connect(client, new InetAddress[] { ip }, 0, Integer.parseInt(urlEntity.port));
mTaskOption.getUrlEntity().validAddr = ip;
} else {
DNSQueryThread dnsThread = new DNSQueryThread(urlEntity.hostName);
dnsThread.start();
dnsThread.join(mConnectTimeOut);
InetAddress[] ips = dnsThread.getIps();
client = connect(newInstanceClient(urlEntity), ips, 0, Integer.parseInt(urlEntity.port));
}
if (client == null) {
failDownload(client, String.format("链接失败, url: %s", mTaskOption.getUrlEntity().url), null,
true);
return null;
}
boolean loginSuccess = true;
if (urlEntity.needLogin) {
try {
if (TextUtils.isEmpty(urlEntity.account)) {
loginSuccess = client.login(urlEntity.user, urlEntity.password);
} else {
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));
return null;
}
}
if (!loginSuccess) {
failDownload(client, "登录失败", null, false);
client.disconnect();
return null;
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
failDownload(client, String.format("无法连接到ftp服务器filePath: %s, url: %s", mEntity.getKey(),
mTaskOption.getUrlEntity().url), null, true);
client.disconnect();
return null;
}
// 开启服务器对UTF-8的支持如果服务器支持就用UTF-8编码
charSet = "UTF-8";
reply = client.sendCommand("OPTS UTF8", "ON");
if (reply != FTPReply.COMMAND_IS_SUPERFLUOUS) {
ALog.i(TAG, "D_FTP 服务器不支持开启UTF8编码尝试使用Aria手动设置的编码");
if (!TextUtils.isEmpty(mTaskOption.getCharSet())) {
charSet = mTaskOption.getCharSet();
}
}
client.setControlEncoding(charSet);
client.setDataTimeout(10 * 1000);
if (mTaskOption.getConnMode() == FtpConnectionMode.DATA_CONNECTION_MODE_ACTIVITY) {
client.enterLocalActiveMode();
if (mTaskOption.getMinPort() != 0 && mTaskOption.getMaxPort() != 0) {
client.setActivePortRange(mTaskOption.getMinPort(), mTaskOption.getMaxPort());
}
if (!TextUtils.isEmpty(mTaskOption.getActiveExternalIPAddress())) {
client.setActiveExternalIPAddress(mTaskOption.getActiveExternalIPAddress());
}
} else {
client.enterLocalPassiveMode();
}
client.setFileType(FTP.BINARY_FILE_TYPE);
return client;
}
@@ -387,9 +379,18 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER ex
protected void handleFile(String remotePath, FTPFile ftpFile) {
}
protected void failDownload(BaseException e, boolean needRetry) {
protected void failDownload(FTPClient client, String msg, Exception e, boolean needRetry) {
if (mCallback != null) {
mCallback.onFail(mEntity, e, needRetry);
if (client == null) {
msg = "创建ftp客户端失败";
needRetry = false;
} else {
msg = String.format("%s, code: %s, msg: %s", msg, client.getReplyCode(),
client.getReplyString());
needRetry = needRetry && !CheckUtil.ftpIsBadRequest(client.getReplyCode());
}
mCallback.onFail(mEntity, new AriaIOException(TAG, msg), needRetry);
}
}

View File

@@ -22,6 +22,7 @@ import aria.apache.commons.net.ftp.FTPClientConfig;
import aria.apache.commons.net.ftp.FTPReply;
import aria.apache.commons.net.ftp.FTPSClient;
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;
@@ -116,9 +117,20 @@ public abstract class BaseFtpThreadTaskAdapter extends AbsThreadTaskAdapter {
}
}
client.setControlEncoding(charSet);
client.setDataTimeout(getTaskConfig().getIOTimeOut());
//client.setDataTimeout(getTaskConfig().getIOTimeOut());
client.setDataTimeout(1000);
client.setConnectTimeout(getTaskConfig().getConnectTimeOut());
client.enterLocalPassiveMode();
if (mTaskOption.getConnMode() == FtpConnectionMode.DATA_CONNECTION_MODE_ACTIVITY) {
client.enterLocalActiveMode();
if (mTaskOption.getMinPort() != 0 && mTaskOption.getMaxPort() != 0) {
client.setActivePortRange(mTaskOption.getMinPort(), mTaskOption.getMaxPort());
}
if (!TextUtils.isEmpty(mTaskOption.getActiveExternalIPAddress())) {
client.setActiveExternalIPAddress(mTaskOption.getActiveExternalIPAddress());
}
} else {
client.enterLocalPassiveMode();
}
client.setFileType(FTP.BINARY_FILE_TYPE);
client.setControlKeepAliveTimeout(5000);
} catch (IOException e) {

View File

@@ -15,6 +15,7 @@
*/
package com.arialyy.aria.ftp;
import aria.apache.commons.net.ftp.FTPClient;
import aria.apache.commons.net.ftp.FTPFile;
import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.CompleteInfo;
@@ -24,7 +25,6 @@ import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.inf.OnFileInfoCallback;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.RecordUtil;
import java.nio.charset.Charset;
@@ -72,6 +72,9 @@ public class FtpDirInfoThread extends AbsFtpInfoThread<DownloadGroupEntity, DGTa
entity.setGroupChild(true);
entity.setConvertFileSize(CommonUtil.formatFileSize(ftpFile.getSize()));
entity.setFileSize(ftpFile.getSize());
//if(CheckUtil.checkDPathConflicts(mTaskWrapper.is))
entity.insert();
DTaskWrapper subWrapper = new DTaskWrapper(entity);
@@ -101,11 +104,11 @@ public class FtpDirInfoThread extends AbsFtpInfoThread<DownloadGroupEntity, DGTa
subOption.setUploadInterceptor(mTaskOption.getUploadInterceptor());
subWrapper.setTaskOption(subOption);
}
@Override protected void failDownload(BaseException e, boolean needRetry) {
super.failDownload(e, needRetry);
@Override
protected void failDownload(FTPClient client, String msg, Exception e, boolean needRetry) {
super.failDownload(client, msg, e, needRetry);
RecordUtil.delGroupTaskRecord(mTaskWrapper.getEntity(), true, true);
}
}

View File

@@ -21,9 +21,8 @@ import com.arialyy.aria.core.common.AbsRecordHandlerAdapter;
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.common.AbsNormalEntity;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.inf.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;
@@ -40,8 +39,12 @@ public class FtpRecordAdapter extends AbsRecordHandlerAdapter {
@Override public void handlerTaskRecord(TaskRecord record) {
RecordHelper helper = new RecordHelper(getWrapper(), record);
if (record.isBlock) {
helper.handleBlockRecord();
if (getWrapper().isSupportBP()) {
if (record.isBlock) {
helper.handleBlockRecord();
} else {
helper.handleMultiRecord();
}
} else if (record.threadNum == 1) {
helper.handleSingleThreadRecord();
}
@@ -55,7 +58,7 @@ public class FtpRecordAdapter extends AbsRecordHandlerAdapter {
tr.threadId = threadId;
tr.startLocation = startL;
tr.isComplete = false;
tr.threadType = TaskRecord.TYPE_HTTP_FTP;
tr.threadType = getWrapper().getEntity().getTaskType();
//最后一个线程的结束位置即为文件的总长度
if (threadId == (record.threadNum - 1)) {
endL = getEntity().getFileSize();
@@ -74,13 +77,11 @@ public class FtpRecordAdapter extends AbsRecordHandlerAdapter {
int requestType = getWrapper().getRequestType();
if (requestType == ITaskWrapper.D_FTP || requestType == ITaskWrapper.D_FTP_DIR) {
record.isBlock = threadNum > 1 && Configuration.getInstance().downloadCfg.isUseBlock();
// 线程数为1或者使用了分块则认为是使用动态长度文件
record.isOpenDynamicFile = threadNum == 1 || record.isBlock;
record.isBlock = Configuration.getInstance().downloadCfg.isUseBlock();
} else {
record.isBlock = false;
}
record.taskType = TaskRecord.TYPE_HTTP_FTP;
record.taskType = getWrapper().getEntity().getTaskType();
record.isGroupRecord = getEntity().isGroupChild();
if (record.isGroupRecord) {
if (getEntity() instanceof DownloadEntity) {
@@ -104,6 +105,4 @@ public class FtpRecordAdapter extends AbsRecordHandlerAdapter {
return 1;
}
}
}

View File

@@ -17,9 +17,10 @@ package com.arialyy.aria.ftp;
import aria.apache.commons.net.ftp.FTPClientConfig;
import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.FtpConnectionMode;
import com.arialyy.aria.core.inf.ITaskOption;
import com.arialyy.aria.core.processor.FtpInterceptHandler;
import com.arialyy.aria.core.processor.IFtpUploadInterceptor;
import com.arialyy.aria.core.inf.ITaskOption;
import java.lang.ref.SoftReference;
import java.net.Proxy;
@@ -55,6 +56,54 @@ public class FtpTaskOption implements ITaskOption {
*/
private FTPClientConfig clientConfig;
/**
* 连接模式,默认为被动模式
* {@link FtpConnectionMode}
*/
private int connMode;
/**
* 主动模式下的端口范围
*/
private int minPort, maxPort;
/**
* 主动模式下对外ip可被Ftp服务器访问的ip
*/
private String activeExternalIPAddress;
public String getActiveExternalIPAddress() {
return activeExternalIPAddress;
}
public void setActiveExternalIPAddress(String activeExternalIPAddress) {
this.activeExternalIPAddress = activeExternalIPAddress;
}
public int getMinPort() {
return minPort;
}
public void setMinPort(int minPort) {
this.minPort = minPort;
}
public int getMaxPort() {
return maxPort;
}
public void setMaxPort(int maxPort) {
this.maxPort = maxPort;
}
public int getConnMode() {
return connMode;
}
public void setConnMode(int connMode) {
this.connMode = connMode;
}
public FTPClientConfig getClientConfig() {
return clientConfig;
}

View File

@@ -16,32 +16,33 @@
package com.arialyy.aria.ftp.download;
import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.task.AbsNormalLoaderAdapter;
import com.arialyy.aria.core.common.RecordHandler;
import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.inf.IRecordHandler;
import com.arialyy.aria.core.task.AbsNormalLoaderAdapter;
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.core.inf.IRecordHandler;
import com.arialyy.aria.core.task.IThreadTask;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.ftp.FtpRecordAdapter;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.FileUtil;
import java.io.File;
/**
* @Author lyy
* @Date 2019-09-19
*/
final class FtpDLoaderAdapter extends AbsNormalLoaderAdapter {
public class FtpDLoaderAdapter extends AbsNormalLoaderAdapter {
FtpDLoaderAdapter(ITaskWrapper wrapper) {
public FtpDLoaderAdapter(ITaskWrapper wrapper) {
super(wrapper);
}
@Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) {
if (!record.isBlock) {
if (getTempFile().exists()) {
getTempFile().delete();
FileUtil.deleteFile(getTempFile());
}
//CommonUtil.createFile(mTempFile.getPath());
} else {
@@ -50,7 +51,7 @@ final class FtpDLoaderAdapter extends AbsNormalLoaderAdapter {
new File(String.format(IRecordHandler.SUB_PATH, getTempFile().getPath(), i));
if (blockFile.exists()) {
ALog.d(TAG, String.format("分块【%s】已经存在将删除该分块", i));
blockFile.delete();
FileUtil.deleteFile(blockFile);
}
}
}

View File

@@ -83,7 +83,7 @@ final class FtpDThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
return;
}
if (getThreadConfig().isOpenDynamicFile) {
if (getThreadConfig().isBlock) {
readDynamicFile(is);
} else {
readNormal(is);
@@ -180,7 +180,9 @@ final class FtpDThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
try {
file =
new BufferedRandomAccessFile(getThreadConfig().tempFile, "rwd", getTaskConfig().getBuffSize());
file.seek(getThreadRecord().startLocation);
if (getThreadRecord().startLocation > 0){
file.seek(getThreadRecord().startLocation);
}
byte[] buffer = new byte[getTaskConfig().getBuffSize()];
int len;
while (getThreadTask().isLive() && (len = is.read(buffer)) != -1) {

View File

@@ -85,13 +85,14 @@ public class FtpDirDLoaderUtil extends AbsGroupUtil {
* @param needCloneInfo 第一次下载,信息已经在{@link FtpDirInfoThread}中clone了
*/
private void startDownload(boolean needCloneInfo) {
// ftp需要获取完成只任务信息才更新只任务数量
getState().setSubSize(getWrapper().getSubTaskWrapper().size());
try {
LOCK.lock();
condition.signalAll();
} finally {
LOCK.unlock();
}
initState();
for (DTaskWrapper wrapper : getWrapper().getSubTaskWrapper()) {
if (needCloneInfo) {
cloneInfo(wrapper);

View File

@@ -15,7 +15,6 @@
*/
package com.arialyy.aria.ftp.upload;
import androidx.annotation.NonNull;
import com.arialyy.aria.util.BufferedRandomAccessFile;
import java.io.IOException;
import java.io.InputStream;
@@ -34,12 +33,12 @@ final class FtpFISAdapter extends InputStream {
void onProgressCallback(byte[] buffer, int byteOffset, int byteCount) throws IOException;
}
FtpFISAdapter(@NonNull BufferedRandomAccessFile is, @NonNull ProgressCallback callback) {
FtpFISAdapter(BufferedRandomAccessFile is, ProgressCallback callback) {
mIs = is;
mCallback = callback;
}
FtpFISAdapter(@NonNull BufferedRandomAccessFile is) {
FtpFISAdapter(BufferedRandomAccessFile is) {
mIs = is;
}
@@ -51,7 +50,7 @@ final class FtpFISAdapter extends InputStream {
return mIs.read();
}
@Override public int read(@NonNull byte[] buffer) throws IOException {
@Override public int read(byte[] buffer) throws IOException {
count = mIs.read(buffer);
if (mCallback != null) {
mCallback.onProgressCallback(buffer, 0, count);
@@ -59,7 +58,7 @@ final class FtpFISAdapter extends InputStream {
return count;
}
@Override public int read(@NonNull byte[] buffer, int byteOffset, int byteCount)
@Override public int read(byte[] buffer, int byteOffset, int byteCount)
throws IOException {
count = mIs.read(buffer, byteOffset, byteCount);
if (mCallback != null) {

View File

@@ -22,11 +22,11 @@ import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.ThreadRecord;
import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.inf.OnFileInfoCallback;
import com.arialyy.aria.core.processor.FtpInterceptHandler;
import com.arialyy.aria.core.processor.IFtpUploadInterceptor;
import com.arialyy.aria.core.upload.UTaskWrapper;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.ftp.AbsFtpInfoThread;
import com.arialyy.aria.core.processor.FtpInterceptHandler;
import com.arialyy.aria.core.processor.IFtpUploadInterceptor;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.DbDataHelper;
@@ -39,14 +39,9 @@ import java.util.List;
* 单任务上传远程服务器文件信息
*/
class FtpUFileInfoThread extends AbsFtpInfoThread<UploadEntity, UTaskWrapper> {
private static final String TAG = "FtpUploadFileInfoThread";
static final int CODE_COMPLETE = 0xab1;
private boolean isComplete = false;
private String remotePath;
/**
* true 使用拦截器false 不使用拦截器
*/
private boolean useInterceptor = false;
FtpUFileInfoThread(UTaskWrapper taskEntity, OnFileInfoCallback callback) {
super(taskEntity, callback);
@@ -59,13 +54,16 @@ class FtpUFileInfoThread extends AbsFtpInfoThread<UploadEntity, UTaskWrapper> {
@Override protected boolean onInterceptor(FTPClient client, FTPFile[] ftpFiles) {
// 旧任务将不做处理,否则断点续传上传将失效
if (!mTaskWrapper.isNewTask()) {
return true;
}
//if (!mTaskWrapper.isNewTask()) {
// ALog.d(TAG, "任务是旧任务,忽略该拦截器");
// return true;
//}
try {
IFtpUploadInterceptor interceptor = mTaskOption.getUploadInterceptor();
if (interceptor != null) {
useInterceptor = true;
/**
* true 使用拦截器false 不使用拦截器
*/
List<String> files = new ArrayList<>();
for (FTPFile ftpFile : ftpFiles) {
if (ftpFile.isDirectory()) {
@@ -77,7 +75,7 @@ class FtpUFileInfoThread extends AbsFtpInfoThread<UploadEntity, UTaskWrapper> {
FtpInterceptHandler interceptHandler = interceptor.onIntercept(mEntity, files);
/*
处理远端有同名文件的情况
* 处理远端有同名文件的情况
*/
if (files.contains(mEntity.getFileName())) {
if (interceptHandler.isCoverServerFile()) {
@@ -93,6 +91,7 @@ class FtpUFileInfoThread extends AbsFtpInfoThread<UploadEntity, UTaskWrapper> {
+ "/"
+ interceptHandler.getNewFileName();
mTaskOption.setNewFileName(interceptHandler.getNewFileName());
closeClient(client);
run();
return false;
@@ -117,11 +116,14 @@ class FtpUFileInfoThread extends AbsFtpInfoThread<UploadEntity, UTaskWrapper> {
*/
@Override protected void handleFile(String remotePath, FTPFile ftpFile) {
super.handleFile(remotePath, ftpFile);
if (ftpFile != null && !useInterceptor) {
if (ftpFile != null) {
//远程文件已完成
if (ftpFile.getSize() == mEntity.getFileSize()) {
isComplete = true;
ALog.d(TAG, "FTP服务器上已存在该文件【" + ftpFile.getName() + "");
} else if (ftpFile.getSize() == 0) {
mTaskWrapper.setNewTask(true);
ALog.d(TAG, "FTP服务器上已存在该文件【" + ftpFile.getName() + "但文件长度为0重新上传该文件");
} else {
ALog.w(TAG, "FTP服务器已存在未完成的文件【"
+ ftpFile.getName()
@@ -134,7 +136,8 @@ class FtpUFileInfoThread extends AbsFtpInfoThread<UploadEntity, UTaskWrapper> {
mTaskWrapper.setNewTask(false);
// 修改记录
TaskRecord record = DbDataHelper.getTaskRecord(mTaskWrapper.getKey());
TaskRecord record = DbDataHelper.getTaskRecord(mTaskWrapper.getKey(),
mTaskWrapper.getEntity().getTaskType());
if (record == null) {
record = new TaskRecord();
record.fileName = mEntity.getFileName();

View File

@@ -28,20 +28,25 @@ import com.arialyy.aria.util.BufferedRandomAccessFile;
import com.arialyy.aria.util.CommonUtil;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Created by Aria.Lao on 2017/7/28. D_FTP 单线程上传任务需要FTP 服务器给用户打开append和write的权限
*/
class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
private final String TAG = "FtpThreadTask";
private String dir, remotePath;
private boolean storeFail = false;
private ScheduledThreadPoolExecutor timer;
private FTPClient client = null;
private boolean isTimeOut = true;
private FtpFISAdapter fa;
FtpUThreadTaskAdapter(SubThreadConfig config) {
super(config);
}
@Override protected void handlerThreadTask() {
FTPClient client = null;
BufferedRandomAccessFile file = null;
try {
ALog.d(TAG,
@@ -66,12 +71,12 @@ class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
}
file =
new BufferedRandomAccessFile(getThreadConfig().tempFile, "rwd", getTaskConfig().getBuffSize());
if (getThreadRecord().startLocation != 0) {
//file.skipBytes((int) getThreadConfig().START_LOCATION);
new BufferedRandomAccessFile(getThreadConfig().tempFile, "rwd",
getTaskConfig().getBuffSize());
if (getThreadRecord().startLocation > 0) {
file.seek(getThreadRecord().startLocation);
}
boolean complete = upload(client, file);
boolean complete = upload(file);
if (!complete || getThreadTask().isBreak()) {
return;
}
@@ -79,6 +84,7 @@ class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
String.format("任务【%s】线程__%s__上传完毕", getEntity().getKey(), getThreadRecord().threadId));
complete();
} catch (IOException e) {
e.printStackTrace();
fail(new AriaIOException(TAG,
String.format("上传失败filePath: %s, uploadUrl: %s", getEntity().getFilePath(),
getThreadConfig().url)), true);
@@ -93,6 +99,7 @@ class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
e.printStackTrace();
}
closeClient(client);
closeTimer();
}
}
@@ -103,32 +110,63 @@ class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
private void initPath() throws UnsupportedEncodingException {
dir = CommonUtil.convertFtpChar(charSet, mTaskOption.getUrlEntity().remotePath);
String fileName =
TextUtils.isEmpty(mTaskOption.getNewFileName()) ? CommonUtil.convertFtpChar(charSet,
getEntity().getFileName())
: CommonUtil.convertFtpChar(charSet, mTaskOption.getNewFileName());
String fileName = TextUtils.isEmpty(mTaskOption.getNewFileName()) ? getEntity().getFileName()
: mTaskOption.getNewFileName();
remotePath =
CommonUtil.convertFtpChar(charSet,
String.format("%s/%s", mTaskOption.getUrlEntity().remotePath, fileName));
}
/**
* 启动监听定时器当网络断开时如果该任务的FTP服务器的传输线程没有断开当客户端重新连接时客户端将无法发送数据到服务端
* 每隔10s检查一次。
*/
private void startTimer() {
timer = new ScheduledThreadPoolExecutor(1);
timer.scheduleWithFixedDelay(new Runnable() {
@Override public void run() {
try {
if (isTimeOut) {
fail(new AriaIOException(TAG, "socket连接失败该问题一般出现于网络断开客户端重新连接"
+ "但是服务器端无法创建socket缺没有返回错误码的情况。"), false);
}
if (fa != null) {
fa.close();
}
isTimeOut = true;
} catch (IOException e) {
e.printStackTrace();
}
}
}, 10, 10, TimeUnit.SECONDS);
}
private void closeTimer() {
if (timer != null && !timer.isShutdown()) {
timer.shutdown();
}
}
/**
* 上传
*
* @return {@code true}上传成功、{@code false} 上传失败
*/
private boolean upload(final FTPClient client, final BufferedRandomAccessFile bis)
private boolean upload(final BufferedRandomAccessFile bis)
throws IOException {
fa = new FtpFISAdapter(bis);
storeFail = false;
startTimer();
try {
ALog.d(TAG, String.format("remotePath: %s", remotePath));
client.storeFile(remotePath, new FtpFISAdapter(bis), new OnFtpInputStreamListener() {
client.storeFile(remotePath, fa, new OnFtpInputStreamListener() {
boolean isStoped = false;
@Override public void onFtpInputStream(FTPClient client, long totalBytesTransferred,
int bytesTransferred, long streamSize) {
try {
isTimeOut = false;
if (getThreadTask().isBreak() && !isStoped) {
isStoped = true;
client.abor();
@@ -139,33 +177,39 @@ class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
progress(bytesTransferred);
} catch (IOException e) {
e.printStackTrace();
storeFail = true;
try {
fa.close();
} catch (IOException e1) {
e1.printStackTrace();
}
closeClient(client);
}
}
});
} catch (IOException e) {
String msg = String.format("文件上传错误,错误码为:%s, msg%s, filePath: %s", client.getReplyCode(),
String msg = String.format("文件上传错误,错误码为:%s, msg%s, filePath: %s", client.getReply(),
client.getReplyString(), getEntity().getFilePath());
if (client.isConnected()) {
client.disconnect();
}
closeClient(client);
e.printStackTrace();
if (e.getMessage().contains("AriaIOException caught while copying")) {
e.printStackTrace();
} else {
fail(new AriaIOException(TAG, msg, e), true);
fail(new AriaIOException(TAG, msg, e), !storeFail);
}
return false;
}
int reply = client.getReplyCode();
if (storeFail) {
return false;
}
int reply = client.getReply();
if (!FTPReply.isPositiveCompletion(reply)) {
if (reply != FTPReply.TRANSFER_ABORTED) {
fail(new AriaIOException(TAG,
String.format("文件上传错误,错误码为:%s, msg%s, filePath: %s", reply, client.getReplyString(),
getEntity().getFilePath())), false);
}
if (client.isConnected()) {
client.disconnect();
}
closeClient(client);
return false;
}
return true;

View File

@@ -1,3 +0,0 @@
<resources>
<string name="app_name">AriaFtpComponent</string>
</resources>

View File

@@ -10,7 +10,6 @@ android {
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}
@@ -25,9 +24,6 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "androidx.appcompat:appcompat:${rootProject.ext.XAppcompatVersion}"
testImplementation 'junit:junit:4.12'
implementation project(path: ':PublicComponent')
}

View File

@@ -24,8 +24,8 @@ import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.processor.IHttpFileLenAdapter;
import com.arialyy.aria.core.inf.OnFileInfoCallback;
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;
@@ -89,6 +89,11 @@ public class HttpFileInfoThread implements Runnable {
true);
} finally {
if (conn != null) {
try {
conn.getInputStream().close();
} catch (IOException e) {
e.printStackTrace();
}
conn.disconnect();
}
}
@@ -214,7 +219,7 @@ public class HttpFileInfoThread implements Runnable {
} else {
failDownload(new AriaIOException(TAG,
String.format("任务下载失败errorCode%s, errorMsg: %s, url: %s", code,
conn.getResponseMessage(), mEntity.getUrl())), true);
conn.getResponseMessage(), mEntity.getUrl())), !CheckUtil.httpIsBadRequest(code));
}
if (end) {
taskOption.setChunked(isChunked);
@@ -277,7 +282,7 @@ public class HttpFileInfoThread implements Runnable {
}
mEntity.setFileName(newName);
mEntity.setFilePath(newPath);
RecordUtil.modifyTaskRecord(oldFile.getPath(), newPath);
RecordUtil.modifyTaskRecord(oldFile.getPath(), newPath, mEntity.getTaskType());
}
/**

View File

@@ -38,15 +38,19 @@ public class HttpRecordAdapter extends AbsRecordHandlerAdapter {
@Override public void onPre() {
super.onPre();
if (getWrapper().getRequestType() == ITaskWrapper.U_HTTP){
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 (record.isBlock) {
helper.handleBlockRecord();
if (getWrapper().isSupportBP()) {
if (record.isBlock) {
helper.handleBlockRecord();
} else {
helper.handleMultiRecord();
}
} else if (!getWrapper().isSupportBP()) {
helper.handleNoSupportBPRecord();
} else {
@@ -63,7 +67,7 @@ public class HttpRecordAdapter extends AbsRecordHandlerAdapter {
tr.startLocation = startL;
tr.isComplete = false;
tr.threadType = TaskRecord.TYPE_HTTP_FTP;
tr.threadType = getEntity().getTaskType();
//最后一个线程的结束位置即为文件的总长度
if (threadId == (record.threadNum - 1)) {
endL = getEntity().getFileSize();
@@ -81,14 +85,13 @@ public class HttpRecordAdapter extends AbsRecordHandlerAdapter {
record.threadNum = threadNum;
int requestType = getWrapper().getRequestType();
if (requestType == ITaskWrapper.D_FTP || requestType == ITaskWrapper.D_FTP_DIR) {
record.isBlock = threadNum > 1 && Configuration.getInstance().downloadCfg.isUseBlock();
// 线程数为1或者使用了分块则认为是使用动态长度文件
record.isOpenDynamicFile = threadNum == 1 || record.isBlock;
if (requestType == ITaskWrapper.D_FTP || requestType == ITaskWrapper.D_FTP_DIR
|| requestType == ITaskWrapper.D_HTTP || requestType == ITaskWrapper.DG_HTTP) {
record.isBlock = Configuration.getInstance().downloadCfg.isUseBlock();
} else {
record.isBlock = false;
}
record.taskType = TaskRecord.TYPE_HTTP_FTP;
record.taskType = getEntity().getTaskType();
record.isGroupRecord = getEntity().isGroupChild();
if (record.isGroupRecord) {
if (getEntity() instanceof DownloadEntity) {

View File

@@ -73,9 +73,10 @@ public class DGroupLoaderUtil extends AbsGroupUtil {
@Override protected boolean onStart() {
super.onStart();
initState();
getState().setSubSize(getWrapper().getSubTaskWrapper().size());
if (getState().getCompleteNum() == getState().getSubSize()) {
mListener.onComplete();
return false;
} else {
// 处理组合任务大小未知的情况
if (getWrapper().isUnknownSize() && getWrapper().getEntity().getFileSize() < 1) {
@@ -91,6 +92,7 @@ public class DGroupLoaderUtil extends AbsGroupUtil {
return getLenComplete;
} else {
for (DTaskWrapper wrapper : getWrapper().getSubTaskWrapper()) {
cloneHeader(wrapper);
if (wrapper.getState() != IEntity.STATE_COMPLETE) {
startSubLoader(createSubLoader(wrapper, true));
}
@@ -179,7 +181,7 @@ public class DGroupLoaderUtil extends AbsGroupUtil {
*/
private void cloneHeader(DTaskWrapper taskWrapper) {
HttpTaskOption groupOption = (HttpTaskOption) getWrapper().getTaskOption();
HttpTaskOption subOption = (HttpTaskOption) taskWrapper.getTaskOption();
HttpTaskOption subOption = new HttpTaskOption();
// 设置属性
subOption.setFileLenAdapter(groupOption.getFileLenAdapter());
@@ -187,5 +189,6 @@ public class DGroupLoaderUtil extends AbsGroupUtil {
subOption.setHeaders(groupOption.getHeaders());
subOption.setProxy(groupOption.getProxy());
subOption.setParams(groupOption.getParams());
taskWrapper.setTaskOption(subOption);
}
}

View File

@@ -28,6 +28,7 @@ import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.http.HttpRecordAdapter;
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;
@@ -43,16 +44,15 @@ final class HttpDLoaderAdapter extends AbsNormalLoaderAdapter {
@Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) {
if (!record.isBlock) {
if (getTempFile().exists()) {
getTempFile().delete();
FileUtil.deleteFile(getTempFile());
}
//CommonUtil.createFile(mTempFile.getPath());
} else {
for (int i = 0; i < totalThreadNum; i++) {
File blockFile =
new File(String.format(IRecordHandler.SUB_PATH, getTempFile().getPath(), i));
if (blockFile.exists()) {
ALog.d(TAG, String.format("分块【%s】已经存在将删除该分块", i));
blockFile.delete();
FileUtil.deleteFile(blockFile);
}
}
}

View File

@@ -15,15 +15,16 @@
*/
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.http.BaseHttpThreadTaskAdapter;
import com.arialyy.aria.http.ConnectionHelp;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.BufferedRandomAccessFile;
import com.arialyy.aria.util.FileUtil;
import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -103,7 +104,7 @@ final class HttpDThreadTaskAdapter extends BaseHttpThreadTaskAdapter {
is = new BufferedInputStream(ConnectionHelp.convertInputStream(conn));
if (mTaskOption.isChunked()) {
readChunked(is);
} else if (getThreadConfig().isOpenDynamicFile) {
} else if (getThreadConfig().isBlock) {
readDynamicFile(is);
} else {
//创建可设置位置的文件
@@ -111,7 +112,9 @@ final class HttpDThreadTaskAdapter extends BaseHttpThreadTaskAdapter {
new BufferedRandomAccessFile(getThreadConfig().tempFile, "rwd",
getTaskConfig().getBuffSize());
//设置每条线程写入文件的位置
file.seek(getThreadRecord().startLocation);
if (getThreadRecord().startLocation > 0){
file.seek(getThreadRecord().startLocation);
}
readNormal(is, file);
handleComplete();
}
@@ -123,6 +126,10 @@ final class HttpDThreadTaskAdapter extends BaseHttpThreadTaskAdapter {
fail(new TaskException(TAG,
String.format("任务【%s】下载失败filePath: %s, url: %s", getFileName(),
getEntity().getFilePath(), getEntity().getUrl()), e), true);
} catch (ArrayIndexOutOfBoundsException e) {
fail(new TaskException(TAG,
String.format("任务【%s】下载失败filePath: %s, url: %s", getFileName(),
getEntity().getFilePath(), getEntity().getUrl()), e), false);
} catch (Exception e) {
fail(new TaskException(TAG,
String.format("任务【%s】下载失败filePath: %s, url: %s", getFileName(),
@@ -136,6 +143,7 @@ final class HttpDThreadTaskAdapter extends BaseHttpThreadTaskAdapter {
is.close();
}
if (conn != null) {
conn.getInputStream().close();
conn.disconnect();
}
} catch (IOException e) {

View File

@@ -1,3 +0,0 @@
<resources>
<string name="app_name">HttpComponent</string>
</resources>

View File

@@ -25,7 +25,6 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "androidx.appcompat:appcompat:${rootProject.ext.XAppcompatVersion}"
implementation project(path: ':HttpComponent')
implementation project(path: ':PublicComponent')
}

View File

@@ -15,6 +15,7 @@
*/
package com.arialyy.aria.m3u8;
import android.text.TextUtils;
import com.arialyy.aria.core.common.RecordHandler;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity;
@@ -59,6 +60,9 @@ public abstract class BaseM3U8Loader extends AbsLoader {
protected String getCacheDir() {
String cacheDir = mM3U8Option.getCacheDir();
if (TextUtils.isEmpty(cacheDir)) {
cacheDir = FileUtil.getTsCacheDir(getEntity().getFilePath(), mM3U8Option.getBandWidth());
}
if (!new File(cacheDir).exists()) {
FileUtil.createDir(cacheDir);
}
@@ -68,8 +72,9 @@ public abstract class BaseM3U8Loader extends AbsLoader {
/**
* 创建索引文件
*/
protected boolean generateIndexFile() {
File tempFile = new File(M3U8InfoThread.M3U8_INDEX_FORMAT, getEntity().getFilePath());
public boolean generateIndexFile(boolean isLive) {
File tempFile =
new File(String.format(M3U8InfoThread.M3U8_INDEX_FORMAT, getEntity().getFilePath()));
if (!tempFile.exists()) {
ALog.e(TAG, "源索引文件不存在");
return false;
@@ -85,21 +90,29 @@ public abstract class BaseM3U8Loader extends AbsLoader {
int i = 0;
while ((line = reader.readLine()) != null) {
byte[] bytes;
if (line.startsWith("EXTINF")) {
if (line.startsWith("#EXTINF")) {
fos.write(line.concat("\r\n").getBytes(Charset.forName("UTF-8")));
String tsPath = getTsFilePath(cacheDir, mRecord.threadRecords.get(i).threadId);
bytes = tsPath.concat("\r\n").getBytes(Charset.forName("UTF-8"));
reader.readLine(); // 继续读一行,避免写入源索引文件的切片地址
i++;
} else if (line.startsWith("EXT-X-KEY")) {
} else if (line.startsWith("#EXT-X-KEY")) {
M3U8Entity m3U8Entity = getEntity().getM3U8Entity();
String keyInfo = String.format("#EXT-X-KEY:METHOD=%s,URI=%s,IV=%s\r\n", m3U8Entity.method,
m3U8Entity.keyPath, m3U8Entity.iv);
bytes = keyInfo.getBytes(Charset.forName("UTF-8"));
} else {
bytes = line.getBytes(Charset.forName("UTF-8"));
bytes = line.concat("\r\n").getBytes(Charset.forName("UTF-8"));
}
fos.write(bytes, 0, bytes.length);
}
// 直播的索引文件需要在结束的时候才写入结束标志
if (isLive) {
fos.write("#EXT-X-ENDLIST".concat("\r\n").getBytes(Charset.forName("UTF-8")));
}
fos.flush();
return true;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {

View File

@@ -24,8 +24,9 @@ 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.core.download.M3U8Entity;
import com.arialyy.aria.core.processor.IBandWidthUrlConverter;
import com.arialyy.aria.core.inf.OnFileInfoCallback;
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;
@@ -39,7 +40,6 @@ import com.arialyy.aria.util.FileUtil;
import com.arialyy.aria.util.Regular;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -55,6 +55,7 @@ import java.util.regex.Pattern;
/**
* 解析url中获取到到m3u8文件信息
* 协议地址https://tools.ietf.org/html/rfc8216
* https://www.cnblogs.com/renhui/p/10351870.html
* https://blog.csdn.net/Guofengpu/article/details/54922865
*/
@@ -72,13 +73,9 @@ final public class M3U8InfoThread implements Runnable {
* 是否停止获取切片信息,{@code true}停止获取切片信息
*/
private boolean isStop = false;
/**
* m3u8文件信息
*/
private List<String> mInfos = new ArrayList<>();
public interface OnGetLivePeerCallback {
void onGetPeer(String url);
void onGetPeer(String url, String extInf);
}
public M3U8InfoThread(DTaskWrapper taskWrapper, OnFileInfoCallback callback) {
@@ -122,38 +119,51 @@ final public class M3U8InfoThread implements Runnable {
}
List<String> extInf = new ArrayList<>();
boolean isLive = mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_LIVE;
boolean isGenerateIndexFile = mTaskWrapper.getEntity().getM3U8Entity().isGenerateIndexFile();
boolean isGenerateIndexFile =
((M3U8TaskOption) mTaskWrapper.getM3u8Option()).isGenerateIndexFile();
// 写入索引信息的流
FileOutputStream fos = null;
if (isGenerateIndexFile) {
mInfos.add(line);
String indexPath = String.format(M3U8_INDEX_FORMAT, mEntity.getFilePath());
File indexFile = new File(indexPath);
if (!indexFile.exists()) {
FileUtil.createFile(indexPath);
} else {
//FileUtil.deleteFile(indexPath);
}
fos = new FileOutputStream(indexFile);
ALog.d(TAG, line);
addIndexInfo(isGenerateIndexFile, fos, line);
}
while ((line = reader.readLine()) != null) {
if (isStop) {
break;
}
if (isGenerateIndexFile) {
mInfos.add(line);
}
if (line.startsWith("#EXT-X-ENDLIST")) {
break;
}
ALog.d(TAG, line);
if (line.startsWith("#EXTINF")) {
String info = reader.readLine();
mInfos.add(info);
if (line.startsWith("#EXT-X-ENDLIST")) {
// 点播文件的下载写入结束标志,直播文件的下载在停止时才写入结束标志
addIndexInfo(isGenerateIndexFile && !isLive, fos, line);
break;
} else if (line.startsWith("#EXTINF")) {
String url = reader.readLine();
if (isLive) {
if (onGetPeerCallback != null) {
onGetPeerCallback.onGetPeer(info);
onGetPeerCallback.onGetPeer(url, line);
}
} else {
extInf.add(info);
extInf.add(url);
}
ALog.d(TAG, url);
addIndexInfo(isGenerateIndexFile && !isLive, fos, line);
addIndexInfo(isGenerateIndexFile && !isLive, fos, url);
} else if (line.startsWith("#EXT-X-STREAM-INF")) {
addIndexInfo(isGenerateIndexFile, fos, line);
int setBand = mM3U8Option.getBandWidth();
int bandWidth = getBandWidth(line);
// 多码率的m3u8配置文件清空信息
if (isGenerateIndexFile && mInfos != null) {
mInfos.clear();
}
//if (isGenerateIndexFile && mInfos != null) {
// mInfos.clear();
//}
if (setBand == 0) {
handleBandWidth(conn, reader.readLine());
} else if (bandWidth == setBand) {
@@ -162,8 +172,11 @@ final public class M3U8InfoThread implements Runnable {
failDownload(String.format("【%s】码率不存在", bandWidth), false);
}
return;
} else if (line.startsWith("EXT-X-KEY")) {
} else if (line.startsWith("#EXT-X-KEY")) {
addIndexInfo(isGenerateIndexFile, fos, line);
getKeyInfo(line);
} else {
addIndexInfo(isGenerateIndexFile, fos, line);
}
}
@@ -177,8 +190,11 @@ final public class M3U8InfoThread implements Runnable {
}
CompleteInfo info = new CompleteInfo();
info.obj = extInf;
generateIndexFile();
onFileInfoCallback.onComplete(mEntity.getKey(), info);
if (fos != null) {
fos.close();
}
} else if (code == HttpURLConnection.HTTP_MOVED_TEMP
|| code == HttpURLConnection.HTTP_MOVED_PERM
|| code == HttpURLConnection.HTTP_SEE_OTHER
@@ -193,40 +209,19 @@ final public class M3U8InfoThread implements Runnable {
}
/**
* 创建索引文件
* 添加切片信息到索引文件
* 直播下载的索引只记录头部信息不记录EXTINF中的信息该信息在onGetPeer的方法中添加。
* 点播下载记录所有信息
*
* @param write true 将信息写入文件
* @param info 切片信息
*/
private void generateIndexFile() {
if (mTaskWrapper.getEntity().getM3U8Entity().isGenerateIndexFile()) {
String indexPath = String.format(M3U8_INDEX_FORMAT, mEntity.getFilePath());
File indexFile = new File(indexPath);
if (indexFile.exists()) {
FileUtil.deleteFile(indexPath);
}
FileUtil.createFile(indexPath);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(indexFile);
for (String str : mInfos) {
byte[] by = str.concat("\r\n").getBytes(Charset.forName("UTF-8"));
fos.write(by, 0, by.length);
}
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void addIndexInfo(boolean write, FileOutputStream fos, String info)
throws IOException {
if (!write) {
return;
}
fos.write(info.concat("\r\n").getBytes(Charset.forName("UTF-8")));
}
/**
@@ -260,6 +255,10 @@ final public class M3U8InfoThread implements Runnable {
m3U8Entity.keyUrl) + ".key";
} else if (param.startsWith("IV")) {
m3U8Entity.iv = param.split("=")[1];
}else if (param.startsWith("KEYFORMAT")){
m3U8Entity.keyFormat = param.split("=")[1];
}else if (param.startsWith("KEYFORMATVERSIONS")){
m3U8Entity.keyFormatVersion = param.split("=")[1];
}
}
downloadKey(m3U8Entity);
@@ -355,11 +354,22 @@ final public class M3U8InfoThread implements Runnable {
File keyF = new File(info.keyPath);
if (!keyF.exists()) {
ALog.d(TAG, "密钥不存在,下载密钥");
FileUtil.createFile(keyF.getPath());
FileUtil.createFile(keyF);
} else {
return;
}
URL url = ConnectionHelp.handleUrl(info.keyUrl, mHttpOption);
IKeyUrlConverter keyUrlConverter = mM3U8Option.getKeyUrlConverter();
String keyUrl = info.keyUrl;
if (keyUrlConverter != null) {
keyUrl = keyUrlConverter.convert(keyUrl);
}
if (TextUtils.isEmpty(keyUrl)){
ALog.e(TAG, "m3u8密钥key url 为空");
return;
}
URL url = ConnectionHelp.handleUrl(keyUrl, mHttpOption);
conn = ConnectionHelp.handleConnection(url, mHttpOption);
ConnectionHelp.setConnectParam(mHttpOption, conn);
conn.setConnectTimeout(mConnectTimeOut);

View File

@@ -24,6 +24,7 @@ import com.arialyy.aria.core.download.M3U8Entity;
import com.arialyy.aria.core.inf.IRecordHandler;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.FileUtil;
import com.arialyy.aria.util.RecordUtil;
import java.io.File;
import java.util.ArrayList;
@@ -42,7 +43,7 @@ public class M3U8RecordAdapter extends AbsRecordHandlerAdapter {
@Override public void onPre() {
super.onPre();
if (getWrapper().getRequestType() == ITaskWrapper.M3U8_LIVE){
if (getWrapper().getRequestType() == ITaskWrapper.M3U8_LIVE) {
RecordUtil.delTaskRecord(getEntity().getFilePath(), IRecordHandler.TYPE_DOWNLOAD);
}
}
@@ -54,18 +55,22 @@ public class M3U8RecordAdapter extends AbsRecordHandlerAdapter {
String cacheDir = mOption.getCacheDir();
long currentProgress = 0;
int completeNum = 0;
File targetFile = new File(mTaskRecord.filePath);
if (!targetFile.exists()) {
FileUtil.createFile(targetFile);
}
M3U8Entity m3U8Entity = ((DownloadEntity) getEntity()).getM3U8Entity();
// 重新下载所有切片
boolean reDownload =
(m3U8Entity.getPeerNum() <= 0 || (m3U8Entity.isGenerateIndexFile() && !new File(
(m3U8Entity.getPeerNum() <= 0 || (mOption.isGenerateIndexFile() && !new File(
String.format(M3U8InfoThread.M3U8_INDEX_FORMAT, getEntity().getFilePath())).exists()));
for (ThreadRecord record : mTaskRecord.threadRecords) {
File temp = new File(BaseM3U8Loader.getTsFilePath(cacheDir, record.threadId));
if (!record.isComplete || reDownload) {
if (temp.exists()) {
temp.delete();
FileUtil.deleteFile(temp);
}
record.startLocation = 0;
//ALog.d(TAG, String.format("分片【%s】未完成将重新下载该分片", record.threadId));
@@ -101,7 +106,7 @@ public class M3U8RecordAdapter extends AbsRecordHandlerAdapter {
tr.threadId = threadId;
tr.isComplete = false;
tr.startLocation = 0;
tr.threadType = TaskRecord.TYPE_M3U8_VOD;
tr.threadType = getEntity().getTaskType();
tr.tsUrl = mOption.getUrls().get(threadId);
return tr;
}
@@ -112,23 +117,16 @@ public class M3U8RecordAdapter extends AbsRecordHandlerAdapter {
record.filePath = getEntity().getFilePath();
record.threadRecords = new ArrayList<>();
record.threadNum = threadNum;
int requestType = getWrapper().getRequestType();
if (requestType == ITaskWrapper.M3U8_VOD) {
record.taskType = TaskRecord.TYPE_M3U8_VOD;
record.isOpenDynamicFile = true;
record.bandWidth = mOption.getBandWidth();
} else if (requestType == ITaskWrapper.M3U8_LIVE) {
record.taskType = TaskRecord.TYPE_M3U8_LIVE;
record.isOpenDynamicFile = true;
record.bandWidth = mOption.getBandWidth();
}
record.isBlock = true;
record.taskType = getEntity().getTaskType();
record.bandWidth = mOption.getBandWidth();
return record;
}
@Override public int initTaskThreadNum() {
if (getWrapper().getRequestType() == ITaskWrapper.M3U8_VOD) {
return mOption.getUrls().size();
return
mOption.getUrls() == null || mOption.getUrls().isEmpty() ? 1 : mOption.getUrls().size();
}
if (getWrapper().getRequestType() == ITaskWrapper.M3U8_LIVE) {
return 1;

View File

@@ -17,6 +17,7 @@ package com.arialyy.aria.m3u8;
import com.arialyy.aria.core.inf.ITaskOption;
import com.arialyy.aria.core.processor.IBandWidthUrlConverter;
import com.arialyy.aria.core.processor.IKeyUrlConverter;
import com.arialyy.aria.core.processor.ILiveTsUrlConverter;
import com.arialyy.aria.core.processor.ITsMergeHandler;
import com.arialyy.aria.core.processor.IVodTsUrlConverter;
@@ -101,14 +102,41 @@ public class M3U8TaskOption implements ITaskOption {
/**
* 生成索引占位字段
*/
private boolean generateIndexFileTemp = false;
private boolean generateIndexFile = false;
public boolean isGenerateIndexFileTemp() {
return generateIndexFileTemp;
/**
* 加密密钥的解密处理器
*/
private SoftReference<IKeyUrlConverter> keyUrlConverter;
/**
* 忽略下载失败的ts切片。
* true即使有失败的切片下载完成后也要合并所有切片并进入complete回调
*/
private boolean ignoreFailureTs = false;
public boolean isIgnoreFailureTs() {
return ignoreFailureTs;
}
public void setGenerateIndexFileTemp(boolean generateIndexFileTemp) {
this.generateIndexFileTemp = generateIndexFileTemp;
public void setIgnoreFailureTs(boolean ignoreFailureTs) {
this.ignoreFailureTs = ignoreFailureTs;
}
public IKeyUrlConverter getKeyUrlConverter() {
return keyUrlConverter == null ? null : keyUrlConverter.get();
}
public void setKeyUrlConverter(IKeyUrlConverter keyUrlConverter) {
this.keyUrlConverter = new SoftReference<>(keyUrlConverter);
}
public boolean isGenerateIndexFile() {
return generateIndexFile;
}
public void setGenerateIndexFile(boolean generateIndexFile) {
this.generateIndexFile = generateIndexFile;
}
public int getJumpIndex() {

View File

@@ -89,10 +89,18 @@ public class M3U8ThreadTaskAdapter extends AbsThreadTaskAdapter {
}
}
int code = conn.getResponseCode();
if (code != HttpURLConnection.HTTP_OK) {
fail(new TaskException(TAG,
String.format("连接错误http错误码%surl%s", code, getThreadConfig().url)),
false);
return;
}
is = new BufferedInputStream(ConnectionHelp.convertInputStream(conn));
if (mHttpTaskOption.isChunked()) {
readChunked(is);
} else if (getThreadConfig().isOpenDynamicFile) {
} else if (getThreadConfig().isBlock) {
readDynamicFile(is);
}
} catch (MalformedURLException e) {

View File

@@ -24,17 +24,22 @@ import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.inf.IThreadState;
import com.arialyy.aria.core.listener.IEventListener;
import com.arialyy.aria.core.listener.ISchedulers;
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.m3u8.BaseM3U8Loader;
import com.arialyy.aria.core.processor.ITsMergeHandler;
import com.arialyy.aria.m3u8.IdGenerator;
import com.arialyy.aria.m3u8.M3U8Listener;
import com.arialyy.aria.m3u8.M3U8TaskOption;
import com.arialyy.aria.m3u8.M3U8ThreadTaskAdapter;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.FileUtil;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
@@ -42,6 +47,8 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import static com.arialyy.aria.m3u8.M3U8InfoThread.M3U8_INDEX_FORMAT;
/**
* M3U8点播文件下载器
*/
@@ -49,15 +56,21 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
/**
* 最大执行数
*/
private static final int EXEC_MAX_NUM = 4;
private static int EXEC_MAX_NUM = 4;
private Handler mStateHandler;
private ArrayBlockingQueue<Long> mFlagQueue = new ArrayBlockingQueue<>(EXEC_MAX_NUM);
private ReentrantLock LOCK = new ReentrantLock();
private Condition mCondition = LOCK.newCondition();
private LinkedBlockingQueue<String> mPeerQueue = new LinkedBlockingQueue<>();
private LinkedBlockingQueue<ExtInfo> mPeerQueue = new LinkedBlockingQueue<>();
private ExtInfo mCurExtInfo;
private FileOutputStream mIndexFos;
M3U8LiveLoader(M3U8Listener listener, DTaskWrapper wrapper) {
super(listener, wrapper);
if (((M3U8TaskOption) wrapper.getM3u8Option()).isGenerateIndexFile()) {
ALog.i(TAG, "直播文件下载,创建索引文件的操作将导致只能同时下载一个切片");
EXEC_MAX_NUM = 1;
}
}
@Override protected IThreadState createStateManager(Looper looper) {
@@ -66,8 +79,8 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
return manager;
}
void offerPeer(String peerUrl) {
mPeerQueue.offer(peerUrl);
void offerPeer(ExtInfo extInfo) {
mPeerQueue.offer(extInfo);
}
@Override protected void handleTask() {
@@ -80,13 +93,14 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
try {
LOCK.lock();
while (mFlagQueue.size() < EXEC_MAX_NUM) {
String url = mPeerQueue.poll();
if (url == null) {
ExtInfo extInfo = mPeerQueue.poll();
if (extInfo == null) {
break;
}
ThreadTask task = createThreadTask(cacheDir, index, url);
mCurExtInfo = extInfo;
ThreadTask task = createThreadTask(cacheDir, index, extInfo.url);
getTaskList().put(index, task);
mFlagQueue.offer(startThreadTask(task));
mFlagQueue.offer(startThreadTask(task, task.getConfig().peerIndex));
index++;
}
if (mFlagQueue.size() > 0) {
@@ -106,11 +120,15 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
return mTempFile.length();
}
private void notifyLock() {
private void notifyLock(boolean success, int peerId) {
try {
LOCK.lock();
long id = mFlagQueue.take();
ALog.d(TAG, String.format("线程【%s】完成", id));
if (success) {
ALog.d(TAG, String.format("切片【%s】下载成功", peerId));
} else {
ALog.e(TAG, String.format("切片【%s】下载失败", peerId));
}
mCondition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
@@ -119,13 +137,27 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
}
}
@Override protected void onPostStop() {
super.onPostStop();
if (mIndexFos != null) {
try {
mIndexFos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 启动线程任务
*
* @return 线程唯一id标志
*/
private long startThreadTask(ThreadTask task) {
private long startThreadTask(ThreadTask task, int indexId) {
ThreadTaskManager.getInstance().startThread(mTaskWrapper.getKey(), task);
((M3U8Listener) mListener).onPeerStart(mTaskWrapper.getKey(),
task.getConfig().tempFile.getPath(),
indexId);
return IdGenerator.getInstance().nextId();
}
@@ -137,20 +169,21 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
record.taskKey = mRecord.filePath;
record.isComplete = false;
record.tsUrl = tsUrl;
record.threadType = TaskRecord.TYPE_M3U8_LIVE;
record.threadType = getEntity().getTaskType();
record.threadId = indexId;
mRecord.threadRecords.add(record);
SubThreadConfig config = new SubThreadConfig();
config.url = tsUrl;
config.tempFile = new File(getTsFilePath(cacheDir, indexId));
config.isBlock = mRecord.isBlock;
config.isOpenDynamicFile = mRecord.isOpenDynamicFile;
config.taskWrapper = mTaskWrapper;
config.record = record;
config.stateHandler = mStateHandler;
config.peerIndex = indexId;
if (!config.tempFile.exists()) {
FileUtil.createFile(config.tempFile.getPath());
FileUtil.createFile(config.tempFile);
}
ThreadTask threadTask = new ThreadTask(config);
M3U8ThreadTaskAdapter adapter = new M3U8ThreadTaskAdapter(config);
@@ -163,10 +196,7 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
*
* @return {@code true} 合并成功,{@code false}合并失败
*/
public boolean mergeFile() {
if (getEntity().getM3U8Entity().isGenerateIndexFile()) {
return generateIndexFile();
}
boolean mergeFile() {
ITsMergeHandler mergeHandler = mM3U8Option.getMergeHandler();
String cacheDir = getCacheDir();
List<String> partPath = new ArrayList<>();
@@ -213,7 +243,7 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
/**
* 任务状态回调
*/
private IEventListener mListener;
private M3U8Listener mListener;
private long mProgress; //当前总进度
private Looper mLooper;
@@ -222,7 +252,7 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
*/
LiveStateManager(Looper looper, IEventListener listener) {
mLooper = looper;
mListener = listener;
mListener = (M3U8Listener) listener;
}
/**
@@ -234,6 +264,7 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
}
@Override public boolean handleMessage(Message msg) {
int peerIndex = msg.getData().getInt(ISchedulers.DATA_M3U8_PEER_INDEX);
switch (msg.what) {
case STATE_STOP:
if (isBreak()) {
@@ -248,15 +279,46 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
}
break;
case STATE_COMPLETE:
notifyLock();
notifyLock(true, peerIndex);
if (mM3U8Option.isGenerateIndexFile() && !isBreak()) {
addExtInf(mCurExtInfo.url, mCurExtInfo.extInf);
}
mListener.onPeerComplete(mTaskWrapper.getKey(),
msg.getData().getString(ISchedulers.DATA_M3U8_PEER_PATH), peerIndex);
break;
case STATE_RUNNING:
mProgress += (long) msg.obj;
break;
case STATE_FAIL:
notifyLock(false, peerIndex);
mListener.onPeerFail(mTaskWrapper.getKey(),
msg.getData().getString(ISchedulers.DATA_M3U8_PEER_PATH), peerIndex);
break;
}
return false;
}
/**
* 给索引文件添加extInfo信息
*/
private void addExtInf(String url, String extInf) {
File indexFile =
new File(String.format(M3U8_INDEX_FORMAT, getEntity().getFilePath()));
if (!indexFile.exists()) {
ALog.e(TAG, String.format("索引文件【%s】不存在添加peer的extInf失败", indexFile.getPath()));
return;
}
try {
if (mIndexFos == null) {
mIndexFos = new FileOutputStream(indexFile, true);
}
mIndexFos.write(extInf.concat("\r\n").getBytes(Charset.forName("UTF-8")));
mIndexFos.write(url.concat("\r\n").getBytes(Charset.forName("UTF-8")));
} catch (IOException e) {
e.printStackTrace();
}
}
@Override public boolean isFail() {
return false;
}
@@ -269,4 +331,14 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
return mProgress;
}
}
static class ExtInfo {
String url;
String extInf;
ExtInfo(String url, String extInf) {
this.url = url;
this.extInf = extInf;
}
}
}

View File

@@ -27,6 +27,7 @@ import com.arialyy.aria.core.processor.ILiveTsUrlConverter;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.exception.M3U8Exception;
import com.arialyy.aria.exception.TaskException;
import com.arialyy.aria.http.HttpTaskOption;
import com.arialyy.aria.m3u8.M3U8InfoThread;
import com.arialyy.aria.m3u8.M3U8Listener;
@@ -87,7 +88,7 @@ public class M3U8LiveUtil extends AbsNormalLoaderUtil {
}
});
infoThread.setOnGetPeerCallback(new M3U8InfoThread.OnGetLivePeerCallback() {
@Override public void onGetPeer(String url) {
@Override public void onGetPeer(String url, String extInf) {
if (mPeerUrls.contains(url)) {
return;
}
@@ -104,7 +105,7 @@ public class M3U8LiveUtil extends AbsNormalLoaderUtil {
fail(new M3U8Exception(TAG, String.format("ts地址错误url%s", url)), false);
return;
}
getLoader().offerPeer(url);
getLoader().offerPeer(new M3U8LiveLoader.ExtInfo(url, extInf));
}
});
return infoThread;
@@ -129,7 +130,13 @@ public class M3U8LiveUtil extends AbsNormalLoaderUtil {
if (mInfoThread != null) {
mInfoThread.setStop(true);
closeTimer();
if (mM3U8Option.isMergeFile()) {
if (((M3U8TaskOption) getTaskWrapper().getM3u8Option()).isGenerateIndexFile()) {
if (getLoader().generateIndexFile(true)) {
getListener().onComplete();
} else {
getListener().onFail(false, new TaskException(TAG, "创建索引文件失败"));
}
} else if (mM3U8Option.isMergeFile()) {
if (getLoader().mergeFile()) {
getListener().onComplete();
} else {

View File

@@ -31,14 +31,16 @@ import com.arialyy.aria.core.inf.IThreadState;
import com.arialyy.aria.core.listener.IEventListener;
import com.arialyy.aria.core.listener.ISchedulers;
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.m3u8.BaseM3U8Loader;
import com.arialyy.aria.core.processor.ITsMergeHandler;
import com.arialyy.aria.m3u8.M3U8Listener;
import com.arialyy.aria.m3u8.M3U8TaskOption;
import com.arialyy.aria.m3u8.M3U8ThreadTaskAdapter;
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;
@@ -219,6 +221,12 @@ public class M3U8VodLoader extends BaseM3U8Loader {
}
}
mManager.updateStateCount();
if (mCompleteNum <= 0) {
mListener.onStart(0);
} else {
int percent = mCompleteNum * 100 / mRecord.threadRecords.size();
mListener.onResume(percent);
}
}
/**
@@ -428,13 +436,12 @@ public class M3U8VodLoader extends BaseM3U8Loader {
config.url = record.tsUrl;
config.tempFile = new File(BaseM3U8Loader.getTsFilePath(cacheDir, record.threadId));
config.isBlock = mRecord.isBlock;
config.isOpenDynamicFile = mRecord.isOpenDynamicFile;
config.taskWrapper = mTaskWrapper;
config.record = record;
config.stateHandler = mStateHandler;
config.peerIndex = index;
if (!config.tempFile.exists()) {
FileUtil.createFile(config.tempFile.getPath());
FileUtil.createFile(config.tempFile);
}
ThreadTask threadTask = new ThreadTask(config);
M3U8ThreadTaskAdapter adapter = new M3U8ThreadTaskAdapter(config);
@@ -446,7 +453,7 @@ public class M3U8VodLoader extends BaseM3U8Loader {
* M3U8线程状态管理
*/
private class VodStateManager implements IThreadState {
private final String TAG = "M3U8ThreadStateManager";
private final String TAG = CommonUtil.getClassName(VodStateManager.class);
/**
* 任务状态回调
@@ -456,7 +463,8 @@ public class M3U8VodLoader extends BaseM3U8Loader {
private int cancelNum = 0; // 已经取消的线程的数
private int stopNum = 0; // 已经停止的线程数
private int failNum = 0; // 失败的线程数
private long progress; //当前总进度
private long percent; //当前总进度,百分比进度
private long progress;
private TaskRecord taskRecord; // 任务记录
private Looper looper;
@@ -473,6 +481,7 @@ public class M3U8VodLoader extends BaseM3U8Loader {
}
}
this.listener = listener;
progress = getEntity().getCurrentProgress();
}
private void updateStateCount() {
@@ -559,7 +568,14 @@ public class M3U8VodLoader extends BaseM3U8Loader {
"startThreadNum = %s, stopNum = %s, cancelNum = %s, failNum = %s, completeNum = %s, flagQueueSize = %s",
startThreadNum, stopNum, cancelNum, failNum, mCompleteNum, mFlagQueue.size()));
ALog.d(TAG, String.format("vod任务【%s】完成", mTempFile.getName()));
if (mM3U8Option.isMergeFile()) {
if (mM3U8Option.isGenerateIndexFile()) {
if (generateIndexFile(false)) {
listener.onComplete();
} else {
listener.onFail(false, new TaskException(TAG, "创建索引文件失败"));
}
} else if (mM3U8Option.isMergeFile()) {
if (mergeFile()) {
listener.onComplete();
} else {
@@ -596,6 +612,7 @@ public class M3U8VodLoader extends BaseM3U8Loader {
int percent = completeNum * 100 / taskRecord.threadRecords.size();
getEntity().setPercent(percent);
getEntity().update();
this.percent = percent;
}
@Override public boolean isFail() {
@@ -604,7 +621,11 @@ public class M3U8VodLoader extends BaseM3U8Loader {
}
@Override public boolean isComplete() {
return mCompleteNum == taskRecord.threadRecords.size() && !isJump;
if (mM3U8Option.isIgnoreFailureTs()) {
return mCompleteNum + failNum >= taskRecord.threadRecords.size() && !isJump;
} else {
return mCompleteNum == taskRecord.threadRecords.size() && !isJump;
}
}
@Override public long getCurrentProgress() {
@@ -625,9 +646,6 @@ public class M3U8VodLoader extends BaseM3U8Loader {
* @return {@code true} 合并成功,{@code false}合并失败
*/
private boolean mergeFile() {
if (getEntity().getM3U8Entity().isGenerateIndexFile()) {
return generateIndexFile();
}
ITsMergeHandler mergeHandler = mM3U8Option.getMergeHandler();
String cacheDir = getCacheDir();
List<String> partPath = new ArrayList<>();

View File

@@ -1,3 +0,0 @@
<resources>
<string name="app_name">M3U8Component</string>
</resources>

Some files were not shown because too many files have changed in this diff Show More