修复组合任务初始化失败时,无法删除的问题

修复`reStart()`后,无法停止的问题
ftp增加主动模式,开启主动模式:https://aria.laoyuyu.me/aria_doc/api/ftp_params.html
优化提示
pull/617/head
laoyuyu 5 years ago
parent f3d5e0135a
commit 0d93953cd9
  1. 3
      AppFrame/src/main/java/com/arialyy/frame/util/RegularExpression.java
  2. 6
      Aria/src/main/java/com/arialyy/aria/core/command/ReStartCmd.java
  3. 4
      Aria/src/main/java/com/arialyy/aria/core/common/AbsNormalTarget.java
  4. 60
      Aria/src/main/java/com/arialyy/aria/core/common/FtpOption.java
  5. 7
      Aria/src/main/java/com/arialyy/aria/core/common/controller/BuilderController.java
  6. 24
      Aria/src/main/java/com/arialyy/aria/core/common/controller/FeatureController.java
  7. 2
      Aria/src/main/java/com/arialyy/aria/core/common/controller/INormalFeature.java
  8. 16
      Aria/src/main/java/com/arialyy/aria/core/common/controller/NormalController.java
  9. 18
      Aria/src/main/java/com/arialyy/aria/core/download/CheckDEntityUtil.java
  10. 13
      Aria/src/main/java/com/arialyy/aria/core/download/CheckDGEntityUtil.java
  11. 9
      Aria/src/main/java/com/arialyy/aria/core/download/CheckFtpDirEntityUtil.java
  12. 20
      Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java
  13. 21
      Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
  14. 8
      Aria/src/main/java/com/arialyy/aria/core/upload/CheckUEntityUtil.java
  15. 4
      DEV_LOG.md
  16. 23
      FtpComponent/src/main/java/aria/apache/commons/net/ftp/FTPClient.java
  17. 172
      FtpComponent/src/main/java/com/arialyy/aria/ftp/AbsFtpInfoThread.java
  18. 13
      FtpComponent/src/main/java/com/arialyy/aria/ftp/BaseFtpThreadTaskAdapter.java
  19. 9
      FtpComponent/src/main/java/com/arialyy/aria/ftp/FtpDirInfoThread.java
  20. 51
      FtpComponent/src/main/java/com/arialyy/aria/ftp/FtpTaskOption.java
  21. 4
      HttpComponent/src/main/java/com/arialyy/aria/http/HttpFileInfoThread.java
  22. 14
      PublicComponent/src/main/java/com/arialyy/aria/core/common/ErrorCode.java
  23. 30
      PublicComponent/src/main/java/com/arialyy/aria/core/common/FtpConnectionMode.java
  24. 1
      PublicComponent/src/main/java/com/arialyy/aria/core/common/RecordHandler.java
  25. 41
      PublicComponent/src/main/java/com/arialyy/aria/util/CheckUtil.java
  26. 12
      app/src/main/java/com/arialyy/simple/core/download/FtpDownloadActivity.java
  27. 3
      app/src/main/java/com/arialyy/simple/core/download/FtpDownloadModule.java
  28. 5
      app/src/main/java/com/arialyy/simple/core/download/HttpDownloadModule.java
  29. 12
      app/src/main/java/com/arialyy/simple/core/download/SingleTaskActivity.java
  30. 2
      app/src/main/java/com/arialyy/simple/core/download/mutil/DownloadAdapter.java
  31. 2
      app/src/main/java/com/arialyy/simple/core/download/mutil/FileListAdapter.java
  32. 10
      app/src/main/res/layout/activity_ftp_download.xml
  33. 6
      app/src/main/res/layout/activity_single.xml

@ -92,5 +92,6 @@ public class RegularExpression {
/** /**
* IP * 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}";
} }

@ -15,9 +15,9 @@
*/ */
package com.arialyy.aria.core.command; 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.task.AbsTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; 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(); task = createTask();
} }
if (task != null) { if (task != null) {
task.cancel(TaskSchedulerType.TYPE_CANCEL_AND_NOT_NOTIFY); mQueue.cancelTask(task, TaskSchedulerType.TYPE_CANCEL_AND_NOT_NOTIFY);
task.start(TaskSchedulerType.TYPE_START_AND_RESET_STATE); mQueue.startTask(task, TaskSchedulerType.TYPE_START_AND_RESET_STATE);
} }
} }
} }

@ -202,8 +202,8 @@ public abstract class AbsNormalTarget<TARGET extends AbsNormalTarget> extends Ab
* 重新下载 * 重新下载
*/ */
@Override @Override
public void reStart() { public long reStart() {
getController().reStart(); return getController().reStart();
} }
@Override @Override

@ -33,6 +33,9 @@ public class FtpOption extends BaseOption {
private String protocol, keyAlias, storePass, storePath; private String protocol, keyAlias, storePass, storePath;
private boolean isImplicit = true; private boolean isImplicit = true;
private IFtpUploadInterceptor uploadInterceptor; private IFtpUploadInterceptor uploadInterceptor;
private int connMode = FtpConnectionMode.DATA_CONNECTION_MODE_PASV;
private int minPort, maxPort;
private String activeExternalIPAddress;
public FtpOption() { public FtpOption() {
super(); super();
@ -143,6 +146,63 @@ public class FtpOption extends BaseOption {
return this; 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) { public void setUrlEntity(FtpUrlEntity urlEntity) {
this.urlEntity = urlEntity; this.urlEntity = urlEntity;
urlEntity.needLogin = isNeedLogin; urlEntity.needLogin = isNeedLogin;

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

@ -43,6 +43,17 @@ import java.lang.reflect.InvocationTargetException;
* 功能控制器 * 功能控制器
*/ */
public abstract class FeatureController { 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 final String TAG;
private AbsTaskWrapper mTaskWrapper; private AbsTaskWrapper mTaskWrapper;
@ -50,6 +61,7 @@ public abstract class FeatureController {
* 是否忽略权限检查 true 忽略权限检查 * 是否忽略权限检查 true 忽略权限检查
*/ */
private boolean ignoreCheckPermissions = false; private boolean ignoreCheckPermissions = false;
private int action = ACTION_DEF;
FeatureController(AbsTaskWrapper wrapper) { FeatureController(AbsTaskWrapper wrapper) {
mTaskWrapper = wrapper; mTaskWrapper = wrapper;
@ -91,6 +103,10 @@ public abstract class FeatureController {
return null; return null;
} }
void setAction(int action) {
this.action = action;
}
/** /**
* 是否忽略权限检查 * 是否忽略权限检查
*/ */
@ -180,15 +196,15 @@ public abstract class FeatureController {
private boolean checkEntity() { private boolean checkEntity() {
ICheckEntityUtil checkUtil = null; ICheckEntityUtil checkUtil = null;
if (mTaskWrapper instanceof DTaskWrapper) { if (mTaskWrapper instanceof DTaskWrapper) {
checkUtil = CheckDEntityUtil.newInstance((DTaskWrapper) mTaskWrapper); checkUtil = CheckDEntityUtil.newInstance((DTaskWrapper) mTaskWrapper, action);
} else if (mTaskWrapper instanceof DGTaskWrapper) { } else if (mTaskWrapper instanceof DGTaskWrapper) {
if (mTaskWrapper.getRequestType() == ITaskWrapper.D_FTP_DIR) { 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) { } else if (mTaskWrapper.getRequestType() == ITaskWrapper.DG_HTTP) {
checkUtil = CheckDGEntityUtil.newInstance((DGTaskWrapper) mTaskWrapper); checkUtil = CheckDGEntityUtil.newInstance((DGTaskWrapper) mTaskWrapper, action);
} }
} else if (mTaskWrapper instanceof UTaskWrapper) { } else if (mTaskWrapper instanceof UTaskWrapper) {
checkUtil = CheckUEntityUtil.newInstance((UTaskWrapper) mTaskWrapper); checkUtil = CheckUEntityUtil.newInstance((UTaskWrapper) mTaskWrapper, action);
} }
return checkUtil != null && checkUtil.checkEntity(); return checkUtil != null && checkUtil.checkEntity();
} }

@ -59,7 +59,7 @@ public interface INormalFeature {
/** /**
* 重新下载 * 重新下载
*/ */
void reStart(); long reStart();
/** /**
* 保存数据 * 保存数据

@ -38,6 +38,7 @@ public final class NormalController extends FeatureController implements INormal
*/ */
@Override @Override
public void stop() { public void stop() {
setAction(ACTION_STOP);
if (checkConfig()) { if (checkConfig()) {
EventMsgUtil.getDefault() EventMsgUtil.getDefault()
.post(CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_STOP, .post(CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_STOP,
@ -60,6 +61,7 @@ public final class NormalController extends FeatureController implements INormal
* @param newStart true 立即将任务恢复到执行队列中 * @param newStart true 立即将任务恢复到执行队列中
*/ */
@Override public void resume(boolean newStart) { @Override public void resume(boolean newStart) {
setAction(ACTION_RESUME);
if (checkConfig()) { if (checkConfig()) {
StartCmd cmd = StartCmd cmd =
(StartCmd) CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_START, (StartCmd) CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_START,
@ -75,11 +77,7 @@ public final class NormalController extends FeatureController implements INormal
*/ */
@Override @Override
public void cancel() { public void cancel() {
if (checkConfig()) { cancel(false);
EventMsgUtil.getDefault()
.post(CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_CANCEL,
checkTaskType()));
}
} }
/** /**
@ -87,6 +85,7 @@ public final class NormalController extends FeatureController implements INormal
*/ */
@Override @Override
public void reTry() { public void reTry() {
setAction(ACTION_RETRY);
if (checkConfig()) { if (checkConfig()) {
int taskType = checkTaskType(); int taskType = checkTaskType();
EventMsgUtil.getDefault() EventMsgUtil.getDefault()
@ -105,6 +104,7 @@ public final class NormalController extends FeatureController implements INormal
*/ */
@Override @Override
public void cancel(boolean removeFile) { public void cancel(boolean removeFile) {
setAction(ACTION_CANCEL);
if (checkConfig()) { if (checkConfig()) {
CancelCmd cancelCmd = CancelCmd cancelCmd =
(CancelCmd) CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_CANCEL, (CancelCmd) CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_CANCEL,
@ -118,15 +118,19 @@ public final class NormalController extends FeatureController implements INormal
* 重新下载 * 重新下载
*/ */
@Override @Override
public void reStart() { public long reStart() {
setAction(ACTION_RESTART);
if (checkConfig()) { if (checkConfig()) {
EventMsgUtil.getDefault() EventMsgUtil.getDefault()
.post(CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_RESTART, .post(CmdHelper.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_RESTART,
checkTaskType())); checkTaskType()));
return getEntity().getId();
} }
return -1;
} }
@Override public void save() { @Override public void save() {
setAction(ACTION_SAVE);
if (!checkConfig()) { if (!checkConfig()) {
ALog.e(TAG, "保存修改失败"); ALog.e(TAG, "保存修改失败");
} else { } else {

@ -16,6 +16,7 @@
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.common.controller.FeatureController;
import com.arialyy.aria.core.inf.ICheckEntityUtil; import com.arialyy.aria.core.inf.ICheckEntityUtil;
import com.arialyy.aria.core.inf.IOptionConstant; import com.arialyy.aria.core.inf.IOptionConstant;
import com.arialyy.aria.core.inf.ITargetHandler; import com.arialyy.aria.core.inf.ITargetHandler;
@ -34,12 +35,14 @@ public class CheckDEntityUtil implements ICheckEntityUtil {
private final String TAG = CommonUtil.getClassName(getClass()); private final String TAG = CommonUtil.getClassName(getClass());
private DTaskWrapper mWrapper; private DTaskWrapper mWrapper;
private DownloadEntity mEntity; private DownloadEntity mEntity;
private int action;
public static CheckDEntityUtil newInstance(DTaskWrapper wrapper) { public static CheckDEntityUtil newInstance(DTaskWrapper wrapper, int action) {
return new CheckDEntityUtil(wrapper); return new CheckDEntityUtil(wrapper, action);
} }
private CheckDEntityUtil(DTaskWrapper wrapper) { private CheckDEntityUtil(DTaskWrapper wrapper, int action) {
this.action = action;
mWrapper = wrapper; mWrapper = wrapper;
mEntity = mWrapper.getEntity(); mEntity = mWrapper.getEntity();
} }
@ -80,19 +83,22 @@ public class CheckDEntityUtil implements ICheckEntityUtil {
} else { } else {
m3U8Entity.update(); m3U8Entity.update();
} }
if (mWrapper.getRequestType() == ITaskWrapper.M3U8_VOD) { if (mWrapper.getRequestType() == ITaskWrapper.M3U8_VOD
&& action == FeatureController.ACTION_CREATE) {
if (mEntity.getFileSize() == 0) { if (mEntity.getFileSize() == 0) {
ALog.w(TAG, ALog.w(TAG,
"由于m3u8协议的特殊性质,无法有效快速获取到正确到文件长度,如果你需要显示文件中长度,你需要自行设置文件长度:.asM3U8().asVod().setFileSize(xxx)"); "由于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()) { if (file.exists()) {
ALog.w(TAG, "对于直播来说,每次下载都是一个新文件,所以你需要设置新都文件路径,否则Aria框架将会覆盖已下载的文件"); ALog.w(TAG, "对于直播来说,每次下载都是一个新文件,所以你需要设置新都文件路径,否则Aria框架将会覆盖已下载的文件");
file.delete(); file.delete();
} }
} }
if (mWrapper.getM3U8Params().getHandler(IOptionConstant.bandWidthUrlConverter) != null if (action != FeatureController.ACTION_CANCEL
&& mWrapper.getM3U8Params().getHandler(IOptionConstant.bandWidthUrlConverter) != null
&& bandWidth == 0) { && bandWidth == 0) {
ALog.w(TAG, "你已经设置了码率url转换器,但是没有设置码率,Aria框架将采用第一个获取到的码率"); ALog.w(TAG, "你已经设置了码率url转换器,但是没有设置码率,Aria框架将采用第一个获取到的码率");
} }

@ -17,6 +17,7 @@ package com.arialyy.aria.core.download;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.common.RequestEnum; 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.ICheckEntityUtil;
import com.arialyy.aria.core.inf.IOptionConstant; import com.arialyy.aria.core.inf.IOptionConstant;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
@ -41,12 +42,14 @@ public class CheckDGEntityUtil implements ICheckEntityUtil {
* 是否需要修改路径 * 是否需要修改路径
*/ */
private boolean needModifyPath = false; private boolean needModifyPath = false;
private int action;
public static CheckDGEntityUtil newInstance(DGTaskWrapper wrapper) { public static CheckDGEntityUtil newInstance(DGTaskWrapper wrapper, int action) {
return new CheckDGEntityUtil(wrapper); return new CheckDGEntityUtil(wrapper, action);
} }
private CheckDGEntityUtil(DGTaskWrapper wrapper) { private CheckDGEntityUtil(DGTaskWrapper wrapper, int action) {
this.action = action;
mWrapper = wrapper; mWrapper = wrapper;
mEntity = mWrapper.getEntity(); mEntity = mWrapper.getEntity();
} }
@ -129,7 +132,9 @@ public class CheckDGEntityUtil implements ICheckEntityUtil {
return false; return false;
} }
if (!mWrapper.isUnknownSize() && mEntity.getFileSize() == 0) { if (action != FeatureController.ACTION_CANCEL
&& !mWrapper.isUnknownSize()
&& mEntity.getFileSize() == 0) {
ALog.e(TAG, "组合任务必须设置文件文件大小,默认需要强制设置文件大小。如果无法获取到总长度,请调用#unknownSize()来标志该组合任务"); ALog.e(TAG, "组合任务必须设置文件文件大小,默认需要强制设置文件大小。如果无法获取到总长度,请调用#unknownSize()来标志该组合任务");
return false; return false;
} }

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

@ -16,10 +16,6 @@
package com.arialyy.aria.core.queue; 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.IEntity;
import com.arialyy.aria.core.inf.TaskSchedulerType; import com.arialyy.aria.core.inf.TaskSchedulerType;
import com.arialyy.aria.core.manager.TaskWrapperManager; 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.DGLoadSharePool;
import com.arialyy.aria.core.queue.pool.DLoadSharePool; import com.arialyy.aria.core.queue.pool.DLoadSharePool;
import com.arialyy.aria.core.queue.pool.UploadSharePool; 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.task.UploadTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
/** /**
@ -213,6 +213,10 @@ public abstract class AbsTaskQueue<TASK extends AbsTask, TASK_WRAPPER extends Ab
} }
@Override public void startTask(TASK task) { @Override public void startTask(TASK task) {
startTask(task, TaskSchedulerType.TYPE_DEFAULT);
}
@Override public void startTask(TASK task, int action) {
if (task == null) { if (task == null) {
ALog.w(TAG, "create fail, task is null"); ALog.w(TAG, "create fail, task is null");
} }
@ -223,7 +227,7 @@ public abstract class AbsTaskQueue<TASK extends AbsTask, TASK_WRAPPER extends Ab
mCachePool.removeTask(task); mCachePool.removeTask(task);
mExecutePool.putTask(task); mExecutePool.putTask(task);
task.getTaskWrapper().getEntity().setFailNum(0); task.getTaskWrapper().getEntity().setFailNum(0);
task.start(); task.start(action);
} }
@Override public void stopTask(TASK task) { @Override public void stopTask(TASK task) {
@ -312,7 +316,11 @@ public abstract class AbsTaskQueue<TASK extends AbsTask, TASK_WRAPPER extends Ab
} }
@Override public void cancelTask(TASK task) { @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() { @Override public TASK getNextTask() {

@ -17,13 +17,14 @@
package com.arialyy.aria.core.queue; package com.arialyy.aria.core.queue;
import com.arialyy.aria.core.download.DGTaskWrapper; 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.DownloadGroupTask;
import com.arialyy.aria.core.task.DownloadTask; 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.ITask;
import com.arialyy.aria.core.task.UploadTask; import com.arialyy.aria.core.task.UploadTask;
import com.arialyy.aria.core.upload.UTaskWrapper; import com.arialyy.aria.core.upload.UTaskWrapper;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
/** /**
* Created by lyy on 2016/8/16. 任务功能接口 * 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); 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); void stopTask(TASK task);
/** /**
* 取消下载任务 * 取消任务
* *
* @param task {@link DownloadTask}{@link UploadTask}{@link DownloadGroupTask} * @param task {@link DownloadTask}{@link UploadTask}{@link DownloadGroupTask}
*/ */
void cancelTask(TASK task); void cancelTask(TASK task);
/**
* 取消任务
*
* @param action {@link TaskSchedulerType}
*/
void cancelTask(TASK task, int action);
/** /**
* 通过key从队列中删除任务 * 通过key从队列中删除任务
* *

@ -25,12 +25,14 @@ public class CheckUEntityUtil implements ICheckEntityUtil {
private final String TAG = "CheckUEntityUtil"; private final String TAG = "CheckUEntityUtil";
private UTaskWrapper mWrapper; private UTaskWrapper mWrapper;
private UploadEntity mEntity; private UploadEntity mEntity;
private int action;
public static CheckUEntityUtil newInstance(UTaskWrapper wrapper) { public static CheckUEntityUtil newInstance(UTaskWrapper wrapper, int action) {
return new CheckUEntityUtil(wrapper); return new CheckUEntityUtil(wrapper, action);
} }
private CheckUEntityUtil(UTaskWrapper wrapper) { private CheckUEntityUtil(UTaskWrapper wrapper, int action) {
this.action = action;
mWrapper = wrapper; mWrapper = wrapper;
mEntity = mWrapper.getEntity(); mEntity = mWrapper.getEntity();
} }

@ -5,6 +5,10 @@
- m3u8协议的key信息增加了`keyFormat`,`keyFormatVersion`字段 - m3u8协议的key信息增加了`keyFormat`,`keyFormatVersion`字段
- m3u8增加了`ignoreFailureTs`方法,忽略虾类失败的ts切片 - m3u8增加了`ignoreFailureTs`方法,忽略虾类失败的ts切片
- 修复在dialogFragment的`onCreateDialog()`注册导致的注解不生效问题 - 修复在dialogFragment的`onCreateDialog()`注册导致的注解不生效问题
- 修复组合任务初始化失败时,无法删除的问题
- 修复`reStart()`后,无法停止的问题
- ftp增加主动模式,开启主动模式:https://aria.laoyuyu.me/aria_doc/api/ftp_params.html
- 优化提示
+ v_3.7.10 (2019/12/3) + 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/543#issuecomment-559733124
- fix bug https://github.com/AriaLyy/Aria/issues/542 - fix bug https://github.com/AriaLyy/Aria/issues/542

@ -16,8 +16,13 @@
*/ */
package aria.apache.commons.net.ftp; package aria.apache.commons.net.ftp;
import aria.apache.commons.net.MalformedServerReplyException;
import aria.apache.commons.net.SocketClient; 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.ftp.parser.ParserInitializationException;
import aria.apache.commons.net.io.CRLFLineReader;
import aria.apache.commons.net.io.CopyStreamAdapter; import aria.apache.commons.net.io.CopyStreamAdapter;
import aria.apache.commons.net.io.CopyStreamEvent; import aria.apache.commons.net.io.CopyStreamEvent;
import aria.apache.commons.net.io.CopyStreamException; import aria.apache.commons.net.io.CopyStreamException;
@ -53,12 +58,6 @@ import java.util.Properties;
import java.util.Random; import java.util.Random;
import java.util.Set; 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 * FTPClient encapsulates all the functionality necessary to store and
* retrieve files from an FTP server. This class takes care of all * 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 { private boolean initFeatureMap() throws IOException {
if (__featuresMap == null) { if (__featuresMap == null) {
// Don't create map here, because next line may throw exception // 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)); boolean success = FTPReply.isPositiveCompletion(sendCommand(FTPCmd.MLST, pathname));
if (success) { if (success) {
String reply = getReplyStrings()[1]; String reply = getReplyStrings()[1];
/* check the response makes sense. /* check the response makes sense.
* Must have space before fact(s) and between fact(s) and filename * Must have space before fact(s) and between fact(s) and filename
* Fact(s) can be absent, so at least 3 chars are needed. * Fact(s) can be absent, so at least 3 chars are needed.
*/ */
if (reply.length() < 3 || reply.charAt(0) != ' ') { if (reply.length() < 3 || reply.charAt(0) != ' ') {
throw new MalformedServerReplyException("Invalid server reply (MLST): '" + reply + "'"); throw new MalformedServerReplyException("Invalid server reply (MLST): '" + reply + "'");
} }

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

@ -22,6 +22,7 @@ import aria.apache.commons.net.ftp.FTPClientConfig;
import aria.apache.commons.net.ftp.FTPReply; import aria.apache.commons.net.ftp.FTPReply;
import aria.apache.commons.net.ftp.FTPSClient; import aria.apache.commons.net.ftp.FTPSClient;
import com.arialyy.aria.core.FtpUrlEntity; 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.common.SubThreadConfig;
import com.arialyy.aria.core.task.AbsThreadTaskAdapter; import com.arialyy.aria.core.task.AbsThreadTaskAdapter;
import com.arialyy.aria.exception.AriaIOException; import com.arialyy.aria.exception.AriaIOException;
@ -118,7 +119,17 @@ public abstract class BaseFtpThreadTaskAdapter extends AbsThreadTaskAdapter {
client.setControlEncoding(charSet); client.setControlEncoding(charSet);
client.setDataTimeout(getTaskConfig().getIOTimeOut()); client.setDataTimeout(getTaskConfig().getIOTimeOut());
client.setConnectTimeout(getTaskConfig().getConnectTimeOut()); 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.setFileType(FTP.BINARY_FILE_TYPE);
client.setControlKeepAliveTimeout(5000); client.setControlKeepAliveTimeout(5000);
} catch (IOException e) { } catch (IOException e) {

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

@ -17,9 +17,10 @@ package com.arialyy.aria.ftp;
import aria.apache.commons.net.ftp.FTPClientConfig; import aria.apache.commons.net.ftp.FTPClientConfig;
import com.arialyy.aria.core.FtpUrlEntity; 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.FtpInterceptHandler;
import com.arialyy.aria.core.processor.IFtpUploadInterceptor; import com.arialyy.aria.core.processor.IFtpUploadInterceptor;
import com.arialyy.aria.core.inf.ITaskOption;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
import java.net.Proxy; import java.net.Proxy;
@ -55,6 +56,54 @@ public class FtpTaskOption implements ITaskOption {
*/ */
private FTPClientConfig clientConfig; 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() { public FTPClientConfig getClientConfig() {
return clientConfig; return clientConfig;
} }

@ -24,8 +24,8 @@ import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.RequestEnum; import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity; 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.inf.OnFileInfoCallback;
import com.arialyy.aria.core.processor.IHttpFileLenAdapter;
import com.arialyy.aria.exception.AriaIOException; import com.arialyy.aria.exception.AriaIOException;
import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.exception.TaskException; import com.arialyy.aria.exception.TaskException;
@ -214,7 +214,7 @@ public class HttpFileInfoThread implements Runnable {
} else { } else {
failDownload(new AriaIOException(TAG, failDownload(new AriaIOException(TAG,
String.format("任务下载失败,errorCode:%s, errorMsg: %s, url: %s", code, String.format("任务下载失败,errorCode:%s, errorMsg: %s, url: %s", code,
conn.getResponseMessage(), mEntity.getUrl())), true); conn.getResponseMessage(), mEntity.getUrl())), !CheckUtil.httpIsBadRequest(code));
} }
if (end) { if (end) {
taskOption.setChunked(isChunked); taskOption.setChunked(isChunked);

@ -1,13 +1,11 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 * 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 * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,

@ -0,0 +1,30 @@
/*
* 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.common;
/**
* FTP 连接模式
*/
public interface FtpConnectionMode {
/**
* 被动模式
*/
int DATA_CONNECTION_MODE_PASV = 0;
/**
* 主动模式
*/
int DATA_CONNECTION_MODE_ACTIVITY = 1;
}

@ -73,6 +73,7 @@ public class RecordHandler implements IRecordHandler {
mAdapter.onPre(); mAdapter.onPre();
mTaskRecord = DbDataHelper.getTaskRecord(getFilePath()); mTaskRecord = DbDataHelper.getTaskRecord(getFilePath());
if (mTaskRecord == null) { if (mTaskRecord == null) {
FileUtil.createFile(getFilePath());
initRecord(true); initRecord(true);
} else { } else {
File file = new File(mTaskRecord.filePath); File file = new File(mTaskRecord.filePath);

@ -23,7 +23,10 @@ import com.arialyy.aria.core.inf.IRecordHandler;
import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.net.HttpURLConnection;
import java.util.List; import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* Created by Lyy on 2016/9/23. * Created by Lyy on 2016/9/23.
@ -32,6 +35,44 @@ import java.util.List;
public class CheckUtil { public class CheckUtil {
private static final String TAG = "CheckUtil"; private static final String TAG = "CheckUtil";
/**
* 检查ip是否正确
*
* @param ip ipv4 地址
* @return {@code true} ip 正确{@code false} ip 错误
*/
public static boolean checkIp(String ip) {
if (TextUtils.isEmpty(ip) || ip.length() < 7 || ip.length() > 15) {
return false;
}
Pattern p = Pattern.compile(Regular.REG_IP_V4);
Matcher m = p.matcher(ip);
return m.find() && m.groupCount() > 0;
}
/**
* 判断http请求是否有效
* {@link HttpURLConnection#HTTP_BAD_GATEWAY} or {@link HttpURLConnection#HTTP_BAD_METHOD}
* or {@link HttpURLConnection#HTTP_BAD_REQUEST} 无法重试
*
* @param errorCode http 返回码
* @return {@code true} 无效请求{@code false} 有效请求
*/
public static boolean httpIsBadRequest(int errorCode) {
return errorCode == HttpURLConnection.HTTP_BAD_GATEWAY
|| errorCode == HttpURLConnection.HTTP_BAD_METHOD
|| errorCode == HttpURLConnection.HTTP_BAD_REQUEST;
}
/**
* 判断ftp请求是否有效
*
* @return {@code true} 无效请求{@code false} 有效请求
*/
public static boolean ftpIsBadRequest(int errorCode) {
return errorCode >= 400 && errorCode < 600;
}
/** /**
* 检查和处理下载任务的路径冲突 * 检查和处理下载任务的路径冲突
* *

@ -23,6 +23,7 @@ import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders; import androidx.lifecycle.ViewModelProviders;
import com.arialyy.annotations.Download; import com.arialyy.annotations.Download;
import com.arialyy.aria.core.Aria; import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.common.FtpConnectionMode;
import com.arialyy.aria.core.common.FtpOption; import com.arialyy.aria.core.common.FtpOption;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
@ -80,11 +81,11 @@ public class FtpDownloadActivity extends BaseActivity<ActivityFtpDownloadBinding
} }
}); });
getBinding().setViewModel(this); getBinding().setViewModel(this);
try { //try {
getBinding().codeView.setSource(AppUtil.getHelpCode(this, "FtpDownload.java")); // getBinding().codeView.setSource(AppUtil.getHelpCode(this, "FtpDownload.java"));
} catch (IOException e) { //} catch (IOException e) {
e.printStackTrace(); // e.printStackTrace();
} //}
} }
public void onClick(View view) { public void onClick(View view) {
@ -123,6 +124,7 @@ public class FtpDownloadActivity extends BaseActivity<ActivityFtpDownloadBinding
private FtpOption getFtpOption() { private FtpOption getFtpOption() {
FtpOption option = new FtpOption(); FtpOption option = new FtpOption();
option.login(user, passw); option.login(user, passw);
option.setConnectionMode(FtpConnectionMode.DATA_CONNECTION_MODE_ACTIVITY);
return option; return option;
} }

@ -47,7 +47,8 @@ public class FtpDownloadModule extends BaseViewModule {
* *
*/ */
LiveData<DownloadEntity> getFtpDownloadInfo(Context context) { LiveData<DownloadEntity> getFtpDownloadInfo(Context context) {
String url = AppUtil.getConfigValue(context, FTP_URL_KEY, ftpDefUrl); //String url = AppUtil.getConfigValue(context, FTP_URL_KEY, ftpDefUrl);
String url = "ftp://9.9.9.72:2121/Cyberduck-6.9.4.30164.zip";
String filePath = AppUtil.getConfigValue(context, FTP_PATH_KEY, ftpDefPath); String filePath = AppUtil.getConfigValue(context, FTP_PATH_KEY, ftpDefPath);
singDownloadInfo = Aria.download(context).getFirstDownloadEntity(url); singDownloadInfo = Aria.download(context).getFirstDownloadEntity(url);

@ -54,11 +54,12 @@ public class HttpDownloadModule extends BaseViewModule {
//String url = "http://image.totwoo.com/totwoo-TOTWOO-v3.5.6.apk"; //String url = "http://image.totwoo.com/totwoo-TOTWOO-v3.5.6.apk";
//String url = "http://fdfs.speedata.cn:9989/group1/M00/00/05/rBGFrl3fdAKAVJwfMtSa9R18wLU139.zip"; //String url = "http://fdfs.speedata.cn:9989/group1/M00/00/05/rBGFrl3fdAKAVJwfMtSa9R18wLU139.zip";
//String url = "http://9.9.9.28:8088/files/update.zip"; //String url = "http://9.9.9.28:8088/files/update.zip";
String url = "https://ss1.baidu.com/-4o3dSag_xI4khGko9WTAnF6hhy/image/h%3D300/sign=a9e671b9a551f3dedcb2bf64a4eff0ec/4610b912c8fcc3cef70d70409845d688d53f20f7.jpg"; //String url = "https://ss1.baidu.com/-4o3dSag_xI4khGko9WTAnF6hhy/image/h%3D300/sign=a9e671b9a551f3dedcb2bf64a4eff0ec/4610b912c8fcc3cef70d70409845d688d53f20f7.jpg";
//String url = "https://imtt.dd.qq.com/16891/apk/70BFFDB05AB8686F2A4CF3E07588A377.apk?fsname=com.tencent.tmgp.speedmobile_1.16.0.33877_1160033877.apk&csr=1bbd"; //String url = "https://imtt.dd.qq.com/16891/apk/70BFFDB05AB8686F2A4CF3E07588A377.apk?fsname=com.tencent.tmgp.speedmobile_1.16.0.33877_1160033877.apk&csr=1bbd";
//String url = "https://ss1.baidu.com/-4o3dSag_xI4khGko9WTAnF6hhy/image/h%3D300/sign=a9e671b9a551f3dedcb2bf64a4eff0ec/4610b912c8fcc3cef70d70409845d688d53f20f7.jpg"; //String url = "https://ss1.baidu.com/-4o3dSag_xI4khGko9WTAnF6hhy/image/h%3D300/sign=a9e671b9a551f3dedcb2bf64a4eff0ec/4610b912c8fcc3cef70d70409845d688d53f20f7.jpg";
//String filePath = AppUtil.getConfigValue(context, HTTP_PATH_KEY, defFilePath); //String filePath = AppUtil.getConfigValue(context, HTTP_PATH_KEY, defFilePath);
String filePath = "/mnt/sdcard/gg.png"; String url = "https://y.qq.com/download/import/QQMusic-import-1.2.1.zip";
String filePath = "/mnt/sdcard/QQMusic-import-1.2.1.zip";
//String filePath = "/mnt/sdcard/update.zip"; //String filePath = "/mnt/sdcard/update.zip";
singDownloadInfo = Aria.download(context).getFirstDownloadEntity(url); singDownloadInfo = Aria.download(context).getFirstDownloadEntity(url);

@ -32,6 +32,7 @@ import androidx.lifecycle.ViewModelProviders;
import com.arialyy.annotations.Download; import com.arialyy.annotations.Download;
import com.arialyy.aria.core.Aria; import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.common.HttpOption; import com.arialyy.aria.core.common.HttpOption;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.listener.ISchedulers; import com.arialyy.aria.core.listener.ISchedulers;
@ -116,11 +117,6 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
} }
}); });
getBinding().setViewModel(this); getBinding().setViewModel(this);
try {
getBinding().codeView.setSource(AppUtil.getHelpCode(this, "HttpDownload.java"));
} catch (IOException e) {
e.printStackTrace();
}
} }
public void chooseUrl() { public void chooseUrl() {
@ -279,10 +275,9 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
.load(mTaskId) .load(mTaskId)
.stop(); .stop();
} else { } else {
mUrl = "http://sdkdown.muzhiwan.com/openfile/2019/07/11/com.netease.syfz.mzw_5d26f8d9cee27.apk"; mTaskId = Aria.download(this).load(mTaskId)
Aria.download(this).load(mTaskId)
//.updateUrl(mUrl) //.updateUrl(mUrl)
.resume(); .reStart();
} }
break; break;
case R.id.cancel: case R.id.cancel:
@ -296,6 +291,7 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
option.addHeader("1", "@") option.addHeader("1", "@")
.useServerFileName(true) .useServerFileName(true)
.setFileLenAdapter(new FileLenAdapter()); .setFileLenAdapter(new FileLenAdapter());
//option.setRequestType(RequestEnum.POST);
mTaskId = Aria.download(SingleTaskActivity.this) mTaskId = Aria.download(SingleTaskActivity.this)
.load(mUrl) .load(mUrl)
.setFilePath(mFilePath, true) .setFilePath(mFilePath, true)

@ -298,7 +298,7 @@ public class DownloadAdapter extends AbsRVAdapter<AbsEntity, DownloadAdapter.Sim
Aria.download(getContext()).load(entity.getId()).cancel(true); Aria.download(getContext()).load(entity.getId()).cancel(true);
break; break;
case ITaskWrapper.DG_HTTP: case ITaskWrapper.DG_HTTP:
Aria.download(getContext()).load(entity.getId()).cancel(true); Aria.download(getContext()).loadGroup(entity.getId()).cancel(true);
break; break;
} }
} }

@ -24,6 +24,7 @@ import android.widget.Toast;
import com.arialyy.aria.core.Aria; import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.download.m3u8.M3U8VodOption; import com.arialyy.aria.core.download.m3u8.M3U8VodOption;
import com.arialyy.aria.core.processor.IVodTsUrlConverter; import com.arialyy.aria.core.processor.IVodTsUrlConverter;
import com.arialyy.aria.util.ALog;
import com.arialyy.simple.R; import com.arialyy.simple.R;
import com.arialyy.simple.base.adapter.AbsHolder; import com.arialyy.simple.base.adapter.AbsHolder;
import com.arialyy.simple.base.adapter.AbsRVAdapter; import com.arialyy.simple.base.adapter.AbsRVAdapter;
@ -88,6 +89,7 @@ final class FileListAdapter extends AbsRVAdapter<FileListEntity, FileListAdapter
.setGroupAlias(item.name) .setGroupAlias(item.name)
.unknownSize() .unknownSize()
.create(); .create();
ALog.d(TAG, "getGroupTaskList = " + Aria.download(this).getGroupTaskList().size());
break; break;
case 2: case 2:
M3U8VodOption option = new M3U8VodOption(); M3U8VodOption option = new M3U8VodOption();

@ -76,11 +76,11 @@
bind:stateStr="@{stateStr}" bind:stateStr="@{stateStr}"
/> />
<com.arialyy.simple.widget.CodeView <!-- <com.arialyy.simple.widget.CodeView-->
android:id="@+id/code_view" <!-- android:id="@+id/code_view"-->
android:layout_width="match_parent" <!-- android:layout_width="match_parent"-->
android:layout_height="match_parent" <!-- android:layout_height="match_parent"-->
/> <!-- />-->
</LinearLayout> </LinearLayout>
</layout> </layout>

@ -76,11 +76,5 @@
bind:stateStr="@{stateStr}" bind:stateStr="@{stateStr}"
/> />
<com.arialyy.simple.widget.CodeView
android:id="@+id/code_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout> </LinearLayout>
</layout> </layout>
Loading…
Cancel
Save