v3.6.6
laoyuyu 6 years ago
commit 5c6770bf5b
  1. 2
      Aria/build.gradle
  2. 12
      Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
  3. 3
      Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java
  4. 34
      Aria/src/main/java/com/arialyy/aria/core/FtpUrlEntity.java
  5. 1
      Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java
  6. 3
      Aria/src/main/java/com/arialyy/aria/core/command/AbsCmdFactory.java
  7. 8
      Aria/src/main/java/com/arialyy/aria/core/command/group/AbsGroupCmd.java
  8. 7
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCancelCmd.java
  9. 6
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCmdFactory.java
  10. 7
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java
  11. 7
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStopCmd.java
  12. 10
      Aria/src/main/java/com/arialyy/aria/core/command/normal/AbsNormalCmd.java
  13. 4
      Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java
  14. 7
      Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelAllCmd.java
  15. 8
      Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java
  16. 10
      Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java
  17. 19
      Aria/src/main/java/com/arialyy/aria/core/command/normal/NormalCmdFactory.java
  18. 11
      Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
  19. 15
      Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java
  20. 7
      Aria/src/main/java/com/arialyy/aria/core/command/normal/StopAllCmd.java
  21. 10
      Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java
  22. 26
      Aria/src/main/java/com/arialyy/aria/core/common/AEvent.java
  23. 335
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
  24. 252
      Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java
  25. 104
      Aria/src/main/java/com/arialyy/aria/core/common/BandwidthLimiter.java
  26. 145
      Aria/src/main/java/com/arialyy/aria/core/common/BaseListener.java
  27. 6
      Aria/src/main/java/com/arialyy/aria/core/common/IUtil.java
  28. 6
      Aria/src/main/java/com/arialyy/aria/core/common/OnFileInfoCallback.java
  29. 39
      Aria/src/main/java/com/arialyy/aria/core/common/ProtocolType.java
  30. 90
      Aria/src/main/java/com/arialyy/aria/core/common/ProxyHelper.java
  31. 11
      Aria/src/main/java/com/arialyy/aria/core/common/StateConstance.java
  32. 4
      Aria/src/main/java/com/arialyy/aria/core/common/SubThreadConfig.java
  33. 5
      Aria/src/main/java/com/arialyy/aria/core/common/ThreadRecord.java
  34. 78
      Aria/src/main/java/com/arialyy/aria/core/common/ThreadTaskManager.java
  35. 130
      Aria/src/main/java/com/arialyy/aria/core/common/ftp/AbsFtpInfoThread.java
  36. 70
      Aria/src/main/java/com/arialyy/aria/core/common/ftp/AbsFtpThreadTask.java
  37. 104
      Aria/src/main/java/com/arialyy/aria/core/common/ftp/FTPSConfig.java
  38. 38
      Aria/src/main/java/com/arialyy/aria/core/common/ftp/FtpDelegate.java
  39. 52
      Aria/src/main/java/com/arialyy/aria/core/common/ftp/SSLSessionReuseFTPSClient.java
  40. 39
      Aria/src/main/java/com/arialyy/aria/core/common/http/HttpHeaderDelegate.java
  41. 86
      Aria/src/main/java/com/arialyy/aria/core/common/http/PostDelegate.java
  42. 11
      Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java
  43. 119
      Aria/src/main/java/com/arialyy/aria/core/download/BaseDListener.java
  44. 2
      Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java
  45. 16
      Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java
  46. 45
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupListener.java
  47. 73
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java
  48. 57
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java
  49. 53
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java
  50. 63
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java
  51. 93
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java
  52. 5
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java
  53. 55
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java
  54. 40
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java
  55. 96
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java
  56. 67
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java
  57. 15
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java
  58. 30
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java
  59. 7
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java
  60. 6
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java
  61. 16
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpFileInfoThread.java
  62. 82
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java
  63. 102
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java
  64. 111
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java
  65. 3
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadGroupListener.java
  66. 24
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java
  67. 3
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java
  68. 12
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTask.java
  69. 11
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTask.java
  70. 74
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java
  71. 115
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java
  72. 27
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java
  73. 7
      Aria/src/main/java/com/arialyy/aria/core/inf/IEventListener.java
  74. 9
      Aria/src/main/java/com/arialyy/aria/core/inf/IFtpTarget.java
  75. 10
      Aria/src/main/java/com/arialyy/aria/core/inf/IHttpHeaderDelegate.java
  76. 31
      Aria/src/main/java/com/arialyy/aria/core/inf/IPostDelegate.java
  77. 43
      Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java
  78. 16
      Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java
  79. 22
      Aria/src/main/java/com/arialyy/aria/core/inf/TaskSchedulerType.java
  80. 6
      Aria/src/main/java/com/arialyy/aria/core/manager/DGTEFactory.java
  81. 135
      Aria/src/main/java/com/arialyy/aria/core/manager/ThreadTaskManager.java
  82. 32
      Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java
  83. 19
      Aria/src/main/java/com/arialyy/aria/core/queue/DownloadGroupTaskQueue.java
  84. 35
      Aria/src/main/java/com/arialyy/aria/core/queue/DownloadTaskQueue.java
  85. 3
      Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
  86. 25
      Aria/src/main/java/com/arialyy/aria/core/queue/TaskFactory.java
  87. 19
      Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java
  88. 9
      Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulerListener.java
  89. 29
      Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java
  90. 10
      Aria/src/main/java/com/arialyy/aria/core/scheduler/ISchedulerListener.java
  91. 10
      Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java
  92. 117
      Aria/src/main/java/com/arialyy/aria/core/upload/BaseUListener.java
  93. 41
      Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java
  94. 3
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadListener.java
  95. 47
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java
  96. 25
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java
  97. 4
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpFileInfoThread.java
  98. 74
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpThreadTask.java
  99. 39
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/HttpThreadTask.java
  100. 10
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/SimpleUploadUtil.java
  101. Some files were not shown because too many files have changed in this diff Show More

@ -26,7 +26,7 @@ dependencies {
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
compile project(':AriaAnnotations')
compile 'com.arialyy.aria:aria-ftp-plug:1.0.3'
compile 'com.arialyy.aria:aria-ftp-plug:1.0.4'
// compile project(':AriaFtpPlug')
}

@ -26,7 +26,6 @@ import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.widget.PopupWindow;
import android.widget.Toast;
import com.arialyy.aria.core.command.ICmd;
import com.arialyy.aria.core.common.QueueMod;
import com.arialyy.aria.core.download.DownloadEntity;
@ -71,7 +70,6 @@ import org.xml.sax.SAXException;
* activity 和其DialogFragment的映射表
*/
private Map<String, List<String>> mSubClass = new ConcurrentHashMap<>();
private List<String> mActivityCount = new ArrayList<>();
public static Context APP;
private List<ICmd> mCommands = new ArrayList<>();
private Configuration.DownloadConfig mDConfig;
@ -470,9 +468,6 @@ import org.xml.sax.SAXException;
private class LifeCallback implements Application.ActivityLifecycleCallbacks {
@Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
mActivityCount.add(
String.format("%s_%s", activity.getClass().getName(), activity.hashCode()));
ALog.w(TAG, "size = " + mActivityCount.size());
}
@Override public void onActivityStarted(Activity activity) {
@ -497,13 +492,6 @@ import org.xml.sax.SAXException;
@Override public void onActivityDestroyed(Activity activity) {
removeReceiver(activity);
mActivityCount.remove(
String.format("%s_%s", activity.getClass().getName(), activity.hashCode()));
ALog.w(TAG, "size = " + mActivityCount.size());
if (mActivityCount.size() == 0) {
ALog.e(TAG, "gggg");
//Toast.makeText(activity, "destroy", Toast.LENGTH_SHORT).show();
}
}
}
}

@ -184,6 +184,9 @@ class ConfigHelper extends DefaultHandler {
if (mType == ConfigType.DOWNLOAD) {
mDownloadConfig.maxSpeed = maxSpeed;
}
if (mType == ConfigType.UPLOAD) {
mUploadConfig.maxSpeed = maxSpeed;
}
}
private void loadConvertSpeed(String value) {

@ -17,6 +17,8 @@
*/
package com.arialyy.aria.core;
import com.arialyy.aria.core.common.ProtocolType;
import com.arialyy.aria.orm.annotation.Ignore;
import java.net.InetAddress;
/**
@ -32,6 +34,12 @@ public class FtpUrlEntity implements Cloneable {
public String account;
/**
* 是否是ftps
* {@code true}ftps协议的地址{@code false}不是ftps协议的地址
*/
public boolean isFtps = false;
/**
* 原始url
*/
@ -40,15 +48,17 @@ public class FtpUrlEntity implements Cloneable {
/**
* ftp协议ftp
*/
public String protocol;
public String scheme;
/**
* 登录的用户名
*/
public String user;
/**
* 密码
*/
@Ignore
public String password;
/**
@ -71,6 +81,28 @@ public class FtpUrlEntity implements Cloneable {
*/
public InetAddress validAddr;
/**
* 证书路径
*/
public String storePath;
/**
* 证书密码
*/
public String storePass;
/**
* 连接协议
* {@link ProtocolType}
*/
@ProtocolType
public String protocol;
/**
* 私钥别名
*/
public String keyAlias;
@Override public FtpUrlEntity clone() {
FtpUrlEntity entity = null;
try {

@ -26,7 +26,6 @@ public abstract class AbsCmd<T extends AbsTaskEntity> implements ICmd {
protected ITaskQueue mQueue;
protected T mTaskEntity;
protected String TAG;
protected String mTargetName;
/**
* 是否是下载任务的命令

@ -24,10 +24,9 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
public abstract class AbsCmdFactory<TASK_ENTITY extends AbsTaskEntity, CMD extends AbsCmd> {
/**
* @param target 创建任务的对象
* @param entity 下载实体
* @param taskType {@link ICmd#TASK_TYPE_DOWNLOAD}{@link ICmd#TASK_TYPE_DOWNLOAD_GROUP}{@link
* ICmd#TASK_TYPE_UPLOAD}
*/
public abstract CMD createCmd(String target, TASK_ENTITY entity, int type, int taskType);
public abstract CMD createCmd(TASK_ENTITY entity, int type, int taskType);
}

@ -36,11 +36,7 @@ public abstract class AbsGroupCmd<T extends AbsGroupTaskEntity> extends AbsCmd<T
AbsGroupTask tempTask;
/**
* @param targetName 创建任务的对象名
*/
AbsGroupCmd(String targetName, T entity) {
mTargetName = targetName;
AbsGroupCmd(T entity) {
mTaskEntity = entity;
TAG = CommonUtil.getClassName(this);
if (entity instanceof DownloadGroupTaskEntity) {
@ -55,7 +51,7 @@ public abstract class AbsGroupCmd<T extends AbsGroupTaskEntity> extends AbsCmd<T
* @return 创建的任务
*/
AbsTask createTask() {
tempTask = (AbsGroupTask) mQueue.createTask(mTargetName, mTaskEntity);
tempTask = (AbsGroupTask) mQueue.createTask(mTaskEntity);
return tempTask;
}

@ -22,11 +22,8 @@ import com.arialyy.aria.core.inf.AbsGroupTaskEntity;
* 删除任务组子任务
*/
class GroupCancelCmd<T extends AbsGroupTaskEntity> extends AbsGroupCmd<T> {
/**
* @param targetName 创建任务的对象名
*/
GroupCancelCmd(String targetName, T entity) {
super(targetName, entity);
GroupCancelCmd(T entity) {
super(entity);
}
@Override public void executeCmd() {

@ -62,13 +62,13 @@ public class GroupCmdFactory {
AbsGroupCmd cmd = null;
switch (type) {
case SUB_TASK_START:
cmd = new GroupStartCmd<>(target, entity);
cmd = new GroupStartCmd<>(entity);
break;
case SUB_TASK_STOP:
cmd = new GroupStopCmd<>(target, entity);
cmd = new GroupStopCmd<>(entity);
break;
case SUB_TASK_CANCEL:
cmd = new GroupCancelCmd<>(target, entity);
cmd = new GroupCancelCmd<>(entity);
}
if (cmd != null) {
cmd.childUrl = childUrl;

@ -22,11 +22,8 @@ import com.arialyy.aria.core.inf.AbsGroupTaskEntity;
* 任务组开始命令该命令负责处理任务组子任务的开始\恢复等工作
*/
class GroupStartCmd<T extends AbsGroupTaskEntity> extends AbsGroupCmd<T> {
/**
* @param targetName 创建任务的对象名
*/
GroupStartCmd(String targetName, T entity) {
super(targetName, entity);
GroupStartCmd( T entity) {
super( entity);
}
@Override public void executeCmd() {

@ -22,11 +22,8 @@ import com.arialyy.aria.core.inf.AbsGroupTaskEntity;
* 停止任务组的命令
*/
class GroupStopCmd<T extends AbsGroupTaskEntity> extends AbsGroupCmd<T> {
/**
* @param targetName 创建任务的对象名
*/
GroupStopCmd(String targetName, T entity) {
super(targetName, entity);
GroupStopCmd(T entity) {
super(entity);
}
@Override public void executeCmd() {

@ -46,13 +46,11 @@ public abstract class AbsNormalCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
int taskType;
/**
* @param targetName 产生任务的对象名
* @param taskType 下载任务类型{@link ICmd#TASK_TYPE_DOWNLOAD}{@link ICmd#TASK_TYPE_DOWNLOAD_GROUP}{@link
* ICmd#TASK_TYPE_UPLOAD}
*/
AbsNormalCmd(String targetName, T entity, int taskType) {
AbsNormalCmd(T entity, int taskType) {
this.taskType = taskType;
mTargetName = targetName;
mTaskEntity = entity;
TAG = CommonUtil.getClassName(this);
if (taskType == ICmd.TASK_TYPE_DOWNLOAD) {
@ -126,7 +124,7 @@ public abstract class AbsNormalCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
*/
void removeTask(AbsTaskEntity taskEntity) {
AbsTask tempTask = getTask(taskEntity.getEntity());
if (tempTask == null){
if (tempTask == null) {
tempTask = createTask(taskEntity);
}
mQueue.cancelTask(tempTask);
@ -181,7 +179,7 @@ public abstract class AbsNormalCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
* @return 创建的任务
*/
AbsTask createTask() {
tempTask = mQueue.createTask(mTargetName, mTaskEntity);
tempTask = mQueue.createTask(mTaskEntity);
return tempTask;
}
@ -193,6 +191,6 @@ public abstract class AbsNormalCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
*/
AbsTask createTask(AbsTaskEntity taskEntity) {
TEManager.getInstance().addTEntity(taskEntity);
return mQueue.createTask(mTargetName, taskEntity);
return mQueue.createTask(taskEntity);
}
}

@ -27,8 +27,8 @@ import com.arialyy.aria.util.ALog;
*/
class AddCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
AddCmd(String targetName, T entity, int taskType) {
super(targetName, entity, taskType);
AddCmd(T entity, int taskType) {
super(entity, taskType);
}
@Override public void executeCmd() {

@ -42,11 +42,8 @@ public class CancelAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
*/
public boolean removeFile = false;
/**
* @param targetName 产生任务的对象名
*/
CancelAllCmd(String targetName, T entity, int taskType) {
super(targetName, entity, taskType);
CancelAllCmd(T entity, int taskType) {
super(entity, taskType);
}
@Override public void executeCmd() {

@ -16,7 +16,6 @@
package com.arialyy.aria.core.command.normal;
import android.text.TextUtils;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.AbsTaskEntity;
@ -31,8 +30,8 @@ public class CancelCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
*/
public boolean removeFile = false;
CancelCmd(String targetName, T entity, int taskType) {
super(targetName, entity, taskType);
CancelCmd(T entity, int taskType) {
super(entity, taskType);
}
@Override public void executeCmd() {
@ -43,9 +42,6 @@ public class CancelCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
}
if (task != null) {
mTaskEntity.setRemoveFile(removeFile);
if (!TextUtils.isEmpty(mTargetName)) {
task.setTargetName(mTargetName);
}
removeTask();
}
}

@ -36,11 +36,8 @@ import com.arialyy.aria.util.NetUtils;
* 目前只只支持单下载任务的最高优先级任务
*/
final class HighestPriorityCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
/**
* @param targetName 产生任务的对象名
*/
HighestPriorityCmd(String targetName, T entity, int taskType) {
super(targetName, entity, taskType);
HighestPriorityCmd(T entity, int taskType) {
super(entity, taskType);
}
@Override public void executeCmd() {
@ -54,9 +51,6 @@ final class HighestPriorityCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T>
task = (DownloadTask) createTask();
}
if (task != null) {
if (!TextUtils.isEmpty(mTargetName)) {
task.setTargetName(mTargetName);
}
((DownloadTaskQueue) mQueue).setTaskHighestPriority(task);
}
}

@ -78,32 +78,31 @@ public class NormalCmdFactory extends AbsCmdFactory<AbsTaskEntity, AbsNormalCmd>
}
/**
* @param target 创建任务的对象
* @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}
*/
public AbsNormalCmd createCmd(String target, AbsTaskEntity entity, int type, int taskType) {
public AbsNormalCmd createCmd(AbsTaskEntity entity, int type, int taskType) {
switch (type) {
case TASK_CREATE:
return new AddCmd<>(target, entity, taskType);
return new AddCmd<>(entity, taskType);
case TASK_RESUME:
case TASK_START:
return new StartCmd<>(target, entity, taskType);
return new StartCmd<>(entity, taskType);
case TASK_CANCEL:
return new CancelCmd<>(target, entity, taskType);
return new CancelCmd<>(entity, taskType);
case TASK_STOP:
return new StopCmd<>(target, entity, taskType);
return new StopCmd<>(entity, taskType);
case TASK_HIGHEST_PRIORITY:
return new HighestPriorityCmd<>(target, entity, taskType);
return new HighestPriorityCmd<>(entity, taskType);
case TASK_STOP_ALL:
return new StopAllCmd<>(target, entity, taskType);
return new StopAllCmd<>(entity, taskType);
case TASK_RESUME_ALL:
return new ResumeAllCmd<>(target, entity, taskType);
return new ResumeAllCmd<>(entity, taskType);
case TASK_CANCEL_ALL:
return new CancelAllCmd<>(target, entity, taskType);
return new CancelAllCmd<>(entity, taskType);
default:
return null;
}

@ -1,5 +1,6 @@
package com.arialyy.aria.core.command.normal;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity;
@ -32,11 +33,8 @@ import java.util.List;
final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
private List<AbsTaskEntity> mWaitList = new ArrayList<>();
/**
* @param targetName 产生任务的对象名
*/
ResumeAllCmd(String targetName, T entity, int taskType) {
super(targetName, entity, taskType);
ResumeAllCmd(T entity, int taskType) {
super(entity, taskType);
}
@Override public void executeCmd() {
@ -65,6 +63,9 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
"isGroupChild=? AND state!=? ORDER BY stopTime DESC", "false", "1");
if (entities != null && !entities.isEmpty()) {
for (DownloadEntity entity : entities) {
//if (TextUtils.isEmpty(entity.getDownloadPath())){
// continue;
//}
resumeTask(TEManager.getInstance().getTEntity(DownloadTaskEntity.class, entity.getKey()));
}
}

@ -16,7 +16,6 @@
package com.arialyy.aria.core.command.normal;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.QueueMod;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
@ -45,8 +44,8 @@ import java.util.List;
*/
class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
StartCmd(String targetName, T entity, int taskType) {
super(targetName, entity, taskType);
StartCmd(T entity, int taskType) {
super(entity, taskType);
}
@Override public void executeCmd() {
@ -67,9 +66,6 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
AbsTask task = getTask();
if (task == null) {
task = createTask();
if (!TextUtils.isEmpty(mTargetName)) {
task.setTargetName(mTargetName);
}
// 任务不存在时,根据配置不同,对任务执行操作
if (mod.equals(QueueMod.NOW.getTag())) {
startTask();
@ -82,14 +78,14 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
|| task.getState() == IEntity.STATE_COMPLETE) {
resumeTask();
} else {
sendWaitState();
sendWaitState(task);
}
}
} else {
//任务没执行并且执行队列中没有该任务,才认为任务没有运行中
if (!task.isRunning() && !mQueue.taskIsRunning(task.getKey())) {
resumeTask();
}else {
} else {
ALog.w(TAG, String.format("任务【%s】已经在运行", task.getTaskName()));
}
}
@ -152,7 +148,8 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
AbsTask task = getTask(te.getEntity());
if (task != null) continue;
if (te instanceof DownloadTaskEntity) {
if (te.getRequestType() == AbsTaskEntity.D_FTP || te.getRequestType() == AbsTaskEntity.U_FTP) {
if (te.getRequestType() == AbsTaskEntity.D_FTP
|| te.getRequestType() == AbsTaskEntity.U_FTP) {
te.setUrlEntity(CommonUtil.getFtpUrlInfo(te.getEntity().getKey()));
}
mQueue = DownloadTaskQueue.getInstance();

@ -7,11 +7,8 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
* 停止所有任务的命令并清空所有等待队列
*/
final class StopAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
/**
* @param targetName 产生任务的对象名
*/
StopAllCmd(String targetName, T entity, int taskType) {
super(targetName, entity, taskType);
StopAllCmd(T entity, int taskType) {
super(entity, taskType);
}
@Override public void executeCmd() {

@ -16,10 +16,9 @@
package com.arialyy.aria.core.command.normal;
import android.text.TextUtils;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.util.ALog;
/**
@ -28,8 +27,8 @@ import com.arialyy.aria.util.ALog;
*/
class StopCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
StopCmd(String targetName, T entity, int taskType) {
super(targetName, entity, taskType);
StopCmd(T entity, int taskType) {
super(entity, taskType);
}
@Override public void executeCmd() {
@ -42,9 +41,6 @@ class StopCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
ALog.w(TAG, "停止命令执行失败,【调度器中没有该任务】");
}
} else {
if (!TextUtils.isEmpty(mTargetName)) {
task.setTargetName(mTargetName);
}
stopTask();
}
}

@ -13,23 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.core.download;
import android.os.Handler;
import com.arialyy.aria.core.inf.IDownloadListener;
package com.arialyy.aria.core.common;
/**
* Created by Aria.Lao on 2017/7/20.
* 普通任务下载的事件监听器
* Aria事件总线
*/
class DownloadListener extends BaseDListener<DownloadEntity, DownloadTaskEntity, DownloadTask>
implements IDownloadListener {
DownloadListener(DownloadTask task, Handler outHandler) {
super(task, outHandler);
}
public class AEvent {
private static final Object LOCK = new Object();
private static volatile AEvent INSTANCE = null;
@Override public void supportBreakpoint(boolean support) {
private AEvent() {
}
public static AEvent getInstance() {
if (INSTANCE == null) {
synchronized (LOCK) {
INSTANCE = new AEvent();
}
}
return INSTANCE;
}
}

@ -16,36 +16,33 @@
package com.arialyy.aria.core.common;
import android.content.Context;
import android.util.SparseArray;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IDownloadListener;
import com.arialyy.aria.core.inf.IEventListener;
import com.arialyy.aria.core.manager.ThreadTaskManager;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.DbHelper;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Created by AriaL on 2017/7/1.
* 任务处理器
*/
public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements Runnable, IUtil {
implements Runnable {
private static final String STATE = "_state_";
private static final String RECORD = "_record_";
/**
@ -64,16 +61,13 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
protected Context mContext;
protected File mTempFile; //文件
protected StateConstance mConstance;
private ExecutorService mFixedThreadPool;
//总线程数
protected int mTotalThreadNum;
//启动线程数
private int mStartThreadNum;
//已完成的线程数
private int mCompleteThreadNum;
private Map<Integer, AbsThreadTask> mTask = new HashMap<>();
private SparseArray<AbsThreadTask> mTask = new SparseArray<>();
private Timer mTimer;
private ScheduledThreadPoolExecutor mTimer;
@Deprecated private File mConfigFile;
/**
* 进度刷新间隔
@ -93,7 +87,12 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
mTaskEntity.setNewTask(newTask);
}
@Override public void setMaxSpeed(double maxSpeed) {
/**
* 设置最大下载/上传速度
*
* @param maxSpeed 单位为kb
*/
public void setMaxSpeed(int maxSpeed) {
for (int i = 0; i < mTotalThreadNum; i++) {
AbsThreadTask task = mTask.get(i);
if (task != null) {
@ -102,11 +101,22 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
}
}
@Override public void run() {
if (mConstance.isRunning) {
return;
/**
* 重置任务状态
*/
private void resetState() {
closeTimer();
mCompleteThreadNum = 0;
mTotalThreadNum = 0;
if (mTask != null && mTask.size() != 0) {
for (int i = 0; i < mTask.size(); i++) {
AbsThreadTask task = mTask.get(i);
if (task != null && !task.isRunning()) {
task.breakTask();
}
}
mTask.clear();
}
startFlow();
}
/**
@ -116,18 +126,16 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
if (isBreak()) {
return;
}
resetState();
mConstance.resetState();
checkTask();
checkRecord();
mConstance.isRunning = true;
mConstance.TASK_RECORD = mRecord;
if (mListener instanceof IDownloadListener) {
((IDownloadListener) mListener).onPostPre(mEntity.getFileSize());
}
if (!mTaskEntity.isSupportBP()) {
mTotalThreadNum = 1;
mStartThreadNum = 1;
} else {
mTotalThreadNum =
mTaskEntity.isNewTask() ? (mStartThreadNum = setNewTaskThreadNum()) : mTotalThreadNum;
mTaskEntity.isNewTask() ? setNewTaskThreadNum() : mTotalThreadNum;
}
mConstance.START_THREAD_NUM = mTotalThreadNum;
@ -149,15 +157,30 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
mRecord.isOpenDynamicFile = true;
}
onPostPre();
if (!mTaskEntity.isSupportBP()) {
handleNoSupportBP();
} else {
handleBreakpoint();
}
startTimer();
}
@Override public void run() {
if (mConstance.isRunning) {
return;
}
startFlow();
}
/**
* 预处理完成
*/
protected void onPostPre() {
}
/**
* 设置新任务的最大线程数
*/
@ -166,9 +189,9 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
/**
* 启动进度获取定时器
*/
private void startTimer() {
mTimer = new Timer(true);
mTimer.schedule(new TimerTask() {
private synchronized void startTimer() {
mTimer = new ScheduledThreadPoolExecutor(1);
mTimer.scheduleWithFixedDelay(new Runnable() {
@Override public void run() {
if (mConstance.isComplete()
|| mConstance.isStop()
@ -179,14 +202,12 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
mListener.onProgress(mConstance.CURRENT_LOCATION);
}
}
}, 0, mUpdateInterval);
}, 0, mUpdateInterval, TimeUnit.MILLISECONDS);
}
protected void closeTimer() {
if (mTimer != null) {
mTimer.purge();
mTimer.cancel();
mTimer = null;
public synchronized void closeTimer() {
if (mTimer != null && !mTimer.isShutdown()) {
mTimer.shutdown();
}
}
@ -203,72 +224,86 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
mUpdateInterval = interval;
}
@Override public long getFileSize() {
public long getFileSize() {
return mEntity.getFileSize();
}
/**
* 获取当前任务位置
*/
@Override public long getCurrentLocation() {
public long getCurrentLocation() {
return mConstance.CURRENT_LOCATION;
}
@Override public boolean isRunning() {
public synchronized boolean isRunning() {
return mConstance.isRunning;
}
@Override public void cancel() {
public synchronized void cancel() {
if (mConstance.isCancel) {
return;
}
closeTimer();
mConstance.isRunning = false;
mConstance.isCancel = true;
if (mFixedThreadPool != null) {
mFixedThreadPool.shutdown();
}
for (int i = 0; i < mStartThreadNum; i++) {
AbsThreadTask task = mTask.get(i);
if (task != null) {
task.cancel();
new Thread(new Runnable() {
@Override public void run() {
for (int i = 0; i < mTask.size(); i++) {
AbsThreadTask task = mTask.get(i);
if (task != null) {
task.cancel();
}
}
ThreadTaskManager.getInstance().stopTaskThread(mTaskEntity.getKey());
}
}
}).start();
}
@Override public void stop() {
public synchronized void stop() {
if (mConstance.isStop) {
return;
}
closeTimer();
mConstance.isRunning = false;
mConstance.isStop = true;
if (mConstance.isComplete()) return;
if (mFixedThreadPool != null) {
mFixedThreadPool.shutdown();
}
for (int i = 0; i < mStartThreadNum; i++) {
AbsThreadTask task = mTask.get(i);
if (task != null) {
task.stop();
new Thread(new Runnable() {
@Override public void run() {
for (int i = 0; i < mTask.size(); i++) {
AbsThreadTask task = mTask.get(i);
if (task != null && !task.isThreadComplete()) {
task.stop();
}
}
ThreadTaskManager.getInstance().stopTaskThread(mTaskEntity.getKey());
}
}
}).start();
}
/**
* 直接调用的时候会自动启动线程执行
*/
@Override public void start() {
public synchronized void start() {
if (mConstance.isRunning) {
return;
}
new Thread(this).start();
}
@Override public void resume() {
public void resume() {
start();
}
/**
* 检查任务检查线程数
* 新任务条件
* 1文件不存在
* 2任务记录文件缺失或不匹配
* 3数据库记录不存在
* 4不支持断点则是新任务
* 检查记录
* 对于分块任务
* 子分块不存在或被删除子线程将重新下载
* 对于普通任务
* 预下载文件不存在则任务任务呗删除
*/
private void checkTask() {
private void checkRecord() {
mConfigFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName()));
if (mConfigFile.exists()) {
convertDb();
@ -279,24 +314,104 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
} else {
if (mRecord.threadRecords == null || mRecord.threadRecords.isEmpty()) {
initRecord(true);
} else if (mRecord.isBlock) {
handleBlockRecord();
} else {
handleNormalRecord();
}
//else if (mTempFile.length() == 0) {
// mRecord.deleteData();
// initRecord(true);
//}
else {
for (ThreadRecord tr : mRecord.threadRecords) {
if (tr.isComplete) {
mCompleteThreadNum++;
} else {
mStartThreadNum++;
}
}
}
/**
* 处理普通任务的记录
*/
private void handleNormalRecord() {
File file = new File(mRecord.filePath);
if (!file.exists()) {
ALog.w(TAG, String.format("文件【%s】不存在,任务将重新开始", file.getPath()));
mRecord.deleteData();
initRecord(true);
return;
}
if (mRecord.isOpenDynamicFile) {
ThreadRecord tr = mRecord.threadRecords.get(0);
if (tr == null) {
mTaskEntity.setNewTask(true);
mTotalThreadNum = 1;
return;
}
if (file.length() > mEntity.getFileSize()) {
ALog.i(TAG, String.format("文件【%s】错误,任务重新开始", file.getPath()));
file.delete();
tr.startLocation = 0;
tr.isComplete = false;
tr.endLocation = mEntity.getFileSize();
} else if (file.length() == mEntity.getFileSize()) {
tr.isComplete = true;
mCompleteThreadNum++;
} else {
if (file.length() != tr.startLocation) {
ALog.i(TAG, String.format("修正【%s】的进度记录为:%s", file.getPath(), file.length()));
tr.startLocation = file.length();
tr.isComplete = false;
}
}
} else {
for (ThreadRecord tr : mRecord.threadRecords) {
if (tr.isComplete) {
mCompleteThreadNum++;
}
}
}
mTotalThreadNum = mRecord.threadRecords.size();
mTaskEntity.setNewTask(false);
}
/**
* 处理分块任务的记录
*/
private void handleBlockRecord() {
final int threadNum = mRecord.threadRecords.size();
final long blockLen = mEntity.getFileSize() / threadNum;
int i = 0;
for (ThreadRecord tr : mRecord.threadRecords) {
File temp = new File(String.format(SUB_PATH, mRecord.filePath, tr.threadId));
if (!temp.exists()) {
ALog.i(TAG, String.format("分块文件【%s】不存在,该分块将重新开始", temp.getPath()));
tr.isComplete = false;
tr.startLocation = -1;
} else {
if (tr.isComplete) {
mCompleteThreadNum++;
} else {
long realLocation = i * blockLen + temp.length();
ALog.i(TAG, String.format(
"startLocation = %s; endLocation = %s; block = %s; tempLen = %s; i = %s",
tr.startLocation, tr.endLocation, blockLen, temp.length(), i));
if (tr.endLocation == realLocation) {
ALog.d(TAG, String.format("分块【%s】已完成,更新记录", temp.getPath()));
tr.startLocation = realLocation;
tr.isComplete = true;
mCompleteThreadNum++;
} else {
tr.isComplete = false;
if (realLocation != tr.startLocation) {
ALog.i(TAG, String.format("修正分块【%s】的进度记录为:%s", temp.getPath(), realLocation));
tr.startLocation = realLocation;
} else if (realLocation > tr.endLocation) {
ALog.i(TAG, String.format("分块【%s】错误,将重新开始该分块", temp.getPath()));
temp.delete();
tr.startLocation = i * blockLen;
}
}
mTotalThreadNum = mRecord.threadRecords.size();
mTaskEntity.setNewTask(false);
}
}
i++;
}
mTotalThreadNum = mRecord.threadRecords.size();
mTaskEntity.setNewTask(false);
}
/**
@ -342,7 +457,6 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
tRecord.isComplete = true;
continue;
}
mStartThreadNum++;
if (record != null) {
Long temp = Long.parseLong(String.valueOf(record));
tRecord.startLocation = temp > 0 ? temp : 0;
@ -418,7 +532,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
private AbsThreadTask createSingThreadTask(int i, long startL, long endL, long fileLength,
ThreadRecord record) {
SubThreadConfig<TASK_ENTITY> config = new SubThreadConfig<>();
config.FILE_SIZE = fileLength;
config.TOTAL_FILE_SIZE = fileLength;
config.URL = mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getUrl();
config.TEMP_FILE =
mRecord.isBlock ? new File(String.format(SUB_PATH, mTempFile.getPath(), i)) : mTempFile;
@ -456,28 +570,35 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
} else {
tr = mRecord.threadRecords.get(i);
}
if (tr.blockLen == 0) {
tr.blockLen = i == mTotalThreadNum - 1 ? (fileLength - i * blockSize) : blockSize;
}
if (tr.isComplete) {//该线程已经完成
if (resumeRecordLocation(i, startL, endL)) return;
continue;
}
//如果有记录,则恢复任务
if (tr.startLocation >= 0) {
Long r = tr.startLocation;
if (tr.startLocation > 0) {
long r = tr.startLocation;
//记录的位置需要在线程区间中
if (startL < r && r < (i == (mTotalThreadNum - 1) ? fileLength : endL)) {
if (startL < r && r <= (i == (mTotalThreadNum - 1) ? fileLength : endL)) {
mConstance.CURRENT_LOCATION += r - startL;
startL = r;
}
ALog.d(TAG, String.format("任务【%s】线程__%s__恢复任务", mEntity.getFileName(), i));
} else {
tr.startLocation = startL;
}
//最后一个线程的结束位置即为文件的总长度
if (i == (mTotalThreadNum - 1)) {
endL = fileLength;
}
// 更新记录
tr.startLocation = startL;
tr.endLocation = endL;
if (tr.endLocation <= 0) {
tr.endLocation = endL;
}
if (isNewTr) {
mRecord.threadRecords.add(tr);
}
@ -508,45 +629,18 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
} else {
mListener.onStart(mConstance.CURRENT_LOCATION);
}
mFixedThreadPool = Executors.newFixedThreadPool(recordL.length);
for (int l : recordL) {
if (l == -1) continue;
Runnable task = mTask.get(l);
if (task != null) {
mFixedThreadPool.execute(task);
}
ThreadTaskManager.getInstance().startThread(mTaskEntity.getKey(), mTask.get(l));
}
}
/**
* 重试线程任务只有线程创建成功才能重试
* 重试任务
*/
public void retryThreadTask() {
if (isBreak()) {
return;
}
if (mTask == null || mTask.size() == 0) {
ALog.w(TAG, "没有线程任务");
return;
}
Set<Integer> keys = mTask.keySet();
for (Integer key : keys) {
AbsThreadTask task = mTask.get(key);
if (task != null && !task.isThreadComplete()) {
task.getConfig().START_LOCATION = task.getConfig().THREAD_RECORD.startLocation;
mConstance.resetState();
startTimer();
ALog.d(TAG, String.format("任务【%s】开始重试,线程__%s__【开始位置:%s,结束位置:%s】", mEntity.getFileName(),
key, task.getConfig().START_LOCATION, task.getConfig().END_LOCATION));
if (!mFixedThreadPool.isShutdown()) {
mFixedThreadPool.execute(task);
} else {
ALog.w(TAG, "线程池已关闭");
mListener.onFail(true);
}
}
}
public void retryTask() {
ALog.w(TAG, String.format("任务【%s】开始重试", mEntity.getFileName()));
startFlow();
}
/**
@ -561,24 +655,23 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
*/
private void handleNoSupportBP() {
SubThreadConfig<TASK_ENTITY> config = new SubThreadConfig<>();
config.FILE_SIZE = mEntity.getFileSize();
config.TOTAL_FILE_SIZE = mEntity.getFileSize();
config.URL = mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getUrl();
config.TEMP_FILE = mTempFile;
config.THREAD_ID = 0;
config.START_LOCATION = 0;
config.END_LOCATION = config.FILE_SIZE;
config.END_LOCATION = config.TOTAL_FILE_SIZE;
config.SUPPORT_BP = mTaskEntity.isSupportBP();
config.TASK_ENTITY = mTaskEntity;
ThreadRecord record = new ThreadRecord();
record.startLocation = 0;
record.endLocation = config.FILE_SIZE;
record.endLocation = config.TOTAL_FILE_SIZE;
record.key = mTempFile.getPath();
config.THREAD_RECORD = record;
AbsThreadTask task = selectThreadTask(config);
if (task == null) return;
mTask.put(0, task);
mFixedThreadPool = Executors.newFixedThreadPool(1);
mFixedThreadPool.execute(task);
ThreadTaskManager.getInstance().startThread(mTaskEntity.getKey(), task);
mListener.onStart(0);
}

@ -15,22 +15,24 @@
*/
package com.arialyy.aria.core.common;
import android.os.Build;
import android.os.Process;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEventListener;
import com.arialyy.aria.core.manager.ThreadTaskManager;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.exception.FileException;
import com.arialyy.aria.exception.TaskException;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.ErrorHelp;
import com.arialyy.aria.util.FileUtil;
import com.arialyy.aria.util.NetUtils;
import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -39,20 +41,17 @@ import java.util.concurrent.Executors;
* 任务线程
*/
public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements Runnable {
implements Callable<AbsThreadTask> {
/**
* 线程重试次数
*/
private final int RETRY_NUM = 2;
/**
* 线程重试间隔
*/
private final int RETRY_INTERVAL = 5000;
private final String TAG = "AbsThreadTask";
/**
* 当前子线程的下载位置
*/
protected long mChildCurrentLocation = 0, mSleepTime = 0;
protected long mChildCurrentLocation = 0;
protected int mBufSize;
protected IEventListener mListener;
protected StateConstance STATE;
@ -60,16 +59,23 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity;
private int mFailTimes = 0;
private Timer mFailTimer;
private long mLastSaveTime;
private ExecutorService mConfigThreadPool;
protected int mConnectTimeOut; //连接超时时间
protected int mReadTimeOut; //流读取的超时时间
protected boolean isNotNetRetry = false; //断网情况是否重试
private boolean taskBreak = false; //任务中断
private boolean taskBreak = false; //任务跳出
protected int mThreadNum;
/**
* 速度限制工具
*/
protected BandwidthLimiter mSpeedBandUtil;
protected AriaManager mAridManager;
protected boolean isInterrupted = false;
private Thread mConfigThread = new Thread(new Runnable() {
@Override public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
final long currentTemp = mChildCurrentLocation;
writeConfig(false, currentTemp);
}
@ -84,16 +90,30 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
mEntity = mTaskEntity.getEntity();
mLastSaveTime = System.currentTimeMillis();
mConfigThreadPool = Executors.newCachedThreadPool();
mThreadNum = STATE.TASK_RECORD.threadRecords.size();
mAridManager = AriaManager.getInstance(AriaManager.APP);
if (getMaxSpeed() > 0) {
mSpeedBandUtil = new BandwidthLimiter(getMaxSpeed(), mThreadNum);
}
}
protected void setMaxSpeed(double maxSpeed) {
if (-0.9999 < maxSpeed && maxSpeed < 0.00001) {
mSleepTime = 0;
} else {
BigDecimal db = new BigDecimal(
((mBufSize / 1024) * (filterVersion() ? 1 : STATE.START_THREAD_NUM) / maxSpeed) * 1000);
mSleepTime = db.setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
}
/**
* 设置线程是否中断
*
* @param isInterrupted {@code true} 中断
*/
public void setInterrupted(boolean isInterrupted) {
this.isInterrupted = isInterrupted;
}
/**
* 线程是否存活
*
* @return {@code true}存活
*/
protected boolean isLive() {
Thread t = Thread.currentThread();
return !t.isInterrupted() && !isInterrupted;
}
/**
@ -104,6 +124,74 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
return mConfig.THREAD_RECORD.isComplete;
}
/**
* 获取任务记录
*/
public TaskRecord getTaskRecord() {
return STATE.TASK_RECORD;
}
/**
* 获取线程记录
*/
public ThreadRecord getThreadRecord() {
return mConfig.THREAD_RECORD;
}
/**
* 获取配置的最大上传/下载速度
*
* @return 单位为kb
*/
public abstract int getMaxSpeed();
/**
* 设置最大下载速度
*
* @param speed 单位为kb
*/
public void setMaxSpeed(int speed) {
if (mSpeedBandUtil != null) {
mSpeedBandUtil.setMaxRate(speed / mThreadNum);
}
}
/**
* 中断任务
*/
public void breakTask() {
synchronized (AriaManager.LOCK) {
taskBreak = true;
if (mConfig.SUPPORT_BP) {
final long currentTemp = mChildCurrentLocation;
STATE.STOP_NUM++;
ALog.d(TAG, String.format("任务【%s】thread__%s__中断【停止位置:%s】", mConfig.TEMP_FILE.getName(),
mConfig.THREAD_ID, currentTemp));
writeConfig(false, currentTemp);
if (STATE.isStop()) {
ALog.i(TAG, String.format("任务【%s】已中断", mConfig.TEMP_FILE.getName()));
STATE.isRunning = false;
}
} else {
ALog.i(TAG, String.format("任务【%s】已中断", mConfig.TEMP_FILE.getName()));
STATE.isRunning = false;
}
}
}
/**
* 是否在运行
*
* @return {@code true}正在运行
*/
public boolean isRunning() {
return STATE.isRunning;
}
public boolean isInterrupted() {
return Thread.currentThread().isInterrupted();
}
/**
* 获取线程配置信息
*/
@ -111,10 +199,6 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
return mConfig;
}
private boolean filterVersion() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
}
@Override protected void finalize() throws Throwable {
super.finalize();
if (mConfigThreadPool != null) {
@ -188,10 +272,11 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
protected void progress(long len) {
synchronized (AriaManager.LOCK) {
if (STATE.CURRENT_LOCATION > mEntity.getFileSize()) {
ALog.d(TAG, String.format("currentLocation=%s, fileSize=%s", STATE.CURRENT_LOCATION,
mEntity.getFileSize()));
String errorMsg =
String.format("下载失败,下载长度超出文件大;currentLocation=%s, fileSize=%s", STATE.CURRENT_LOCATION,
mEntity.getFileSize());
taskBreak = true;
fail(mChildCurrentLocation, "下载失败,下载长度超出文件大小", null, false);
fail(mChildCurrentLocation, new FileException(TAG, errorMsg), false);
return;
}
mChildCurrentLocation += len;
@ -235,11 +320,10 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
* 线程任务失败
*
* @param subCurrentLocation 当前线程下载进度
* @param msg 自定义信息
* @param ex 异常信息
*/
protected void fail(final long subCurrentLocation, String msg, Exception ex) {
fail(subCurrentLocation, msg, ex, true);
protected void fail(final long subCurrentLocation, BaseException ex) {
fail(subCurrentLocation, ex, true);
}
/**
@ -247,19 +331,17 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
*
* @param subCurrentLocation 当前子线程进度
*/
protected void fail(final long subCurrentLocation, String msg, Exception ex, boolean needRetry) {
protected void fail(final long subCurrentLocation, BaseException ex, boolean needRetry) {
synchronized (AriaManager.LOCK) {
if (ex != null) {
ALog.e(TAG, msg + "\n" + ALog.getExceptionString(ex));
} else {
ALog.e(TAG, msg);
ALog.e(TAG, ALog.getExceptionString(ex));
}
if (mConfig.SUPPORT_BP) {
writeConfig(false, subCurrentLocation);
retryThis(needRetry && STATE.START_THREAD_NUM != 1);
} else {
ALog.e(TAG, String.format("任务【%s】执行失败", mConfig.TEMP_FILE.getName()));
mListener.onFail(true);
mListener.onFail(true, ex);
ErrorHelp.saveError(TAG, "", ALog.getExceptionString(ex));
}
}
@ -271,36 +353,70 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
* @param needRetry 是否可以重试
*/
private void retryThis(boolean needRetry) {
if (mFailTimer != null) {
mFailTimer.purge();
mFailTimer.cancel();
}
if (!NetUtils.isConnected(AriaManager.APP) && !isNotNetRetry) {
ALog.w(TAG, String.format("任务【%s】thread__%s__重试失败,网络未连接", mConfig.TEMP_FILE.getName(),
mConfig.THREAD_ID));
}
if (mFailTimes < RETRY_NUM && needRetry && (NetUtils.isConnected(AriaManager.APP)
|| isNotNetRetry) && isBreak()) {
mFailTimer = new Timer(true);
mFailTimer.schedule(new TimerTask() {
@Override public void run() {
if (isBreak()) {
handleFailState(false);
return;
}
mFailTimes++;
ALog.w(TAG, String.format("任务【%s】thread__%s__正在重试", mConfig.TEMP_FILE.getName(),
mConfig.THREAD_ID));
mConfig.START_LOCATION = mChildCurrentLocation == 0 ? mConfig.START_LOCATION
: mConfig.THREAD_RECORD.startLocation;
AbsThreadTask.this.run();
}
}, RETRY_INTERVAL);
|| isNotNetRetry) && !isBreak()) {
ALog.w(TAG,
String.format("任务【%s】thread__%s__正在重试", mConfig.TEMP_FILE.getName(), mConfig.THREAD_ID));
mFailTimes++;
handleRetryRecord();
ThreadTaskManager.getInstance().retryThread(AbsThreadTask.this);
} else {
handleFailState(!isBreak());
}
}
/**
* 处理线程重试的记录只有多线程任务才会执行
*/
private void handleRetryRecord() {
if (getTaskRecord().isBlock) {
ThreadRecord tr = getThreadRecord();
long block = mEntity.getFileSize() / getTaskRecord().threadRecords.size();
File file = mConfig.TEMP_FILE;
if (file.length() > tr.endLocation) {
ALog.i(TAG, String.format("分块【%s】错误,将重新下载该分块", file.getPath()));
boolean b = file.delete();
ALog.w(TAG, "删除:" + b);
tr.startLocation = block * tr.threadId;
tr.isComplete = false;
mConfig.START_LOCATION = tr.startLocation;
} else if (file.length() == tr.endLocation) {
STATE.COMPLETE_THREAD_NUM++;
tr.isComplete = true;
} else {
tr.startLocation = block * tr.threadId + file.length();
mConfig.START_LOCATION = tr.startLocation;
tr.isComplete = false;
STATE.CURRENT_LOCATION = getBlockRealTotalSize();
ALog.i(TAG, String.format("修正分块【%s】进度,开始位置:%s,当前进度:%s", file.getPath(), tr.startLocation,
STATE.CURRENT_LOCATION));
}
} else {
mConfig.START_LOCATION = mChildCurrentLocation == 0 ? mConfig.START_LOCATION
: mConfig.THREAD_RECORD.startLocation;
}
}
/**
* 获取分块任务真实的进度
*
* @return 进度
*/
private long getBlockRealTotalSize() {
long size = 0;
for (int i = 0, len = getTaskRecord().threadRecords.size(); i < len; i++) {
File temp = new File(String.format(AbsFileer.SUB_PATH, getTaskRecord().filePath, i));
if (temp.exists()) {
size += temp.length();
}
}
return size;
}
/**
* 处理失败状态
*
@ -313,8 +429,9 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
STATE.isRunning = false;
// 手动停止不进行fail回调
if (!STATE.isStop) {
ALog.e(TAG, String.format("任务【%s】执行失败", mConfig.TEMP_FILE.getName()));
mListener.onFail(taskNeedReTry);
String errorMsg = String.format("任务【%s】执行失败", mConfig.TEMP_FILE.getName());
//ALog.e(TAG, errorMsg);
mListener.onFail(taskNeedReTry, new TaskException(TAG, errorMsg));
}
}
}
@ -328,13 +445,24 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
*/
protected void writeConfig(boolean isComplete, final long record) {
synchronized (AriaManager.LOCK) {
if (mConfig.THREAD_RECORD != null) {
mConfig.THREAD_RECORD.isComplete = isComplete;
if (0 < record && record < mConfig.END_LOCATION) {
mConfig.THREAD_RECORD.startLocation = record;
ThreadRecord tr = getThreadRecord();
if (tr != null) {
tr.isComplete = isComplete;
if (getTaskRecord().isBlock || getTaskRecord().isOpenDynamicFile) {
tr.startLocation = mConfig.TEMP_FILE.length();
} else {
if (0 < record && record < mConfig.END_LOCATION) {
tr.startLocation = record;
}
}
mConfig.THREAD_RECORD.update();
tr.update();
}
}
}
@Override public AbsThreadTask call() throws Exception {
isInterrupted = false;
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return this;
}
}

@ -0,0 +1,104 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* 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
*
* 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;
/**
* 速度限制
*/
public class BandwidthLimiter {
public static int maxBandWith = 2 * 1024; //KB
/* KB */
private static Long KB = 1024L;
/* The smallest count chunk length in bytes */
private static Long CHUNK_LENGTH = 1024L;
/* How many bytes will be sent or receive */
private int bytesWillBeSentOrReceive = 0;
/* When the last piece was sent or receive */
private long lastPieceSentOrReceiveTick = System.nanoTime();
/* Default rate is 1024KB/s */
private int maxRate = 1024;
/* Time cost for sending CHUNK_LENGTH bytes in nanoseconds */
private long timeCostPerChunk = (1000000000L * CHUNK_LENGTH)
/ (this.maxRate * KB);
/**
* Initialize a BandwidthLimiter object with a certain rate.
*
* @param maxRate the download or upload speed in KBytes
*/
public BandwidthLimiter(int maxRate, int threadNum) {
if (threadNum > 1) {
maxRate = maxRate / threadNum;
}
this.setMaxRate(maxRate);
}
/**
* Set the max upload or download rate in KB/s. maxRate must be grater than
* 0. If maxRate is zero, it means there is no bandwidth limit.
*
* @param maxRate If maxRate is zero, it means there is no bandwidth limit.
* @throws IllegalArgumentException
*/
public synchronized void setMaxRate(int maxRate)
throws IllegalArgumentException {
if (maxRate < 0) {
throw new IllegalArgumentException("maxRate can not less than 0");
}
this.maxRate = maxRate;
if (maxRate == 0) {
this.timeCostPerChunk = 0;
} else {
this.timeCostPerChunk = (1000000000L * CHUNK_LENGTH)
/ (this.maxRate * KB);
}
}
/**
* Next 1 byte should do bandwidth limit.
*/
public synchronized void limitNextBytes() {
this.limitNextBytes(1);
}
/**
* Next len bytes should do bandwidth limit
*/
public synchronized void limitNextBytes(int len) {
this.bytesWillBeSentOrReceive += len;
/* We have sent CHUNK_LENGTH bytes */
while (!Thread.currentThread().isInterrupted() && this.bytesWillBeSentOrReceive > CHUNK_LENGTH) {
long nowTick = System.nanoTime();
long missedTime = this.timeCostPerChunk
- (nowTick - this.lastPieceSentOrReceiveTick);
if (missedTime > 0) {
try {
Thread.currentThread().sleep(missedTime / 1000000,
(int) (missedTime % 1000000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.bytesWillBeSentOrReceive -= CHUNK_LENGTH;
this.lastPieceSentOrReceiveTick = nowTick
+ (missedTime > 0 ? missedTime : 0);
}
}
}

@ -0,0 +1,145 @@
/*
* 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;
import android.os.Handler;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.IEventListener;
import com.arialyy.aria.core.inf.TaskSchedulerType;
import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.ErrorHelp;
import java.lang.ref.WeakReference;
public abstract class BaseListener<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>, TASK extends AbsTask<ENTITY, TASK_ENTITY>>
implements IEventListener {
private static final String TAG = "BaseListener";
protected WeakReference<Handler> outHandler;
private int RUN_SAVE_INTERVAL = 5 * 1000; //5s保存一次下载中的进度
private long mLastLen; //上一次发送长度
private boolean isFirst = true;
private TASK mTask;
private long mLastSaveTime;
protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity;
protected boolean isConvertSpeed;
protected long mUpdateInterval;
protected AriaManager manager;
protected BaseListener(TASK task, Handler outHandler) {
this.outHandler = new WeakReference<>(outHandler);
this.mTask = new WeakReference<>(task).get();
this.mEntity = mTask.getTaskEntity().getEntity();
this.mTaskEntity = mTask.getTaskEntity();
manager = AriaManager.getInstance(AriaManager.APP);
mLastLen = mEntity.getCurrentProgress();
mLastSaveTime = System.currentTimeMillis();
}
@Override public void onPre() {
saveData(IEntity.STATE_PRE, -1);
sendInState2Target(ISchedulers.PRE);
}
@Override public void onStart(long startLocation) {
saveData(IEntity.STATE_RUNNING, startLocation);
sendInState2Target(ISchedulers.START);
}
@Override public void onResume(long resumeLocation) {
saveData(IEntity.STATE_RUNNING, resumeLocation);
sendInState2Target(ISchedulers.RESUME);
}
@Override public void onProgress(long currentLocation) {
mEntity.setCurrentProgress(currentLocation);
long speed = currentLocation - mLastLen;
if (isFirst) {
speed = 0;
isFirst = false;
}
handleSpeed(speed);
sendInState2Target(ISchedulers.RUNNING);
if (System.currentTimeMillis() - mLastSaveTime >= RUN_SAVE_INTERVAL) {
saveData(IEntity.STATE_RUNNING, currentLocation);
mLastSaveTime = System.currentTimeMillis();
}
mLastLen = currentLocation;
}
@Override public void onStop(long stopLocation) {
saveData(mTask.getSchedulerType() == TaskSchedulerType.TYPE_STOP_AND_WAIT ? IEntity.STATE_WAIT
: IEntity.STATE_STOP, stopLocation);
handleSpeed(0);
sendInState2Target(ISchedulers.STOP);
}
@Override public void onComplete() {
saveData(IEntity.STATE_COMPLETE, mEntity.getFileSize());
handleSpeed(0);
sendInState2Target(ISchedulers.COMPLETE);
}
@Override public void onCancel() {
saveData(IEntity.STATE_CANCEL, -1);
handleSpeed(0);
sendInState2Target(ISchedulers.CANCEL);
}
@Override public void onFail(boolean needRetry, BaseException e) {
mEntity.setFailNum(mEntity.getFailNum() + 1);
saveData(IEntity.STATE_FAIL, mEntity.getCurrentProgress());
handleSpeed(0);
mTask.needRetry = needRetry;
mTask.putExpand(AbsTask.ERROR_INFO_KEY, e);
sendInState2Target(ISchedulers.FAIL);
e.printStackTrace();
ErrorHelp.saveError(e.getTag(), "", ALog.getExceptionString(e));
}
private void handleSpeed(long speed) {
if (mUpdateInterval != 1000) {
speed = speed * 1000 / mUpdateInterval;
}
if (isConvertSpeed) {
mEntity.setConvertSpeed(CommonUtil.formatFileSize(speed < 0 ? 0 : speed) + "/s");
}
mEntity.setSpeed(speed < 0 ? 0 : speed);
mEntity.setPercent((int) (mEntity.getFileSize() <= 0 ? 0
: mEntity.getCurrentProgress() * 100 / mEntity.getFileSize()));
}
/**
* 将任务状态发送给下载器
*
* @param state {@link ISchedulers#START}
*/
protected void sendInState2Target(int state) {
if (outHandler.get() != null) {
outHandler.get().obtainMessage(state, mTask).sendToTarget();
}
}
protected abstract void saveData(int state, long location);
}

@ -60,7 +60,9 @@ public interface IUtil {
void resume();
/**
* 设置最大速度
* 设置最大下载/上传速度
*
* @param speed 单位kb
*/
void setMaxSpeed(double maxSpeed);
void setMaxSpeed(int speed);
}

@ -15,6 +15,8 @@
*/
package com.arialyy.aria.core.common;
import com.arialyy.aria.exception.BaseException;
public interface OnFileInfoCallback {
/**
* 处理完成
@ -26,7 +28,7 @@ public interface OnFileInfoCallback {
/**
* 请求失败
*
* @param errorMsg 错误信息
* @param e 错误信息
*/
void onFail(String url, String errorMsg, boolean needRetry);
void onFail(String url, BaseException e, boolean needRetry);
}

@ -0,0 +1,39 @@
/*
* 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;
import android.support.annotation.StringDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@StringDef({
ProtocolType.Default,
ProtocolType.SSL,
ProtocolType.SSLv3,
ProtocolType.TLS,
ProtocolType.TLSv1,
ProtocolType.TLSv1_1,
ProtocolType.TLSv1_2
})
@Retention(RetentionPolicy.SOURCE) public @interface ProtocolType {
String Default = "TLS";
String SSL = "SSL";
String SSLv3 = "SSLv3";
String TLS = "TLS";
String TLSv1 = "TLSv1";
String TLSv1_1 = "TLSv1.1";
String TLSv1_2 = "TLSv1.2";
}

@ -15,26 +15,47 @@
*/
package com.arialyy.aria.core.common;
import android.os.Build;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* Created by Aria.Lao on 2017/7/10.
* 代理参数获取
*/
public class ProxyHelper {
/**
* 普通下载任务类型
*/
public static int PROXY_TYPE_DOWNLOAD = 0x01;
/**
* 组合下载任务类型
*/
public static int PROXY_TYPE_DOWNLOAD_GROUP = 0x02;
///**
// * 组合任务子任务类型
// */
//public static int PROXY_TYPE_DOWNLOAD_GROUP_SUB = 0x03;
/**
* 普通上传任务类型
*/
public static int PROXY_TYPE_UPLOAD = 0x04;
public Set<String> downloadCounter = new HashSet<>(), uploadCounter = new HashSet<>(),
downloadGroupCounter = new HashSet<>(), downloadGroupSubCounter = new HashSet<>();
public Map<String, Set<Integer>> mProxyCache = new ConcurrentHashMap<>();
public static volatile ProxyHelper INSTANCE = null;
private boolean canLoadClass = false;
private ProxyHelper() {
init();
//init();
}
public static ProxyHelper getInstance() {
@ -46,14 +67,75 @@ public class ProxyHelper {
return INSTANCE;
}
/**
* @since 3.4.6 版本开始已经在ElementHandler中关闭了ProxyClassCounter对象的生成
*/
@Deprecated
private void init() {
List<String> classes = CommonUtil.getClassName(AriaManager.APP,
List<String> classes = CommonUtil.getPkgClassNames(AriaManager.APP,
"com.arialyy.aria.ProxyClassCounter");
for (String className : classes) {
count(className);
canLoadClass = classes != null
&& !classes.isEmpty()
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
if (canLoadClass) {
for (String className : classes) {
count(className);
}
}
}
/**
* 是否能读取到代理计数文件
*
* @return {@code true} 可以读取{@code false} 不能读取
*/
public boolean isCanLoadCountClass() {
return canLoadClass;
}
/**
* 检查观察者对象的代理文件类型
*
* @param clazz 观察者对象
* @return {@link #PROXY_TYPE_DOWNLOAD}如果没有实体对象则返回空的list
*/
public Set<Integer> checkProxyType(Class clazz) {
final String className = clazz.getName();
Set<Integer> result = mProxyCache.get(clazz.getName());
if (result != null) {
return result;
}
result = new HashSet<>();
try {
if (Class.forName(className.concat("$$DownloadGroupListenerProxy")) != null) {
result.add(PROXY_TYPE_DOWNLOAD_GROUP);
}
} catch (ClassNotFoundException e) {
//e.printStackTrace();
}
try {
if (Class.forName(className.concat("$$DownloadListenerProxy")) != null) {
result.add(PROXY_TYPE_DOWNLOAD);
}
} catch (ClassNotFoundException e) {
//e.printStackTrace();
}
try {
if (Class.forName(className.concat("$$UploadListenerProxy")) != null) {
result.add(PROXY_TYPE_UPLOAD);
}
} catch (ClassNotFoundException e) {
//e.printStackTrace();
}
if (!result.isEmpty()) {
mProxyCache.put(clazz.getName(), result);
}
return result;
}
@Deprecated
private void count(String className) {
try {
Class clazz = Class.forName(className);

@ -40,24 +40,29 @@ public class StateConstance {
public void resetState() {
isCancel = false;
isStop = false;
isRunning = true;
isRunning = false;
CANCEL_NUM = 0;
STOP_NUM = 0;
FAIL_NUM = 0;
COMPLETE_THREAD_NUM = 0;
START_THREAD_NUM = 0;
CURRENT_LOCATION = 0;
}
/**
* 所有子线程是否都已经停止
*/
public boolean isStop() {
return STOP_NUM == START_THREAD_NUM;
//ALog.d(TAG, String.format("stop_num=%s; start_thread_num=%s; complete_num=%s", STOP_NUM,
// START_THREAD_NUM, COMPLETE_THREAD_NUM));
return STOP_NUM == START_THREAD_NUM || STOP_NUM + COMPLETE_THREAD_NUM == START_THREAD_NUM;
}
/**
* 所有子线程是否都已经失败
*/
public boolean isFail() {
ALog.d(TAG, String.format("fail_num=%s; start_thread_num=%s, complete_num=%s", FAIL_NUM,
ALog.d(TAG, String.format("fail_num=%s; start_thread_num=%s; complete_num=%s", FAIL_NUM,
START_THREAD_NUM, COMPLETE_THREAD_NUM));
return COMPLETE_THREAD_NUM != START_THREAD_NUM
&& (FAIL_NUM == START_THREAD_NUM || FAIL_NUM + COMPLETE_THREAD_NUM == START_THREAD_NUM);

@ -9,8 +9,8 @@ import java.io.File;
public class SubThreadConfig<TASK_ENTITY extends AbsTaskEntity> {
//线程Id
public int THREAD_ID;
//下载文件大小
public long FILE_SIZE;
//文件总长度
public long TOTAL_FILE_SIZE;
//子线程启动下载位置
public long START_LOCATION;
//子线程结束下载位置

@ -47,4 +47,9 @@ public class ThreadRecord extends DbEntity {
* 线程id
*/
public int threadId = -1;
/**
* 分块长度
*/
public long blockLen = 0;
}

@ -1,78 +0,0 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.core.common;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 线程任务管理器
*/
class ThreadTaskManager {
private static volatile ThreadTaskManager INSTANCE = null;
private Map<String, List<AbsThreadTask>> mThreadTasks = new ConcurrentHashMap<>();
private ThreadTaskManager() {
}
public static ThreadTaskManager getInstance() {
if (INSTANCE == null) {
synchronized (ThreadTaskManager.class) {
INSTANCE = new ThreadTaskManager();
}
}
return INSTANCE;
}
/**
* 添加单条线程记录
*
* @param key 任务对应的key
* @param threadTask 线程任务
*/
public void addTask(String key, AbsThreadTask threadTask) {
if (mThreadTasks.get(key) == null) {
mThreadTasks.put(key, new ArrayList<AbsThreadTask>());
}
mThreadTasks.get(key).add(threadTask);
}
/**
* 删除对应的任务的线程记录
*
* @param key 任务对应的key
*/
public void removeTask(String key) {
for (Iterator<Map.Entry<String, List<AbsThreadTask>>> iter = mThreadTasks.entrySet().iterator();
iter.hasNext(); ) {
Map.Entry<String, List<AbsThreadTask>> entry = iter.next();
if (key.equals(entry.getKey())) {
List<AbsThreadTask> list = mThreadTasks.get(key);
if (list != null && !list.isEmpty()) {
list.clear();
}
iter.remove();
}
}
}
}

@ -13,26 +13,36 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.core.common;
package com.arialyy.aria.core.common.ftp;
import android.os.Process;
import android.text.TextUtils;
import aria.apache.commons.net.ftp.FTP;
import aria.apache.commons.net.ftp.FTPClient;
import aria.apache.commons.net.ftp.FTPFile;
import aria.apache.commons.net.ftp.FTPReply;
import aria.apache.commons.net.ftp.FTPSClient;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.common.ProtocolType;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.exception.AriaIOException;
import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.exception.FileException;
import com.arialyy.aria.exception.TaskException;
import com.arialyy.aria.util.ALog;
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.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import javax.net.ssl.SSLContext;
/**
* Created by Aria.Lao on 2017/7/25.
@ -69,6 +79,7 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
protected abstract String setRemotePath();
@Override public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
FTPClient client = null;
try {
client = createFtpClient();
@ -78,13 +89,16 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
}
String remotePath =
new String(setRemotePath().getBytes(charSet), AbsFtpThreadTask.SERVER_CHARSET);
if (mTaskEntity.getUrlEntity().isFtps) {
((FTPSClient) client).execPROT("P");
//((FTPSClient) client).enterLocalActiveMode();
}
FTPFile[] files = client.listFiles(remotePath);
String s = client.getReplyString();
ALog.i(TAG, s);
boolean isExist = files.length != 0;
if (!isExist && !isUpload) {
failDownload(String.format("文件不存在,任务链接【%s】,remotePath:%s", mTaskEntity.getUrlEntity().url,
remotePath), false);
failDownload(new FileException(TAG,
String.format("文件不存在,url: %s, remotePath:%s", mTaskEntity.getUrlEntity().url,
remotePath)), false);
int i = remotePath.lastIndexOf(File.separator);
FTPFile[] files1;
if (i == -1) {
@ -101,8 +115,7 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
ALog.i(TAG,
"================================= --end-- ===================================");
} else {
String msg = client.getReplyString();
ALog.w(TAG, msg);
ALog.w(TAG, String.format("获取文件列表失败,msg:%s", client.getReplyString()));
}
client.disconnect();
return;
@ -116,8 +129,9 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
mTaskEntity.setNewTask(true);
} else {
client.disconnect();
failDownload(String.format("获取文件信息错误,错误码为:%s,msg:%s", reply, client.getReplyString()),
true);
failDownload(new AriaIOException(TAG,
String.format("获取文件信息错误,url: %s, errorCode:%s, errorMsg:%s",
mTaskEntity.getUrlEntity().url, reply, client.getReplyString())), true);
return;
}
}
@ -128,15 +142,11 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
mTaskEntity.update();
onPreComplete(reply);
} catch (IOException e) {
failDownload(e.getMessage(), true);
failDownload(new AriaIOException(TAG,
String.format("FTP错误信息,code:%s,msg:%s", client.getReplyCode(), client.getReplyString()),
e), true);
} finally {
if (client != null) {
try {
client.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
closeClient(client);
}
}
@ -172,7 +182,7 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
Pattern p = Pattern.compile(Regular.REG_IP_V4);
Matcher m = p.matcher(urlEntity.hostName);
if (m.find() && m.groupCount() > 0) {
client = new FTPClient();
client = newInstanceClient(urlEntity);
InetAddress ip = InetAddress.getByName(urlEntity.hostName);
client.setConnectTimeout(mConnectTimeOut); // 连接10s超时
client.connect(ip, Integer.parseInt(urlEntity.port));
@ -182,11 +192,18 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
dnsThread.start();
dnsThread.join(mConnectTimeOut);
InetAddress[] ips = dnsThread.getIps();
client = connect(new FTPClient(), ips, 0, Integer.parseInt(urlEntity.port));
client = connect(newInstanceClient(urlEntity), ips, 0, Integer.parseInt(urlEntity.port));
}
if (urlEntity.isFtps) {
int code = ((FTPSClient) client).execAUTH(
TextUtils.isEmpty(urlEntity.protocol) ? ProtocolType.TLS : urlEntity.protocol);
ALog.d(TAG, String.format("cod:%s,msg:%s", code, client.getReplyString()));
}
if (client == null) {
failDownload("链接失败", false);
failDownload(new AriaIOException(TAG,
String.format("链接失败, url: %s", mTaskEntity.getUrlEntity().url)), false);
return null;
}
@ -199,43 +216,89 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
loginSuccess = client.login(urlEntity.user, urlEntity.password, urlEntity.account);
}
} catch (IOException e) {
ALog.e(TAG, client.getReplyString());
ALog.e(TAG,
new TaskException(TAG, String.format("登录失败,错误码为:%s, msg:%s", client.getReplyCode(),
client.getReplyString()), e));
return null;
}
}
if (!loginSuccess) {
failDownload("登录失败", false);
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(String.format("无法连接到ftp服务器,错误码为:%s,msg:%s", reply, client.getReplyString()),
failDownload(new AriaIOException(TAG,
String.format("无法连接到ftp服务器,filePath: %s, url: %s, errorCode: %s, errorMsg:%s",
mEntity.getKey(), mTaskEntity.getUrlEntity().url, reply, client.getReplyString())),
true);
return null;
}
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
charSet = "UTF-8";
reply = client.sendCommand("OPTS UTF8", "ON");
if (!TextUtils.isEmpty(mTaskEntity.getCharSet()) || (!FTPReply.isPositiveCompletion(reply)
&& reply != FTPReply.COMMAND_OK)) {
if (reply != FTPReply.COMMAND_IS_SUPERFLUOUS) {
ALog.i(TAG, "FTP 服务器不支持开启UTF8编码,尝试使用Aria手动设置的编码");
charSet = mTaskEntity.getCharSet();
if (!TextUtils.isEmpty(mTaskEntity.getCharSet())) {
charSet = mTaskEntity.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();
}
return client;
}
private void closeClient(FTPClient client) {
try {
if (client != null && client.isConnected()) {
client.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 创建FTP/FTPS客户端
*/
private FTPClient newInstanceClient(FtpUrlEntity urlEntity) {
FTPClient temp = null;
if (urlEntity.isFtps) {
SSLContext sslContext =
SSLContextUtil.getSSLContext(urlEntity.keyAlias, urlEntity.storePath, urlEntity.protocol);
if (sslContext == null) {
sslContext = SSLContextUtil.getDefaultSLLContext(urlEntity.protocol);
}
//System.setProperty("jdk.tls.useExtendedMasterSecret", "false");
//FTPSClient client = new SSLSessionReuseFTPSClient(true, sslContext);
FTPSClient client = new FTPSClient(true, sslContext);
//Log.d(TAG, "session = " + client.getEnableSessionCreation());
temp = client;
} else {
temp = new FTPClient();
}
return temp;
}
/**
* 连接到ftp服务器
*/
@ -268,7 +331,7 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
e1.printStackTrace();
}
ALog.w(TAG, "遇到[ECONNREFUSED-连接被服务器拒绝]错误,正在尝试下一个地址");
return connect(new FTPClient(), ips, index + 1, port);
return connect(newInstanceClient(mTaskEntity.getUrlEntity()), ips, index + 1, port);
}
}
@ -302,10 +365,9 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
protected void handleFile(String remotePath, FTPFile ftpFile) {
}
private void failDownload(String errorMsg, boolean needRetry) {
ALog.e(TAG, errorMsg);
private void failDownload(BaseException e, boolean needRetry) {
if (mCallback != null) {
mCallback.onFail(mEntity.getKey(), errorMsg, needRetry);
mCallback.onFail(mEntity.getKey(), e, needRetry);
}
}

@ -13,20 +13,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.core.common;
package com.arialyy.aria.core.common.ftp;
import android.text.TextUtils;
import aria.apache.commons.net.ftp.FTP;
import aria.apache.commons.net.ftp.FTPClient;
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.AbsThreadTask;
import com.arialyy.aria.core.common.ProtocolType;
import com.arialyy.aria.core.common.StateConstance;
import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEventListener;
import com.arialyy.aria.exception.AriaIOException;
import com.arialyy.aria.util.ALog;
import java.io.IOException;
import com.arialyy.aria.util.SSLContextUtil;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import javax.net.ssl.SSLContext;
/**
* Created by lyy on 2017/9/26.
@ -35,7 +42,7 @@ import org.apache.commons.net.ftp.FTPReply;
public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
extends AbsThreadTask<ENTITY, TASK_ENTITY> {
private final String TAG = "AbsFtpThreadTask";
protected String charSet, port;
protected String charSet;
/**
* D_FTP 服务器编码
*/
@ -55,7 +62,7 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
if (urlEntity.validAddr == null) {
try {
InetAddress[] ips = InetAddress.getAllByName(urlEntity.hostName);
client = connect(new FTPClient(), ips, 0, Integer.parseInt(urlEntity.port));
client = connect(newInstanceClient(urlEntity), ips, 0, Integer.parseInt(urlEntity.port));
if (client == null) {
return null;
}
@ -63,10 +70,10 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
e.printStackTrace();
}
} else {
client = new FTPClient();
client = newInstanceClient(urlEntity);
try {
client.connect(urlEntity.validAddr, Integer.parseInt(urlEntity.port));
} catch (IOException e) {
} catch (java.io.IOException e) {
ALog.e(TAG, ALog.getExceptionString(e));
return null;
}
@ -77,6 +84,12 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
}
try {
if (urlEntity.isFtps) {
int code = ((FTPSClient) client).execAUTH(
TextUtils.isEmpty(urlEntity.protocol) ? ProtocolType.TLS : urlEntity.protocol);
ALog.d(TAG, String.format("cod:%s,msg:%s", code, client.getReplyString()));
}
if (urlEntity.needLogin) {
if (TextUtils.isEmpty(urlEntity.account)) {
client.login(urlEntity.user, urlEntity.password);
@ -87,15 +100,16 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
fail(mChildCurrentLocation,
String.format("无法连接到ftp服务器,错误码为:%s,msg:%s", reply, client.getReplyString()), null);
fail(mChildCurrentLocation, new AriaIOException(TAG,
String.format("无法连接到ftp服务器,错误码为:%s,msg:%s", reply, client.getReplyString())), false);
return null;
}
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
charSet = "UTF-8";
if (!TextUtils.isEmpty(mTaskEntity.getCharSet()) || !FTPReply.isPositiveCompletion(
client.sendCommand("OPTS UTF8", "ON"))) {
charSet = mTaskEntity.getCharSet();
if (reply != FTPReply.COMMAND_IS_SUPERFLUOUS) {
if (!TextUtils.isEmpty(mTaskEntity.getCharSet())) {
charSet = mTaskEntity.getCharSet();
}
}
client.setControlEncoding(charSet);
client.setDataTimeout(mReadTimeOut);
@ -103,12 +117,34 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
client.setControlKeepAliveTimeout(5000);
} catch (IOException e) {
if (mTaskEntity.getUrlEntity().isFtps) {
((FTPSClient) client).execPROT("P");
}
} catch (java.io.IOException e) {
e.printStackTrace();
}
return client;
}
/**
* 创建FTP/FTPS客户端
*/
private FTPClient newInstanceClient(FtpUrlEntity urlEntity) {
FTPClient temp;
if (urlEntity.isFtps) {
SSLContext sslContext =
SSLContextUtil.getSSLContext(urlEntity.keyAlias, urlEntity.storePath, urlEntity.protocol);
if (sslContext == null) {
sslContext = SSLContextUtil.getDefaultSLLContext(urlEntity.protocol);
}
temp = new FTPSClient(true, sslContext);
} else {
temp = new FTPClient();
}
return temp;
}
/**
* 连接到ftp服务器
*/
@ -117,12 +153,12 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
client.connect(ips[index], port);
mTaskEntity.getUrlEntity().validAddr = ips[index];
return client;
} catch (IOException e) {
} catch (java.io.IOException e) {
try {
if (client.isConnected()) {
client.disconnect();
}
} catch (IOException e1) {
} catch (java.io.IOException e1) {
e1.printStackTrace();
}
if (index + 1 >= ips.length) {

@ -0,0 +1,104 @@
/*
* 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;
import android.text.TextUtils;
import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.ProtocolType;
import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.inf.ITarget;
/**
* FTP SSL/TSL配置
*/
public class FTPSConfig<TARGET extends AbsTarget> implements ITarget {
private final String TAG = "FTPSConfig";
private TARGET mTarget;
private FtpUrlEntity mUrlEntity;
public FTPSConfig(TARGET target) {
mTarget = target;
mUrlEntity = mTarget.getTaskEntity().getUrlEntity();
}
/**
* 设置协议类型
*
* @param protocol {@link ProtocolType}
*/
public FTPSConfig setProtocol(@ProtocolType String protocol) {
if (TextUtils.isEmpty(protocol)) {
throw new NullPointerException("协议为空");
}
mUrlEntity.protocol = protocol;
return this;
}
/**
* 设置证书别名
*
* @param keyAlias 别名
*/
public FTPSConfig setAlias(String keyAlias) {
if (TextUtils.isEmpty(keyAlias)) {
throw new NullPointerException("别名为空");
}
mUrlEntity.keyAlias = keyAlias;
return this;
}
/**
* 设置证书密码
*
* @param storePass 私钥密码
*/
public FTPSConfig setStorePass(String storePass) {
if (TextUtils.isEmpty(storePass)) {
throw new NullPointerException("证书密码为空");
}
mUrlEntity.storePass = storePass;
return this;
}
/**
* 设置证书路径
*
* @param storePath 证书路径
*/
public FTPSConfig setStorePath(String storePath) {
if (TextUtils.isEmpty(storePath)) {
throw new NullPointerException("证书路径为空");
}
mUrlEntity.storePath = storePath;
return this;
}
@Override public void start() {
mTarget.start();
}
@Override public void stop() {
mTarget.stop();
}
@Override public void resume() {
mTarget.resume();
}
@Override public void cancel() {
mTarget.cancel();
}
}

@ -13,35 +13,34 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.core.delegate;
package com.arialyy.aria.core.common.ftp;
import android.text.TextUtils;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.inf.IFtpTarget;
import com.arialyy.aria.core.inf.ITarget;
import com.arialyy.aria.util.ALog;
import java.net.Proxy;
/**
* Created by laoyuyu on 2018/3/9.
* ftp 委托
*/
public class FtpDelegate<TARGET extends ITarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements IFtpTarget<TARGET> {
public class FtpDelegate<TARGET extends AbsTarget> implements IFtpTarget<TARGET> {
private static final String TAG = "FtpDelegate";
private ENTITY mEntity;
private TASK_ENTITY mTaskEntity;
private FtpUrlEntity mUrlEntity;
private TARGET mTarget;
public FtpDelegate(TARGET target, TASK_ENTITY taskEntity) {
public FtpDelegate(TARGET target) {
mTarget = target;
mTaskEntity = taskEntity;
mEntity = mTaskEntity.getEntity();
mUrlEntity = target.getTaskEntity().getUrlEntity();
}
@Override public TARGET charSet(String charSet) {
if (TextUtils.isEmpty(charSet)) return mTarget;
mTaskEntity.setCharSet(charSet);
if (TextUtils.isEmpty(charSet)) {
throw new NullPointerException("字符编码为空");
}
mTarget.getTaskEntity().setCharSet(charSet);
return mTarget;
}
@ -57,10 +56,15 @@ public class FtpDelegate<TARGET extends ITarget, ENTITY extends AbsEntity, TASK_
ALog.e(TAG, "密码不能为null");
return mTarget;
}
mTaskEntity.getUrlEntity().needLogin = true;
mTaskEntity.getUrlEntity().user = userName;
mTaskEntity.getUrlEntity().password = password;
mTaskEntity.getUrlEntity().account = account;
mUrlEntity.needLogin = true;
mUrlEntity.user = userName;
mUrlEntity.password = password;
mUrlEntity.account = account;
return mTarget;
}
@Override public TARGET setProxy(Proxy proxy) {
mTarget.getTaskEntity().setProxy(proxy);
return mTarget;
}
}

@ -0,0 +1,52 @@
package com.arialyy.aria.core.common.ftp;
import aria.apache.commons.net.ftp.FTPSClient;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.Locale;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.SSLSocket;
public class SSLSessionReuseFTPSClient extends FTPSClient {
SSLSessionReuseFTPSClient(boolean b, SSLContext context) {
super(b, context);
}
// adapted from:
// https://trac.cyberduck.io/browser/trunk/ftp/src/main/java/ch/cyberduck/core/ftp/FTPClient.java
@Override
protected void _prepareDataSocket_(final Socket socket) throws IOException {
if (socket instanceof SSLSocket) {
// Control socket is SSL
final SSLSession session = ((SSLSocket) _socket_).getSession();
if (session.isValid()) {
final SSLSessionContext context = session.getSessionContext();
try {
//final Field sessionHostPortCache = context.getClass().getDeclaredField("sessionHostPortCache");
final Field sessionHostPortCache =
context.getClass().getDeclaredField("sessionsByHostAndPort");
sessionHostPortCache.setAccessible(true);
final Object cache = sessionHostPortCache.get(context);
final Method method =
cache.getClass().getDeclaredMethod("put", Object.class, Object.class);
method.setAccessible(true);
method.invoke(cache, String.format("%s:%s", socket.getInetAddress().getHostName(),
String.valueOf(socket.getPort())).toLowerCase(Locale.ROOT), session);
method.invoke(cache, String.format("%s:%s", socket.getInetAddress().getHostAddress(),
String.valueOf(socket.getPort())).toLowerCase(Locale.ROOT), session);
} catch (NoSuchFieldException e) {
throw new IOException(e);
} catch (Exception e) {
throw new IOException(e);
}
} else {
throw new IOException("Invalid SSL Session");
}
}
}
}

@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.core.delegate;
package com.arialyy.aria.core.common.http;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IHttpHeaderTarget;
import com.arialyy.aria.core.inf.ITarget;
import com.arialyy.aria.core.inf.IHttpHeaderDelegate;
import com.arialyy.aria.util.ALog;
import java.net.Proxy;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
@ -31,18 +30,13 @@ import java.util.Set;
* Created by laoyuyu on 2018/3/9.
* HTTP header参数设置委托类
*/
public class HttpHeaderDelegate<TARGET extends ITarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements IHttpHeaderTarget<TARGET> {
public class HttpHeaderDelegate<TARGET extends AbsTarget>
implements IHttpHeaderDelegate<TARGET> {
private static final String TAG = "HttpHeaderDelegate";
private ENTITY mEntity;
private TASK_ENTITY mTaskEntity;
private TARGET mTarget;
public HttpHeaderDelegate(TARGET target, TASK_ENTITY taskEntity) {
public HttpHeaderDelegate(TARGET target) {
mTarget = target;
mTaskEntity = taskEntity;
mEntity = mTaskEntity.getEntity();
}
/**
@ -61,7 +55,7 @@ public class HttpHeaderDelegate<TARGET extends ITarget, ENTITY extends AbsEntity
ALog.w(TAG, "设置header失败,header对应的value不能为null");
return mTarget;
}
addHeader(mTaskEntity, key, value);
addHeader(mTarget.getTaskEntity(), key, value);
return mTarget;
}
@ -77,19 +71,12 @@ public class HttpHeaderDelegate<TARGET extends ITarget, ENTITY extends AbsEntity
ALog.w(TAG, "设置header失败,map没有header数据");
return mTarget;
}
addHeaders(mTaskEntity, headers);
addHeaders(mTarget.getTaskEntity(), headers);
return mTarget;
}
/**
* 设置请求类型POST或GET默认为在GET
* 只试用于HTTP请求
*
* @param requestEnum {@link RequestEnum}
*/
@Override
public TARGET setRequestMode(RequestEnum requestEnum) {
setRequestMode(mTaskEntity, requestEnum);
@Override public TARGET setUrlProxy(Proxy proxy) {
mTarget.getTaskEntity().setProxy(proxy);
return mTarget;
}
@ -101,10 +88,6 @@ public class HttpHeaderDelegate<TARGET extends ITarget, ENTITY extends AbsEntity
}
}
public void setRequestMode(AbsTaskEntity taskEntity, RequestEnum requestEnum) {
taskEntity.setRequestEnum(requestEnum);
}
public void addHeaders(AbsTaskEntity taskEntity, Map<String, String> headers) {
/*
两个map比较逻辑

@ -0,0 +1,86 @@
/*
* 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.http;
import android.text.TextUtils;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.download.DownloadGroupTarget;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.inf.IPostDelegate;
import com.arialyy.aria.core.inf.ITarget;
import com.arialyy.aria.util.ALog;
import java.util.HashMap;
import java.util.Map;
/**
* post处理委托类
*/
public class PostDelegate<TARGET extends AbsTarget> implements IPostDelegate<TARGET>, ITarget {
private static final String TAG = "PostDelegate";
private TARGET mTarget;
public PostDelegate(TARGET target) {
mTarget = target;
mTarget.getTaskEntity().setRequestEnum(RequestEnum.POST);
}
@Override public TARGET setParams(Map<String, String> params) {
mTarget.getTaskEntity().setParams(params);
if (mTarget instanceof DownloadGroupTarget) {
for (DownloadTaskEntity subTask : ((DownloadGroupTaskEntity) mTarget.getTaskEntity()).getSubTaskEntities()) {
subTask.setParams(params);
}
}
return mTarget;
}
@Override public TARGET setParam(String key, String value) {
if (TextUtils.isEmpty(key) || TextUtils.isEmpty(value)) {
ALog.d(TAG, "key 或value 为空");
return mTarget;
}
Map<String, String> params = mTarget.getTaskEntity().getParams();
if (params == null) {
params = new HashMap<>();
mTarget.getTaskEntity().setParams(params);
}
params.put(key, value);
if (mTarget instanceof DownloadGroupTarget) {
for (DownloadTaskEntity subTask : ((DownloadGroupTaskEntity) mTarget.getTaskEntity()).getSubTaskEntities()) {
subTask.setParams(params);
}
}
return mTarget;
}
@Override public void start() {
mTarget.start();
}
@Override public void stop() {
mTarget.stop();
}
@Override public void resume() {
mTarget.resume();
}
@Override public void cancel() {
mTarget.cancel();
}
}

@ -40,6 +40,11 @@ abstract class AbsDownloadTarget<TARGET extends AbsTarget, ENTITY extends AbsEnt
*/
String mTempFilePath;
/**
* {@code true}强制下载不考虑文件路径是否被占用
*/
boolean forceDownload = false;
/**
* 将任务设置为最高优先级任务最高优先级任务有以下特点
* 1在下载队列中有且只有一个最高优先级任务
@ -52,8 +57,8 @@ abstract class AbsDownloadTarget<TARGET extends AbsTarget, ENTITY extends AbsEnt
protected void setHighestPriority() {
if (checkEntity()) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity,
NormalCmdFactory.TASK_HIGHEST_PRIORITY, checkTaskType()))
.setCmd(CommonUtil.createNormalCmd(mTaskEntity, NormalCmdFactory.TASK_HIGHEST_PRIORITY,
checkTaskType()))
.exe();
}
}
@ -64,7 +69,7 @@ abstract class AbsDownloadTarget<TARGET extends AbsTarget, ENTITY extends AbsEnt
public void add() {
if (checkEntity()) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE,
.setCmd(CommonUtil.createNormalCmd(mTaskEntity, NormalCmdFactory.TASK_CREATE,
checkTaskType()))
.exe();
}

@ -16,53 +16,27 @@
package com.arialyy.aria.core.download;
import android.os.Handler;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.BaseListener;
import com.arialyy.aria.core.common.TaskRecord;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IDownloadListener;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CommonUtil;
import java.lang.ref.WeakReference;
/**
* 下载监听类
*/
class BaseDListener<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>, TASK extends AbsTask<TASK_ENTITY>>
class BaseDListener extends BaseListener<DownloadEntity, DownloadTaskEntity, DownloadTask>
implements IDownloadListener {
private static final String TAG = "BaseDListener";
WeakReference<Handler> outHandler;
private int RUN_SAVE_INTERVAL = 5 * 1000; //5s保存一次下载中的进度
private long mLastLen = 0; //上一次发送长度
private boolean isFirst = true;
protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity;
private TASK mTask;
private boolean isConvertSpeed = false;
boolean isWait = false;
private long mLastSaveTime;
private long mUpdateInterval;
BaseDListener(TASK task, Handler outHandler) {
this.outHandler = new WeakReference<>(outHandler);
this.mTask = new WeakReference<>(task).get();
this.mEntity = mTask.getTaskEntity().getEntity();
this.mTaskEntity = mTask.getTaskEntity();
final AriaManager manager = AriaManager.getInstance(AriaManager.APP);
BaseDListener(DownloadTask task, Handler outHandler) {
super(task, outHandler);
isConvertSpeed = manager.getDownloadConfig().isConvertSpeed();
mLastLen = mEntity.getCurrentProgress();
mLastSaveTime = System.currentTimeMillis();
mUpdateInterval = manager.getDownloadConfig().getUpdateInterval();
}
@Override public void onPre() {
saveData(IEntity.STATE_PRE, -1);
sendInState2Target(ISchedulers.PRE);
}
@Override public void onPostPre(long fileSize) {
mEntity.setFileSize(fileSize);
mEntity.setConvertFileSize(CommonUtil.formatFileSize(fileSize));
@ -74,84 +48,8 @@ class BaseDListener<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<
}
@Override public void onStart(long startLocation) {
saveData(IEntity.STATE_RUNNING, startLocation);
sendInState2Target(ISchedulers.START);
}
@Override public void onResume(long resumeLocation) {
saveData(IEntity.STATE_RUNNING, resumeLocation);
sendInState2Target(ISchedulers.RESUME);
}
@Override public void onProgress(long currentLocation) {
mEntity.setCurrentProgress(currentLocation);
long speed = currentLocation - mLastLen;
if (isFirst) {
speed = 0;
isFirst = false;
}
handleSpeed(speed);
sendInState2Target(ISchedulers.RUNNING);
if (System.currentTimeMillis() - mLastSaveTime >= RUN_SAVE_INTERVAL) {
saveData(IEntity.STATE_RUNNING, currentLocation);
mLastSaveTime = System.currentTimeMillis();
}
mLastLen = currentLocation;
}
@Override public void onStop(long stopLocation) {
saveData(isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP, stopLocation);
handleSpeed(0);
sendInState2Target(ISchedulers.STOP);
}
@Override public void onCancel() {
saveData(IEntity.STATE_CANCEL, -1);
handleSpeed(0);
sendInState2Target(ISchedulers.CANCEL);
}
@Override public void onComplete() {
saveData(IEntity.STATE_COMPLETE, mEntity.getFileSize());
handleSpeed(0);
sendInState2Target(ISchedulers.COMPLETE);
}
@Override public void onFail(boolean needRetry) {
mEntity.setFailNum(mEntity.getFailNum() + 1);
saveData(IEntity.STATE_FAIL, mEntity.getCurrentProgress());
handleSpeed(0);
mTask.needRetry = needRetry;
sendInState2Target(ISchedulers.FAIL);
}
private void handleSpeed(long speed) {
if (mUpdateInterval != 1000) {
speed = speed * 1000 / mUpdateInterval;
}
if (isConvertSpeed) {
mEntity.setConvertSpeed(CommonUtil.formatFileSize(speed < 0 ? 0 : speed) + "/s");
}
mEntity.setSpeed(speed < 0 ? 0 : speed);
mEntity.setPercent((int) (mEntity.getFileSize() <= 0 ? 0
: mEntity.getCurrentProgress() * 100 / mEntity.getFileSize()));
}
/**
* 将任务状态发送给下载器
*
* @param state {@link ISchedulers#START}
*/
private void sendInState2Target(int state) {
if (outHandler.get() != null) {
outHandler.get().obtainMessage(state, mTask).sendToTarget();
}
}
private void saveData(int state, long location) {
@Override
protected void saveData(int state, long location) {
mTaskEntity.setState(state);
mEntity.setState(state);
mEntity.setComplete(state == IEntity.STATE_COMPLETE);
@ -160,14 +58,11 @@ class BaseDListener<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<
TaskRecord record =
DbEntity.findFirst(TaskRecord.class, "TaskRecord.filePath=?", mTaskEntity.getKey());
if (record != null) {
CommonUtil.delTaskRecord(record, mTaskEntity.isRemoveFile(), (DownloadEntity) mEntity);
CommonUtil.delTaskRecord(record, mTaskEntity.isRemoveFile(), mEntity);
} else {
mEntity.deleteData();
}
} else if (mEntity instanceof DownloadGroupEntity) {
CommonUtil.delGroupTaskRecord(mTaskEntity.isRemoveFile(), ((DownloadGroupEntity) mEntity));
}
//mEntity.deleteData();
return;
} else if (state == IEntity.STATE_STOP) {
mEntity.setStopTime(System.currentTimeMillis());

@ -25,7 +25,7 @@ import java.io.File;
import java.util.List;
/**
* Created by Aria.Lao on 2017/7/26.
* Created by lyy on 2017/7/26.
*/
abstract class BaseGroupTarget<TARGET extends BaseGroupTarget>
extends AbsDownloadTarget<TARGET, DownloadGroupEntity, DownloadGroupTaskEntity> {

@ -86,7 +86,7 @@ abstract class BaseNormalTarget<TARGET extends BaseNormalTarget>
* @return {@code true}任务存在
*/
@Override public boolean taskExists() {
return DownloadTaskQueue.getInstance().getTask(mEntity.getUrl()) != null;
return DownloadTaskQueue.getInstance().getTask(mEntity.getKey()) != null;
}
/**
@ -162,11 +162,17 @@ abstract class BaseNormalTarget<TARGET extends BaseNormalTarget>
}
}
//设置文件保存路径,如果新文件路径和文件路径不同,则修改路径
//设置文件保存路径,如果新文件路径和文件路径不同,则修改路径
if (!filePath.equals(mEntity.getDownloadPath())) {
if (DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=?", filePath)) {
ALog.e(TAG, "下载失败,保存路径【" + filePath + "】已经被其它任务占用,请设置其它保存路径");
return false;
if (!forceDownload) {
ALog.e(TAG, "下载失败,保存路径【" + filePath + "】已经被其它任务占用,请设置其它保存路径");
return false;
}else {
ALog.d(TAG, "保存路径【" + filePath + "】已经被其它任务占用,当前任务将覆盖该路径的文件");
DbEntity.deleteData(DownloadEntity.class, "downloadPath=?", filePath);
mTaskEntity = TEManager.getInstance().getTEntity(DownloadTaskEntity.class, url);
}
}
File oldFile = new File(mEntity.getDownloadPath());
File newFile = new File(filePath);
@ -200,7 +206,7 @@ abstract class BaseNormalTarget<TARGET extends BaseNormalTarget>
ALog.e(TAG, "下载失败,url【" + url + "】不合法");
return false;
}
if (!TextUtils.isEmpty(newUrl)){
if (!TextUtils.isEmpty(newUrl)) {
mEntity.setUrl(newUrl);
mTaskEntity.setUrl(newUrl);
}

@ -16,17 +16,22 @@
package com.arialyy.aria.core.download;
import android.os.Handler;
import com.arialyy.aria.core.common.BaseListener;
import com.arialyy.aria.core.download.downloader.IDownloadGroupListener;
import com.arialyy.aria.core.inf.GroupSendParams;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.ErrorHelp;
/**
* Created by Aria.Lao on 2017/7/20.
* 任务组下载事件
*/
class DownloadGroupListener
extends BaseDListener<DownloadGroupEntity, DownloadGroupTaskEntity, DownloadGroupTask>
extends BaseListener<DownloadGroupEntity, DownloadGroupTaskEntity, DownloadGroupTask>
implements IDownloadGroupListener {
private final String TAG = "DownloadGroupListener";
private GroupSendParams<DownloadGroupTask, DownloadEntity> mSeedEntity;
@ -35,6 +40,8 @@ class DownloadGroupListener
super(task, outHandler);
mSeedEntity = new GroupSendParams<>();
mSeedEntity.groupTask = task;
isConvertSpeed = manager.getDownloadConfig().isConvertSpeed();
mUpdateInterval = manager.getDownloadConfig().getUpdateInterval();
}
@Override public void onSubPre(DownloadEntity subEntity) {
@ -59,9 +66,11 @@ class DownloadGroupListener
sendInState2Target(ISchedulers.SUB_COMPLETE, subEntity);
}
@Override public void onSubFail(DownloadEntity subEntity) {
@Override public void onSubFail(DownloadEntity subEntity, BaseException e) {
saveCurrentLocation();
sendInState2Target(ISchedulers.SUB_FAIL, subEntity);
e.printStackTrace();
ErrorHelp.saveError(e.getTag(), "", ALog.getExceptionString(e));
}
@Override public void onSubCancel(DownloadEntity subEntity) {
@ -100,4 +109,36 @@ class DownloadGroupListener
mEntity.setCurrentProgress(location);
mEntity.update();
}
@Override public void onPostPre(long fileSize) {
mEntity.setFileSize(fileSize);
mEntity.setConvertFileSize(CommonUtil.formatFileSize(fileSize));
saveData(IEntity.STATE_POST_PRE, -1);
sendInState2Target(ISchedulers.POST_PRE);
}
@Override public void supportBreakpoint(boolean support) {
}
@Override protected void saveData(int state, long location) {
mTaskEntity.setState(state);
mEntity.setState(state);
mEntity.setComplete(state == IEntity.STATE_COMPLETE);
if (state == IEntity.STATE_CANCEL) {
if (mEntity instanceof DownloadGroupEntity) {
CommonUtil.delGroupTaskRecord(mTaskEntity.isRemoveFile(), mEntity);
}
return;
} else if (state == IEntity.STATE_STOP) {
mEntity.setStopTime(System.currentTimeMillis());
} else if (mEntity.isComplete()) {
mEntity.setCompleteTime(System.currentTimeMillis());
mEntity.setCurrentProgress(mEntity.getFileSize());
}
if (location > 0) {
mEntity.setCurrentProgress(location);
}
mTaskEntity.update();
}
}

@ -19,12 +19,15 @@ import android.support.annotation.CheckResult;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.delegate.HttpHeaderDelegate;
import com.arialyy.aria.core.inf.IHttpHeaderTarget;
import com.arialyy.aria.core.common.http.HttpHeaderDelegate;
import com.arialyy.aria.core.common.http.PostDelegate;
import com.arialyy.aria.core.inf.IHttpHeaderDelegate;
import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.net.Proxy;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@ -36,9 +39,8 @@ import java.util.Set;
* 下载任务组
*/
public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> implements
IHttpHeaderTarget<DownloadGroupTarget> {
private HttpHeaderDelegate<DownloadGroupTarget, DownloadGroupEntity, DownloadGroupTaskEntity>
mDelegate;
IHttpHeaderDelegate<DownloadGroupTarget> {
private HttpHeaderDelegate<DownloadGroupTarget> mDelegate;
/**
* 子任务下载地址
*/
@ -67,11 +69,45 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> im
mGroupName = CommonUtil.getMd5Code(mUrls);
mTaskEntity = TEManager.getInstance().getGTEntity(DownloadGroupTaskEntity.class, mUrls);
mEntity = mTaskEntity.getEntity();
if (mEntity != null) {
mDirPathTemp = mEntity.getDirPath();
}
mDelegate = new HttpHeaderDelegate<>(this, mTaskEntity);
mDelegate = new HttpHeaderDelegate<>(this);
}
/**
* Post处理
*/
public PostDelegate asPost() {
return new PostDelegate<>(this);
}
/**
* 更新组合任务下载地址
*
* @param urls 新的组合任务下载地址列表
*/
@CheckResult
public DownloadGroupTarget updateUrls(List<String> urls) {
if (urls == null || urls.isEmpty()) {
throw new NullPointerException("下载地址列表为空");
}
if (urls.size() != mUrls.size()) {
throw new IllegalArgumentException("新下载地址数量和旧下载地址数量不一致");
}
mUrls.clear();
mUrls.addAll(urls);
mGroupName = CommonUtil.getMd5Code(urls);
mEntity.setGroupName(mGroupName);
mTaskEntity.setKey(mGroupName);
mEntity.update();
if (mEntity.getSubEntities() != null && !mEntity.getSubEntities().isEmpty()) {
for (DownloadEntity de : mEntity.getSubEntities()) {
de.setGroupName(mGroupName);
de.update();
}
}
return this;
}
/**
@ -150,6 +186,12 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> im
return false;
}
if (mTaskEntity.getRequestEnum() == RequestEnum.POST) {
for (DownloadTaskEntity subTask : mTaskEntity.getSubTaskEntities()) {
subTask.setRequestEnum(RequestEnum.POST);
}
}
mEntity.save();
mTaskEntity.save();
@ -234,10 +276,17 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> im
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));
return;
}
File oldFile = new File(oldPath);
if (oldFile.exists()) {
oldFile.renameTo(new File(newPath));
}
CommonUtil.modifyTaskRecord(oldFile.getPath(), newPath);
entity.setDownloadPath(newPath);
taskEntity.setKey(newPath);
@ -263,6 +312,7 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> im
return true;
}
@CheckResult
@Override public DownloadGroupTarget addHeader(@NonNull String key, @NonNull String value) {
for (DownloadTaskEntity subTask : mTaskEntity.getSubTaskEntities()) {
mDelegate.addHeader(subTask, key, value);
@ -270,6 +320,7 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> im
return mDelegate.addHeader(key, value);
}
@CheckResult
@Override public DownloadGroupTarget addHeaders(Map<String, String> headers) {
for (DownloadTaskEntity subTask : mTaskEntity.getSubTaskEntities()) {
mDelegate.addHeaders(subTask, headers);
@ -277,10 +328,8 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> im
return mDelegate.addHeaders(headers);
}
@Override public DownloadGroupTarget setRequestMode(RequestEnum requestEnum) {
for (DownloadTaskEntity subTask : mTaskEntity.getSubTaskEntities()) {
subTask.setRequestEnum(requestEnum);
}
return mDelegate.setRequestMode(requestEnum);
@CheckResult
@Override public DownloadGroupTarget setUrlProxy(Proxy proxy) {
return mDelegate.setUrlProxy(proxy);
}
}

@ -18,23 +18,20 @@ package com.arialyy.aria.core.download;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.downloader.DownloadGroupUtil;
import com.arialyy.aria.core.download.downloader.FtpDirDownloadUtil;
import com.arialyy.aria.core.download.downloader.IDownloadGroupListener;
import com.arialyy.aria.core.inf.AbsGroupTask;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
/**
* Created by AriaL on 2017/6/27.
* 任务组任务
*/
public class DownloadGroupTask extends AbsGroupTask<DownloadGroupTaskEntity> {
private final String TAG = "DownloadGroupTask";
private DownloadGroupListener mListener;
public class DownloadGroupTask extends AbsGroupTask<DownloadGroupEntity, DownloadGroupTaskEntity> {
private DownloadGroupTask(DownloadGroupTaskEntity taskEntity, Handler outHandler) {
mTaskEntity = taskEntity;
@ -43,49 +40,18 @@ public class DownloadGroupTask extends AbsGroupTask<DownloadGroupTaskEntity> {
mListener = new DownloadGroupListener(this, mOutHandler);
switch (taskEntity.getRequestType()) {
case AbsTaskEntity.D_HTTP:
mUtil = new DownloadGroupUtil(mListener, mTaskEntity);
mUtil = new DownloadGroupUtil((IDownloadGroupListener) mListener, mTaskEntity);
break;
case AbsTaskEntity.D_FTP_DIR:
mUtil = new FtpDirDownloadUtil(mListener, mTaskEntity);
mUtil = new FtpDirDownloadUtil((IDownloadGroupListener) mListener, mTaskEntity);
break;
}
Log.d(TAG, "FTP_TASK_MD5:" + mTaskEntity.hashCode());
}
@Override public boolean isRunning() {
return mUtil.isRunning();
}
public DownloadGroupEntity getEntity() {
return mTaskEntity.getEntity();
}
@Override public void start() {
if (mUtil.isRunning()) {
ALog.d(TAG, "任务正在下载");
} else {
mUtil.start();
}
}
@Override public void stop() {
super.stop();
if (!mUtil.isRunning()) {
mListener.onStop(getCurrentProgress());
} else {
mUtil.stop();
}
}
@Override public void cancel() {
super.cancel();
if (!mUtil.isRunning()) {
mListener.onCancel();
} else {
mUtil.cancel();
}
}
@Override public String getTaskName() {
return "任务组->" + (TextUtils.isEmpty(mTaskEntity.getEntity().getAlias())
? mTaskEntity.getEntity().getGroupName() : mTaskEntity.getEntity().getAlias());
@ -94,11 +60,9 @@ public class DownloadGroupTask extends AbsGroupTask<DownloadGroupTaskEntity> {
public static class Builder {
DownloadGroupTaskEntity taskEntity;
Handler outHandler;
String targetName;
public Builder(String targetName, DownloadGroupTaskEntity taskEntity) {
public Builder(DownloadGroupTaskEntity taskEntity) {
CheckUtil.checkTaskEntity(taskEntity);
this.targetName = targetName;
this.taskEntity = taskEntity;
}
@ -108,19 +72,12 @@ public class DownloadGroupTask extends AbsGroupTask<DownloadGroupTaskEntity> {
* @param schedulers {@link ISchedulers}
*/
public DownloadGroupTask.Builder setOutHandler(ISchedulers schedulers) {
try {
outHandler = new Handler(schedulers);
} catch (Exception e) {
e.printStackTrace();
outHandler = new Handler(Looper.getMainLooper(), schedulers);
}
outHandler = new Handler(Looper.getMainLooper(), schedulers);
return this;
}
public DownloadGroupTask build() {
DownloadGroupTask task = new DownloadGroupTask(taskEntity, outHandler);
task.setTargetName(targetName);
return task;
return new DownloadGroupTask(taskEntity, outHandler);
}
}
}

@ -47,12 +47,12 @@ public class DownloadReceiver extends AbsReceiver {
/**
* 设置最大下载速度单位kb
* 该方法为实验性功能清不要轻易在生产环境中使用
*
* @param maxSpeed 为0表示不限速
*/
@Deprecated public void setMaxSpeed(int maxSpeed) {
public DownloadReceiver setMaxSpeed(int maxSpeed) {
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().setMaxSpeed(maxSpeed);
return this;
}
/**
@ -160,15 +160,17 @@ public class DownloadReceiver extends AbsReceiver {
ALog.e(TAG, String.format("【%s】观察者为空", targetName));
return;
}
Set<String> dCounter = ProxyHelper.getInstance().downloadCounter;
Set<String> dgCounter = ProxyHelper.getInstance().downloadGroupCounter;
Set<String> dgsCounter = ProxyHelper.getInstance().downloadGroupSubCounter;
if (dCounter != null && dCounter.contains(targetName)) {
DownloadSchedulers.getInstance().register(obj);
}
if ((dgCounter != null && dgCounter.contains(targetName)) || (dgsCounter != null
&& dgsCounter.contains(targetName))) {
DownloadGroupSchedulers.getInstance().register(obj);
Set<Integer> set = ProxyHelper.getInstance().checkProxyType(obj.getClass());
if (set != null && !set.isEmpty()) {
for (Integer type : set) {
if (type == ProxyHelper.PROXY_TYPE_DOWNLOAD) {
DownloadSchedulers.getInstance().register(obj);
} else if (type == ProxyHelper.PROXY_TYPE_DOWNLOAD_GROUP) {
DownloadGroupSchedulers.getInstance().register(obj);
}
}
} else {
ALog.w(TAG, "没有Aria的注解方法");
}
}
@ -204,15 +206,15 @@ public class DownloadReceiver extends AbsReceiver {
ALog.e(TAG, String.format("【%s】观察者为空", targetName));
return;
}
Set<String> dCounter = ProxyHelper.getInstance().downloadCounter;
Set<String> dgCounter = ProxyHelper.getInstance().downloadGroupCounter;
Set<String> dgsCounter = ProxyHelper.getInstance().downloadGroupSubCounter;
if (dCounter != null && dCounter.contains(targetName)) {
DownloadSchedulers.getInstance().unRegister(obj);
}
if (dgCounter != null && dgCounter.contains(targetName) || (dgsCounter != null
&& dgsCounter.contains(targetName))) {
DownloadGroupSchedulers.getInstance().unRegister(obj);
Set<Integer> set = ProxyHelper.getInstance().mProxyCache.get(obj.getClass().getName());
if (set != null) {
for (Integer integer : set) {
if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD) {
DownloadSchedulers.getInstance().unRegister(obj);
} else if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD_GROUP) {
DownloadGroupSchedulers.getInstance().unRegister(obj);
}
}
}
}
@ -286,7 +288,7 @@ public class DownloadReceiver extends AbsReceiver {
* @return {@code true}存在{@code false} 不存在
*/
public boolean taskExists(String downloadUrl) {
return DownloadEntity.findFirst(DownloadEntity.class, "url=?", downloadUrl) != null;
return DbEntity.checkDataExist(DownloadTaskEntity.class, "url=?", downloadUrl);
}
/**
@ -299,8 +301,7 @@ public class DownloadReceiver extends AbsReceiver {
return false;
}
String groupName = CommonUtil.getMd5Code(urls);
return DownloadGroupEntity.findFirst(DownloadGroupEntity.class, "groupName=?", groupName)
!= null;
return DbEntity.checkDataExist(DownloadGroupEntity.class, "groupName=?", groupName);
}
/**
@ -368,7 +369,7 @@ public class DownloadReceiver extends AbsReceiver {
public void stopAllTask() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(NormalCmdFactory.getInstance()
.createCmd(targetName, new DownloadTaskEntity(), NormalCmdFactory.TASK_STOP_ALL,
.createCmd(new DownloadTaskEntity(), NormalCmdFactory.TASK_STOP_ALL,
ICmd.TASK_TYPE_DOWNLOAD))
.exe();
}
@ -381,7 +382,7 @@ public class DownloadReceiver extends AbsReceiver {
public void resumeAllTask() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(NormalCmdFactory.getInstance()
.createCmd(targetName, new DownloadTaskEntity(), NormalCmdFactory.TASK_RESUME_ALL,
.createCmd(new DownloadTaskEntity(), NormalCmdFactory.TASK_RESUME_ALL,
ICmd.TASK_TYPE_DOWNLOAD))
.exe();
}
@ -395,7 +396,7 @@ public class DownloadReceiver extends AbsReceiver {
public void removeAllTask(boolean removeFile) {
final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP);
CancelAllCmd cancelCmd =
(CancelAllCmd) CommonUtil.createNormalCmd(targetName, new DownloadTaskEntity(),
(CancelAllCmd) CommonUtil.createNormalCmd(new DownloadTaskEntity(),
NormalCmdFactory.TASK_CANCEL_ALL, ICmd.TASK_TYPE_DOWNLOAD);
cancelCmd.removeFile = removeFile;
ariaManager.setCmd(cancelCmd).exe();

@ -18,8 +18,9 @@ package com.arialyy.aria.core.download;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.delegate.HttpHeaderDelegate;
import com.arialyy.aria.core.inf.IHttpHeaderTarget;
import com.arialyy.aria.core.common.http.HttpHeaderDelegate;
import com.arialyy.aria.core.common.http.PostDelegate;
import com.arialyy.aria.core.inf.IHttpHeaderDelegate;
import java.net.Proxy;
import java.util.Map;
@ -28,9 +29,8 @@ import java.util.Map;
* https://github.com/AriaLyy/Aria
*/
public class DownloadTarget extends BaseNormalTarget<DownloadTarget>
implements IHttpHeaderTarget<DownloadTarget> {
private HttpHeaderDelegate<DownloadTarget, DownloadEntity, DownloadTaskEntity> mDelegate;
implements IHttpHeaderDelegate<DownloadTarget> {
private HttpHeaderDelegate<DownloadTarget> mHeaderDelegate;
DownloadTarget(DownloadEntity entity, String targetName) {
this(entity.getUrl(), targetName);
@ -38,7 +38,14 @@ public class DownloadTarget extends BaseNormalTarget<DownloadTarget>
DownloadTarget(String url, String targetName) {
initTarget(url, targetName);
mDelegate = new HttpHeaderDelegate<>(this, mTaskEntity);
mHeaderDelegate = new HttpHeaderDelegate<>(this);
}
/**
* Post处理
*/
public PostDelegate asPost() {
return new PostDelegate<>(this);
}
/**
@ -53,17 +60,6 @@ public class DownloadTarget extends BaseNormalTarget<DownloadTarget>
return this;
}
/**
* 设置URL的代理
*
* @param proxy {@link Proxy}
*/
@CheckResult
public DownloadTarget setUrlProxy(Proxy proxy) {
mTaskEntity.setProxy(proxy);
return this;
}
/**
* 设置文件存储路径
* 该api后续版本会删除
@ -89,6 +85,21 @@ public class DownloadTarget extends BaseNormalTarget<DownloadTarget>
return this;
}
/**
* 设置文件存储路径如果需要修改新的文件名修改路径便可
* 原文件路径 /mnt/sdcard/test.zip
* 如果需要将test.zip改为game.zip只需要重新设置文件路径为/mnt/sdcard/game.zip
*
* @param filePath 路径必须为文件路径不能为文件夹路径
* @param forceDownload {@code true}强制下载不考虑未见路径是否被占用
*/
@CheckResult
public DownloadTarget setFilePath(@NonNull String filePath, boolean forceDownload) {
mTempFilePath = filePath;
this.forceDownload = forceDownload;
return this;
}
/**
* 从header中获取文件描述信息
*/
@ -100,18 +111,24 @@ public class DownloadTarget extends BaseNormalTarget<DownloadTarget>
return HTTP;
}
/**
* 设置URL的代理
*
* @param proxy {@link Proxy}
*/
@CheckResult
@Override public DownloadTarget setUrlProxy(Proxy proxy) {
return mHeaderDelegate.setUrlProxy(proxy);
}
@CheckResult
@Override public DownloadTarget addHeader(@NonNull String key, @NonNull String value) {
return mDelegate.addHeader(key, value);
return mHeaderDelegate.addHeader(key, value);
}
@CheckResult
@Override public DownloadTarget addHeaders(Map<String, String> headers) {
return mDelegate.addHeaders(headers);
return mHeaderDelegate.addHeaders(headers);
}
@CheckResult
@Override public DownloadTarget setRequestMode(RequestEnum requestEnum) {
return mDelegate.setRequestMode(requestEnum);
}
}

@ -19,9 +19,9 @@ package com.arialyy.aria.core.download;
import android.os.Handler;
import android.os.Looper;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.download.downloader.SimpleDownloadUtil;
import com.arialyy.aria.core.inf.AbsNormalTask;
import com.arialyy.aria.core.inf.IDownloadListener;
import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.util.ALog;
import java.io.File;
@ -30,19 +30,15 @@ import java.io.File;
* Created by lyy on 2016/8/11.
* 下载任务类
*/
public class DownloadTask extends AbsNormalTask<DownloadTaskEntity> {
public class DownloadTask extends AbsNormalTask<DownloadEntity, DownloadTaskEntity> {
public static final String TAG = "DownloadTask";
private DownloadListener mListener;
private DownloadEntity mEntity;
private IUtil mUtil;
private DownloadTask(DownloadTaskEntity taskEntity, Handler outHandler) {
mTaskEntity = taskEntity;
mOutHandler = outHandler;
mContext = AriaManager.APP;
mListener = new DownloadListener(this, mOutHandler);
mUtil = new SimpleDownloadUtil(taskEntity, mListener);
mListener = new BaseDListener(this, mOutHandler);
mUtil = new SimpleDownloadUtil(taskEntity, (IDownloadListener) mListener);
mEntity = taskEntity.getEntity();
}
@ -76,76 +72,10 @@ public class DownloadTask extends AbsNormalTask<DownloadTaskEntity> {
return mEntity.getUrl();
}
/**
* 是否真正下载
*
* @return {@code true} 真正下载
*/
@Override public boolean isRunning() {
return mUtil.isRunning();
}
public DownloadEntity getDownloadEntity() {
return mEntity;
}
/**
* 暂停任务并让任务处于等待状态
*/
@Override public void stopAndWait() {
stop(true);
}
/**
* 设置最大下载速度单位kb
*
* @param maxSpeed 为0表示不限速
*/
public void setMaxSpeed(double maxSpeed) {
mUtil.setMaxSpeed(maxSpeed);
}
/**
* 开始下载
*/
@Override public void start() {
mListener.isWait = false;
if (mUtil.isRunning()) {
ALog.d(TAG, "任务正在下载");
} else {
mUtil.start();
}
}
/**
* 停止下载
*/
@Override public void stop() {
super.stop();
stop(false);
}
private void stop(boolean isWait) {
mListener.isWait = isWait;
if (mUtil.isRunning()) {
mUtil.stop();
} else {
mListener.onStop(mEntity.getCurrentProgress());
}
}
/**
* 取消下载
*/
@Override public void cancel() {
super.cancel();
if (mUtil.isRunning()) {
mUtil.cancel();
} else {
mListener.onCancel();
}
}
@Override public String getTaskName() {
return mEntity.getFileName();
}
@ -153,10 +83,8 @@ public class DownloadTask extends AbsNormalTask<DownloadTaskEntity> {
public static class Builder {
DownloadTaskEntity taskEntity;
Handler outHandler;
String targetName;
public Builder(String targetName, DownloadTaskEntity taskEntity) {
this.targetName = targetName;
public Builder(DownloadTaskEntity taskEntity) {
this.taskEntity = taskEntity;
}
@ -166,19 +94,12 @@ public class DownloadTask extends AbsNormalTask<DownloadTaskEntity> {
* @param schedulers {@link ISchedulers}
*/
public Builder setOutHandler(ISchedulers schedulers) {
try {
outHandler = new Handler(schedulers);
} catch (Exception e) {
ALog.w(TAG, ALog.getExceptionString(e));
outHandler = new Handler(Looper.getMainLooper(), schedulers);
}
outHandler = new Handler(Looper.getMainLooper(), schedulers);
return this;
}
public DownloadTask build() {
DownloadTask task = new DownloadTask(taskEntity, outHandler);
task.setTargetName(targetName);
return task;
return new DownloadTask(taskEntity, outHandler);
}
}
}

@ -21,6 +21,7 @@ import com.arialyy.aria.orm.annotation.Foreign;
import com.arialyy.aria.orm.annotation.Ignore;
import com.arialyy.aria.orm.annotation.NoNull;
import com.arialyy.aria.orm.annotation.Primary;
import java.util.Map;
/**
* Created by lyy on 2017/1/23.
@ -60,8 +61,6 @@ public class DownloadTaskEntity extends AbsNormalTaskEntity<DownloadEntity> {
onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE)
private String key;
public DownloadTaskEntity() {
}
@ -112,6 +111,4 @@ public class DownloadTaskEntity extends AbsNormalTaskEntity<DownloadEntity> {
public void setGroupTask(boolean groupTask) {
isGroupTask = groupTask;
}
}

@ -17,11 +17,14 @@ package com.arialyy.aria.core.download;
import android.support.annotation.CheckResult;
import android.text.TextUtils;
import com.arialyy.aria.core.delegate.FtpDelegate;
import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.ftp.FTPSConfig;
import com.arialyy.aria.core.common.ftp.FtpDelegate;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IFtpTarget;
import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.util.ALog;
import java.net.Proxy;
/**
* Created by Aria.Lao on 2017/7/26.
@ -29,7 +32,7 @@ import com.arialyy.aria.util.ALog;
*/
public class FtpDirDownloadTarget extends BaseGroupTarget<FtpDirDownloadTarget>
implements IFtpTarget<FtpDirDownloadTarget> {
private FtpDelegate<FtpDirDownloadTarget, DownloadGroupEntity, DownloadGroupTaskEntity> mDelegate;
private FtpDelegate<FtpDirDownloadTarget> mDelegate;
FtpDirDownloadTarget(String url, String targetName) {
mTargetName = targetName;
@ -44,7 +47,7 @@ public class FtpDirDownloadTarget extends BaseGroupTarget<FtpDirDownloadTarget>
if (mEntity != null) {
mDirPathTemp = mEntity.getDirPath();
}
mDelegate = new FtpDelegate<>(this, mTaskEntity);
mDelegate = new FtpDelegate<>(this);
}
@Override protected int getTargetType() {
@ -58,14 +61,34 @@ public class FtpDirDownloadTarget extends BaseGroupTarget<FtpDirDownloadTarget>
mTaskEntity.save();
if (mTaskEntity.getSubTaskEntities() != null) {
//初始化子项的登录信息
FtpUrlEntity tUrlEntity = mTaskEntity.getUrlEntity();
for (DownloadTaskEntity entity : mTaskEntity.getSubTaskEntities()) {
entity.getUrlEntity().needLogin = mTaskEntity.getUrlEntity().needLogin;
entity.getUrlEntity().account = mTaskEntity.getUrlEntity().account;
entity.getUrlEntity().user = mTaskEntity.getUrlEntity().user;
entity.getUrlEntity().password = mTaskEntity.getUrlEntity().password;
FtpUrlEntity urlEntity = entity.getUrlEntity();
urlEntity.needLogin = tUrlEntity.needLogin;
urlEntity.account = tUrlEntity.account;
urlEntity.user = tUrlEntity.user;
urlEntity.password = tUrlEntity.password;
// 处理ftps详细
if (tUrlEntity.isFtps) {
urlEntity.isFtps = true;
urlEntity.protocol = tUrlEntity.protocol;
urlEntity.storePath = tUrlEntity.storePath;
urlEntity.storePass = tUrlEntity.storePass;
urlEntity.keyAlias = tUrlEntity.keyAlias;
}
}
}
}
if (mTaskEntity.getUrlEntity().isFtps) {
if (TextUtils.isEmpty(mTaskEntity.getUrlEntity().storePath)) {
ALog.e(TAG, "证书路径为空");
return false;
}
if (TextUtils.isEmpty(mTaskEntity.getUrlEntity().keyAlias)) {
ALog.e(TAG, "证书别名为空");
return false;
}
}
return b;
}
@ -90,16 +113,34 @@ public class FtpDirDownloadTarget extends BaseGroupTarget<FtpDirDownloadTarget>
}
return true;
}
/**
* 是否是FTPS协议
* 如果是FTPS协议需要使用{@link FTPSConfig#setStorePath(String)} {@link FTPSConfig#setAlias(String)}
* 设置证书信息
*/
@CheckResult
public FTPSConfig<FtpDirDownloadTarget> asFtps() {
mTaskEntity.getUrlEntity().isFtps = true;
return new FTPSConfig<>(this);
}
@CheckResult
@Override public FtpDirDownloadTarget charSet(String charSet) {
return mDelegate.charSet(charSet);
}
@CheckResult
@Override public FtpDirDownloadTarget login(String userName, String password) {
return mDelegate.login(userName, password);
}
@CheckResult
@Override public FtpDirDownloadTarget login(String userName, String password, String account) {
return mDelegate.login(userName, password, account);
}
@Override public FtpDirDownloadTarget setProxy(Proxy proxy) {
return mDelegate.setProxy(proxy);
}
}

@ -17,10 +17,14 @@ package com.arialyy.aria.core.download;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull;
import com.arialyy.aria.core.delegate.FtpDelegate;
import android.text.TextUtils;
import com.arialyy.aria.core.common.ftp.FTPSConfig;
import com.arialyy.aria.core.common.ftp.FtpDelegate;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IFtpTarget;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.net.Proxy;
/**
* Created by lyy on 2016/12/5.
@ -28,7 +32,7 @@ import com.arialyy.aria.util.CommonUtil;
*/
public class FtpDownloadTarget extends BaseNormalTarget<FtpDownloadTarget>
implements IFtpTarget<FtpDownloadTarget> {
private FtpDelegate<FtpDownloadTarget, DownloadEntity, DownloadTaskEntity> mDelegate;
private FtpDelegate<FtpDownloadTarget> mDelegate;
public FtpDownloadTarget(DownloadEntity entity, String targetName) {
this(entity.getUrl(), targetName);
@ -45,7 +49,32 @@ public class FtpDownloadTarget extends BaseNormalTarget<FtpDownloadTarget>
mTaskEntity.setUrlEntity(CommonUtil.getFtpUrlInfo(url));
mTaskEntity.setRequestType(AbsTaskEntity.D_FTP);
mDelegate = new FtpDelegate<>(this, mTaskEntity);
mDelegate = new FtpDelegate<>(this);
}
/**
* 是否是FTPS协议
* 如果是FTPS协议需要使用{@link FTPSConfig#setStorePath(String)} {@link FTPSConfig#setAlias(String)}
* 设置证书信息
*/
@CheckResult
public FTPSConfig<FtpDownloadTarget> asFtps() {
mTaskEntity.getUrlEntity().isFtps = true;
return new FTPSConfig<>(this);
}
@Override protected boolean checkEntity() {
if (mTaskEntity.getUrlEntity().isFtps){
if (TextUtils.isEmpty(mTaskEntity.getUrlEntity().storePath)){
ALog.e(TAG, "证书路径为空");
return false;
}
if (TextUtils.isEmpty(mTaskEntity.getUrlEntity().keyAlias)){
ALog.e(TAG, "证书别名为空");
return false;
}
}
return super.checkEntity();
}
/**
@ -90,4 +119,9 @@ public class FtpDownloadTarget extends BaseNormalTarget<FtpDownloadTarget>
@Override public FtpDownloadTarget login(String userName, String password, String account) {
return mDelegate.login(userName, password, account);
}
@CheckResult
@Override public FtpDownloadTarget setProxy(Proxy proxy) {
return mDelegate.setProxy(proxy);
}
}

@ -22,23 +22,23 @@ import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.IDownloadListener;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.exception.TaskException;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.NetUtils;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Created by AriaL on 2017/6/30.
* 任务组核心逻辑
*/
public abstract class AbsGroupUtil implements IUtil {
public abstract class AbsGroupUtil implements IUtil, Runnable {
private static final Object LOCK = new Object();
private final String TAG = "AbsGroupUtil";
/**
@ -55,30 +55,29 @@ public abstract class AbsGroupUtil implements IUtil {
*/
long mTotalLen = 0;
long mCurrentLocation = 0;
private ExecutorService mExePool;
protected IDownloadGroupListener mListener;
DownloadGroupTaskEntity mGTEntity;
private boolean isRunning = false;
private Timer mTimer;
private ScheduledThreadPoolExecutor mTimer;
/**
* 保存所有没有下载完成的任务key为下载地址
*/
Map<String, DownloadTaskEntity> mExeMap = new HashMap<>();
Map<String, DownloadTaskEntity> mExeMap = new ConcurrentHashMap<>();
/**
* 下载失败的映射表key为下载地址
*/
Map<String, DownloadTaskEntity> mFailMap = new HashMap<>();
Map<String, DownloadTaskEntity> mFailMap = new ConcurrentHashMap<>();
/**
* 该任务组对应的所有任务
*/
private Map<String, DownloadTaskEntity> mTasksMap = new HashMap<>();
private Map<String, DownloadTaskEntity> mTasksMap = new ConcurrentHashMap<>();
/**
* 下载器映射表key为下载地址
*/
private Map<String, Downloader> mDownloaderMap = new HashMap<>();
private Map<String, Downloader> mDownloaderMap = new ConcurrentHashMap<>();
/**
* 是否需要读取文件长度{@code true}需要
@ -96,7 +95,6 @@ public abstract class AbsGroupUtil implements IUtil {
AbsGroupUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity groupEntity) {
mListener = listener;
mGTEntity = groupEntity;
mExePool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
mUpdateInterval =
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getUpdateInterval();
}
@ -227,10 +225,6 @@ public abstract class AbsGroupUtil implements IUtil {
isCancel = true;
closeTimer();
onCancel();
if (!mExePool.isShutdown()) {
mExePool.shutdown();
}
Set<String> keys = mDownloaderMap.keySet();
for (String key : keys) {
Downloader dt = mDownloaderMap.get(key);
@ -250,9 +244,6 @@ public abstract class AbsGroupUtil implements IUtil {
isStop = true;
closeTimer();
onStop();
if (!mExePool.isShutdown()) {
mExePool.shutdown();
}
Set<String> keys = mDownloaderMap.keySet();
for (String key : keys) {
@ -275,6 +266,7 @@ public abstract class AbsGroupUtil implements IUtil {
*/
protected void onPre() {
mListener.onPre();
isRunning = true;
mGroupSize = mGTEntity.getSubTaskEntities().size();
mTotalLen = mGTEntity.getEntity().getFileSize();
isNeedLoadFileSize = mTotalLen <= 10;
@ -295,6 +287,10 @@ public abstract class AbsGroupUtil implements IUtil {
}
@Override public void start() {
new Thread(this).start();
}
@Override public void run() {
if (isStop || isCancel) {
closeTimer();
return;
@ -311,8 +307,14 @@ public abstract class AbsGroupUtil implements IUtil {
start();
}
@Override public void setMaxSpeed(double maxSpeed) {
@Override public void setMaxSpeed(int speed) {
Set<String> keys = mDownloaderMap.keySet();
for (String key : keys) {
Downloader dt = mDownloaderMap.get(key);
if (dt != null) {
dt.setMaxSpeed(speed);
}
}
}
private void clearState() {
@ -320,12 +322,9 @@ public abstract class AbsGroupUtil implements IUtil {
mFailMap.clear();
}
void closeTimer() {
isRunning = false;
if (mTimer != null) {
mTimer.purge();
mTimer.cancel();
mTimer = null;
synchronized void closeTimer() {
if (mTimer != null && !mTimer.isShutdown()) {
mTimer.shutdown();
}
}
@ -343,10 +342,10 @@ public abstract class AbsGroupUtil implements IUtil {
startTimer();
}
private void startTimer() {
private synchronized void startTimer() {
isRunning = true;
mTimer = new Timer(true);
mTimer.schedule(new TimerTask() {
mTimer = new ScheduledThreadPoolExecutor(1);
mTimer.scheduleWithFixedDelay(new Runnable() {
@Override public void run() {
if (!isRunning) {
closeTimer();
@ -363,7 +362,7 @@ public abstract class AbsGroupUtil implements IUtil {
mListener.onProgress(t);
}
}
}, 0, mUpdateInterval);
}, 0, mUpdateInterval, TimeUnit.MILLISECONDS);
}
/**
@ -382,9 +381,8 @@ public abstract class AbsGroupUtil implements IUtil {
ChildDownloadListener listener = new ChildDownloadListener(taskEntity);
Downloader dt = new Downloader(listener, taskEntity);
mDownloaderMap.put(taskEntity.getEntity().getUrl(), dt);
if (mExePool.isShutdown()) return dt;
if (start) {
mExePool.execute(dt);
dt.start();
}
return dt;
}
@ -397,9 +395,9 @@ public abstract class AbsGroupUtil implements IUtil {
private DownloadEntity subEntity;
private int RUN_SAVE_INTERVAL = 5 * 1000; //5s保存一次下载中的进度
private long lastSaveTime;
private long lastLen = 0;
private Timer timer;
private boolean isNotNetRetry = false;
private long lastLen;
private ScheduledThreadPoolExecutor timer;
private boolean isNotNetRetry;
ChildDownloadListener(DownloadTaskEntity entity) {
subTaskEntity = entity;
@ -486,7 +484,7 @@ public abstract class AbsGroupUtil implements IUtil {
}
}
@Override public void onFail(boolean needRetry) {
@Override public void onFail(boolean needRetry, BaseException e) {
subEntity.setFailNum(subEntity.getFailNum() + 1);
saveData(IEntity.STATE_FAIL, lastLen);
handleSpeed(0);
@ -497,22 +495,26 @@ public abstract class AbsGroupUtil implements IUtil {
* 重试下载只有全部都下载失败才会执行任务组的整体重试否则只会执行单个子任务的重试
*/
private void reTry(boolean needRetry) {
Downloader dt = mDownloaderMap.get(subEntity.getUrl());
synchronized (AbsGroupUtil.LOCK) {
Downloader dt = mDownloaderMap.get(subEntity.getUrl());
if (!isCancel && !isStop && dt != null
&& !dt.isBreak()
&& needRetry
&& subEntity.getFailNum() < 3
&& (NetUtils.isConnected(AriaManager.APP) || isNotNetRetry)) {
ALog.d(TAG, "downloader retry");
reStartTask(dt);
} else {
mFailMap.put(subTaskEntity.getUrl(), subTaskEntity);
mListener.onSubFail(subEntity);
mListener.onSubFail(subEntity, new TaskException(TAG,
String.format("任务组子任务【%s】下载失败,下载地址【%s】", subEntity.getFileName(),
subEntity.getUrl())));
if (mFailMap.size() == mExeMap.size() || mFailMap.size() + mCompleteNum == mGroupSize) {
closeTimer();
}
if (mFailMap.size() == mGroupSize) {
mListener.onFail(true);
mListener.onFail(true, new TaskException(TAG,
String.format("任务组【%s】下载失败", mGTEntity.getEntity().getGroupName())));
} else if (mFailMap.size() + mCompleteNum >= mExeMap.size()) {
mListener.onStop(mCurrentLocation);
}
@ -521,18 +523,16 @@ public abstract class AbsGroupUtil implements IUtil {
}
private void reStartTask(final Downloader dt) {
if (timer != null) {
timer.purge();
timer.cancel();
if (timer == null || timer.isShutdown()) {
timer = new ScheduledThreadPoolExecutor(1);
}
timer = new Timer();
timer.schedule(new TimerTask() {
timer.schedule(new Runnable() {
@Override public void run() {
if (dt != null) {
dt.retryThreadTask();
dt.retryTask();
}
}
}, 5000);
}, 5, TimeUnit.SECONDS);
}
private void handleSpeed(long speed) {

@ -16,18 +16,21 @@
package com.arialyy.aria.core.download.downloader;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.ProtocolType;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.util.SSLContextUtil;
import java.io.IOException;
import java.io.InputStream;
import java.net.CookieManager;
import java.net.CookieStore;
import java.net.HttpCookie;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream;
import java.util.zip.InflaterInputStream;
@ -75,11 +78,13 @@ class ConnectionHelp {
urlConn = url.openConnection();
}
if (urlConn instanceof HttpsURLConnection) {
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
conn = (HttpsURLConnection) urlConn;
SSLContext sslContext =
SSLContextUtil.getSSLContext(SSLContextUtil.CA_ALIAS, SSLContextUtil.CA_PATH);
SSLContextUtil.getSSLContextFromAssets(manager.getDownloadConfig().getCaName(),
manager.getDownloadConfig().getCaPath(), ProtocolType.Default);
if (sslContext == null) {
sslContext = SSLContextUtil.getDefaultSLLContext();
sslContext = SSLContextUtil.getDefaultSLLContext(ProtocolType.Default);
}
SSLSocketFactory ssf = sslContext.getSocketFactory();
((HttpsURLConnection) conn).setSSLSocketFactory(ssf);
@ -98,6 +103,8 @@ class ConnectionHelp {
static HttpURLConnection setConnectParam(DownloadTaskEntity entity, HttpURLConnection conn) {
if (entity.getRequestEnum() == RequestEnum.POST) {
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
}
Set<String> keys = null;
if (entity.getHeaders() != null && entity.getHeaders().size() > 0) {
@ -106,7 +113,9 @@ class ConnectionHelp {
conn.setRequestProperty(key, entity.getHeaders().get(key));
}
}
if (conn.getRequestProperty("Accept-Language") == null) {
conn.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,ja;q=0.7");
}
if (conn.getRequestProperty("Accept-Encoding") == null) {
conn.setRequestProperty("Accept-Encoding", "identity");
}
@ -124,30 +133,40 @@ class ConnectionHelp {
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36");
}
if (conn.getRequestProperty("Accept") == null) {
StringBuilder accept = new StringBuilder();
//StringBuilder accept = new StringBuilder();
//accept
//.append("image/gif, ")
//.append("image/jpeg, ")
//.append("image/pjpeg, ")
//.append("image/webp, ")
//.append("image/apng, ")
//.append("application/xml, ")
//.append("application/xaml+xml, ")
//.append("application/xhtml+xml, ")
//.append("application/x-shockwave-flash, ")
//.append("application/x-ms-xbap, ")
//.append("application/x-ms-application, ")
//.append("application/msword, ")
//.append("application/vnd.ms-excel, ")
//.append("application/vnd.ms-xpsdocument, ")
//.append("application/vnd.ms-powerpoint, ")
//.append("text/plain, ")
//.append("text/html, ")
//.append("*/*");
//.append("image/gif, ")
//.append("image/jpeg, ")
//.append("image/pjpeg, ")
//.append("image/webp, ")
//.append("image/apng, ")
//.append("application/xml, ")
//.append("application/xaml+xml, ")
//.append("application/xhtml+xml, ")
//.append("application/x-shockwave-flash, ")
//.append("application/x-ms-xbap, ")
//.append("application/x-ms-application, ")
//.append("application/msword, ")
//.append("application/vnd.ms-excel, ")
//.append("application/vnd.ms-xpsdocument, ")
//.append("application/vnd.ms-powerpoint, ")
//.append("text/plain, ")
//.append("text/html, ")
//.append("*/*");
conn.setRequestProperty("Accept", "*/*");
}
//302获取重定向地址
conn.setInstanceFollowRedirects(false);
CookieManager manager = entity.getCookieManager();
if (manager != null) {
CookieStore store = manager.getCookieStore();
if (store != null && store.getCookies().size() > 0) {
conn.setRequestProperty("Cookie",
TextUtils.join(";", store.getCookies()));
}
}
return conn;
}
}

@ -22,6 +22,8 @@ import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.exception.TaskException;
import com.arialyy.aria.util.ALog;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@ -85,8 +87,8 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
}
if (mExeMap.size() == 0) {
ALog.e(TAG, "任务组无可执行任务");
mListener.onFail(false);
mListener.onFail(false, new TaskException(TAG,
String.format("任务组【%s】无可执行任务", mGTEntity.getEntity().getGroupName())));
return;
}
Set<String> keys = mExeMap.keySet();
@ -133,7 +135,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
checkStartFlow();
}
@Override public void onFail(String url, String errorMsg, boolean needRetry) {
@Override public void onFail(String url, BaseException e, boolean needRetry) {
if (isStop) return;
ALog.e(TAG, String.format("任务【%s】初始化失败", url));
DownloadTaskEntity te = mExeMap.get(url);
@ -163,9 +165,14 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
*/
private void checkStartFlow() {
synchronized (DownloadGroupUtil.class) {
if (isStop) {
closeTimer();
return;
}
if (mInitFailNum == mExeNum) {
closeTimer();
mListener.onFail(true);
mListener.onFail(true, new TaskException(TAG,
String.format("任务组【%s】初始化失败", mGTEntity.getEntity().getGroupName())));
}
if (!isStart && mInitCompleteNum + mInitFailNum == mExeNum || !isNeedLoadFileSize) {
startRunningFlow();

@ -23,10 +23,9 @@ import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IDownloadListener;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.exception.TaskException;
import com.arialyy.aria.util.BufferedRandomAccessFile;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.ErrorHelp;
import java.io.File;
import java.io.IOException;
@ -58,7 +57,10 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
@Override protected boolean handleNewTask() {
if (!mRecord.isBlock) {
CommonUtil.createFile(mTempFile.getPath());
if (mTempFile.exists()) {
mTempFile.delete();
}
//CommonUtil.createFile(mTempFile.getPath());
}
BufferedRandomAccessFile file = null;
try {
@ -69,8 +71,9 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
}
return true;
} catch (IOException e) {
failDownload(String.format("下载失败【downloadUrl:%s】;【filePath:%s】\n %S", mEntity.getUrl(),
mEntity.getDownloadPath(), ALog.getExceptionString(e)));
failDownload(new TaskException(TAG,
String.format("下载失败,filePath: %s, url: %s", mEntity.getDownloadPath(),
mEntity.getUrl()), e));
} finally {
if (file != null) {
try {
@ -83,6 +86,15 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
return false;
}
@Override protected void onPostPre() {
super.onPostPre();
((IDownloadListener) mListener).onPostPre(mEntity.getFileSize());
File file = new File(mEntity.getDownloadPath());
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
}
@Override protected AbsThreadTask selectThreadTask(SubThreadConfig<DownloadTaskEntity> config) {
switch (mTaskEntity.getRequestType()) {
case AbsTaskEntity.D_FTP:
@ -94,11 +106,9 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
return null;
}
private void failDownload(String errorMsg) {
private void failDownload(BaseException e) {
closeTimer();
ALog.e(TAG, errorMsg);
mConstance.isRunning = false;
mListener.onFail(false);
ErrorHelp.saveError(TAG, "", errorMsg);
mListener.onFail(false, e);
}
}

@ -19,6 +19,8 @@ import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.exception.TaskException;
import com.arialyy.aria.util.ErrorHelp;
import java.util.Set;
@ -51,14 +53,13 @@ public class FtpDirDownloadUtil extends AbsGroupUtil {
}
}
@Override public void onFail(String url, String errorMsg, boolean needRetry) {
@Override public void onFail(String url, BaseException e, boolean needRetry) {
DownloadTaskEntity te = mExeMap.get(url);
if (te != null) {
mFailMap.put(url, te);
mExeMap.remove(url);
}
mListener.onFail(needRetry);
ErrorHelp.saveError(TAG, "", errorMsg);
mListener.onFail(needRetry, e);
}
}).start();
}

@ -15,10 +15,11 @@
*/
package com.arialyy.aria.core.download.downloader;
import aria.apache.commons.net.ftp.FTPFile;
import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.AbsFtpInfoThread;
import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.common.ftp.AbsFtpInfoThread;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
@ -27,7 +28,6 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.util.CommonUtil;
import java.nio.charset.Charset;
import java.util.ArrayList;
import org.apache.commons.net.ftp.FTPFile;
/**
* Created by Aria.Lao on 2017/7/25.
@ -61,7 +61,7 @@ class FtpDirInfoThread extends AbsFtpInfoThread<DownloadGroupEntity, DownloadGro
final FtpUrlEntity urlEntity = mTaskEntity.getUrlEntity().clone();
DownloadEntity entity = new DownloadEntity();
entity.setUrl(
urlEntity.protocol + "://" + urlEntity.hostName + ":" + urlEntity.port + "/" + remotePath);
urlEntity.scheme + "://" + urlEntity.hostName + ":" + urlEntity.port + "/" + remotePath);
entity.setDownloadPath(mEntity.getDirPath() + "/" + remotePath);
int lastIndex = remotePath.lastIndexOf("/");
String fileName = lastIndex < 0 ? CommonUtil.keyToHashKey(remotePath)

@ -15,22 +15,36 @@
*/
package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.common.AbsFtpInfoThread;
import aria.apache.commons.net.ftp.FTPFile;
import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.common.ftp.AbsFtpInfoThread;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.exception.AriaIOException;
import com.arialyy.aria.util.CommonUtil;
/**
* Created by Aria.Lao on 2017/7/25.
* 获取ftp文件信息
*/
class FtpFileInfoThread extends AbsFtpInfoThread<DownloadEntity, DownloadTaskEntity> {
private final String TAG = "FtpFileInfoThread";
FtpFileInfoThread(DownloadTaskEntity taskEntity, OnFileInfoCallback callback) {
super(taskEntity, callback);
}
@Override protected void handleFile(String remotePath, FTPFile ftpFile) {
super.handleFile(remotePath, ftpFile);
if (!CommonUtil.checkSDMemorySpace(mEntity.getDownloadPath(), ftpFile.getSize())) {
mCallback.onFail(mEntity.getUrl(),
new AriaIOException(TAG,
String.format("获取ftp文件信息失败,内存空间不足, filePath: %s", mEntity.getDownloadPath())),
false);
}
}
@Override protected String setRemotePath() {
return mTaskEntity.getUrlEntity().remotePath;
}

@ -15,13 +15,16 @@
*/
package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.AbsFtpThreadTask;
import aria.apache.commons.net.ftp.FTPClient;
import aria.apache.commons.net.ftp.FTPReply;
import com.arialyy.aria.core.common.StateConstance;
import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.common.ftp.AbsFtpThreadTask;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.IDownloadListener;
import com.arialyy.aria.exception.AriaIOException;
import com.arialyy.aria.exception.TaskException;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.BufferedRandomAccessFile;
import java.io.FileOutputStream;
@ -31,8 +34,6 @@ import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
/**
* Created by Aria.Lao on 2017/7/24.
@ -46,20 +47,19 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
FtpThreadTask(StateConstance constance, IDownloadListener listener,
SubThreadConfig<DownloadTaskEntity> downloadInfo) {
super(constance, listener, downloadInfo);
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
mConnectTimeOut = manager.getDownloadConfig().getConnectTimeOut();
mReadTimeOut = manager.getDownloadConfig().getIOTimeOut();
mBufSize = manager.getDownloadConfig().getBuffSize();
isNotNetRetry = manager.getDownloadConfig().isNotNetRetry();
mConnectTimeOut = mAridManager.getDownloadConfig().getConnectTimeOut();
mReadTimeOut = mAridManager.getDownloadConfig().getIOTimeOut();
mBufSize = mAridManager.getDownloadConfig().getBuffSize();
isNotNetRetry = mAridManager.getDownloadConfig().isNotNetRetry();
isOpenDynamicFile = STATE.TASK_RECORD.isOpenDynamicFile;
isBlock = STATE.TASK_RECORD.isBlock;
setMaxSpeed(manager.getDownloadConfig().getMaxSpeed());
}
@Override public void run() {
@Override public FtpThreadTask call() throws Exception {
super.call();
if (mConfig.THREAD_RECORD.isComplete) {
handleComplete();
return;
return this;
}
mChildCurrentLocation = mConfig.START_LOCATION;
FTPClient client = null;
@ -70,7 +70,10 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
String.format("任务【%s】线程__%s__开始下载【开始位置 : %s,结束位置:%s】", mConfig.TEMP_FILE.getName(),
mConfig.THREAD_ID, mConfig.START_LOCATION, mConfig.END_LOCATION));
client = createClient();
if (client == null) return;
if (client == null) {
fail(mChildCurrentLocation, new TaskException(TAG, "ftp client 创建失败"));
return this;
}
if (mConfig.START_LOCATION > 0) {
client.setRestartOffset(mConfig.START_LOCATION);
}
@ -78,10 +81,10 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
int reply = client.getReplyCode();
if (!FTPReply.isPositivePreliminary(reply) && reply != FTPReply.COMMAND_OK) {
fail(mChildCurrentLocation,
String.format("获取文件信息错误,错误码为:%s,msg:%s", reply, client.getReplyString()),
null);
new AriaIOException(TAG,
String.format("获取文件信息错误,错误码为:%s,msg:%s", reply, client.getReplyString())));
client.disconnect();
return;
return this;
}
String remotePath =
new String(mTaskEntity.getUrlEntity().remotePath.getBytes(charSet), SERVER_CHARSET);
@ -90,10 +93,10 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
reply = client.getReplyCode();
if (!FTPReply.isPositivePreliminary(reply)) {
fail(mChildCurrentLocation,
String.format("获取流失败,错误码为:%s,msg:%s", reply, client.getReplyString()),
null);
new AriaIOException(TAG,
String.format("获取流失败,错误码为:%s,msg:%s", reply, client.getReplyString())));
client.disconnect();
return;
return this;
}
if (isOpenDynamicFile) {
@ -103,9 +106,11 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
handleComplete();
}
} catch (IOException e) {
fail(mChildCurrentLocation, String.format("下载失败【%s】", mConfig.URL), e);
fail(mChildCurrentLocation,
new AriaIOException(TAG, String.format("下载失败【%s】", mConfig.URL), e));
} catch (Exception e) {
fail(mChildCurrentLocation, "获取流失败", e);
fail(mChildCurrentLocation,
new AriaIOException(TAG, String.format("下载失败【%s】", mConfig.URL), e));
} finally {
try {
if (is != null) {
@ -118,6 +123,7 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
e.printStackTrace();
}
}
return this;
}
/**
@ -135,9 +141,10 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
if (isBlock) {
boolean success = mergeFile();
if (!success) {
ALog.e(TAG, String.format("任务【%s】分块文件合并失败", mConfig.TEMP_FILE.getName()));
//ALog.e(TAG, String.format("任务【%s】分块文件合并失败", mConfig.TEMP_FILE.getName()));
STATE.isRunning = false;
mListener.onFail(false);
mListener.onFail(false,
new TaskException(TAG, String.format("任务【%s】分块文件合并失败", mConfig.TEMP_FILE.getName())));
return;
}
}
@ -147,7 +154,8 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
}
if (STATE.isFail()) {
STATE.isRunning = false;
mListener.onFail(false);
mListener.onFail(false,
new TaskException(TAG, String.format("任务【%s】下载失败", mConfig.TEMP_FILE.getName())));
}
}
@ -164,12 +172,12 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
foc = fos.getChannel();
fic = Channels.newChannel(is);
ByteBuffer bf = ByteBuffer.allocate(mBufSize);
while ((len = fic.read(bf)) != -1) {
while (isLive() && (len = fic.read(bf)) != -1) {
if (isBreak()) {
break;
}
if (mSleepTime > 0) {
Thread.sleep(mSleepTime);
if (mSpeedBandUtil != null) {
mSpeedBandUtil.limitNextBytes(len);
}
if (mChildCurrentLocation + len >= mConfig.END_LOCATION) {
len = (int) (mConfig.END_LOCATION - mChildCurrentLocation);
@ -186,10 +194,9 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
}
}
handleComplete();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
fail(mChildCurrentLocation, String.format("下载失败【%s】", mConfig.URL), e);
fail(mChildCurrentLocation,
new AriaIOException(TAG, String.format("下载失败【%s】", mConfig.URL), e));
} finally {
try {
if (fos != null) {
@ -217,11 +224,13 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
file.seek(mConfig.START_LOCATION);
byte[] buffer = new byte[mBufSize];
int len;
while ((len = is.read(buffer)) != -1) {
while (isLive() && (len = is.read(buffer)) != -1) {
if (isBreak()) {
break;
}
if (mSleepTime > 0) Thread.sleep(mSleepTime);
if (mSpeedBandUtil != null) {
mSpeedBandUtil.limitNextBytes(len);
}
if (mChildCurrentLocation + len >= mConfig.END_LOCATION) {
len = (int) (mConfig.END_LOCATION - mChildCurrentLocation);
file.write(buffer, 0, len);
@ -233,9 +242,8 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
}
}
} catch (IOException e) {
fail(mChildCurrentLocation, String.format("下载失败【%s】", mConfig.URL), e);
} catch (InterruptedException e) {
e.printStackTrace();
fail(mChildCurrentLocation,
new AriaIOException(TAG, String.format("下载失败【%s】", mConfig.URL), e));
} finally {
try {
if (file != null) {
@ -246,4 +254,8 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
}
}
}
@Override public int getMaxSpeed() {
return mAridManager.getDownloadConfig().getMaxSpeed();
}
}

@ -15,12 +15,18 @@
*/
package com.arialyy.aria.core.download.downloader;
import android.os.Process;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.exception.AriaIOException;
import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.exception.TaskException;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
@ -28,9 +34,18 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.HttpCookie;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 下载文件信息获取
@ -51,6 +66,7 @@ class HttpFileInfoThread implements Runnable {
}
@Override public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
HttpURLConnection conn = null;
try {
URL url = new URL(CommonUtil.convertUrl(mEntity.getUrl()));
@ -62,12 +78,9 @@ class HttpFileInfoThread implements Runnable {
conn.connect();
handleConnect(conn);
} catch (IOException e) {
failDownload("下载失败【downloadUrl:"
+ mEntity.getUrl()
+ "】\n【filePath:"
+ mEntity.getDownloadPath()
+ "】\n"
+ ALog.getExceptionString(e), true);
failDownload(new AriaIOException(TAG,
String.format("下载失败,filePath: %s, url: %s", mEntity.getDownloadPath(), mEntity.getUrl())),
true);
} finally {
if (conn != null) {
conn.disconnect();
@ -76,6 +89,23 @@ class HttpFileInfoThread implements Runnable {
}
private void handleConnect(HttpURLConnection conn) throws IOException {
if (mTaskEntity.getRequestEnum() == RequestEnum.POST) {
Map<String, String> params = mTaskEntity.getParams();
if (params != null) {
OutputStreamWriter dos = new OutputStreamWriter(conn.getOutputStream());
Set<String> keys = params.keySet();
StringBuilder sb = new StringBuilder();
for (String key : keys) {
sb.append(key).append("=").append(URLEncoder.encode(params.get(key))).append("&");
}
String url = sb.toString();
url = url.substring(0, url.length() - 1);
dos.write(url);
dos.flush();
dos.close();
}
}
long len = conn.getContentLength();
if (len < 0) {
String temp = conn.getHeaderField("Content-Length");
@ -92,6 +122,14 @@ class HttpFileInfoThread implements Runnable {
}
}
}
if (!CommonUtil.checkSDMemorySpace(mEntity.getDownloadPath(), len)) {
failDownload(new TaskException(TAG,
String.format("下载失败,内存空间不足;filePath: %s, url: %s", mEntity.getDownloadPath(),
mEntity.getUrl())), false);
return;
}
int code = conn.getResponseCode();
boolean end = false;
if (TextUtils.isEmpty(mEntity.getMd5Code())) {
@ -104,7 +142,7 @@ class HttpFileInfoThread implements Runnable {
if (!TextUtils.isEmpty(str) && str.equals("chunked")) {
isChunked = true;
}
//Map<String, List<String>> headers = conn.getHeaderFields();
Map<String, List<String>> headers = conn.getHeaderFields();
String disposition = conn.getHeaderField("Content-Disposition");
if (mTaskEntity.isUseServerFileName() && !TextUtils.isEmpty(disposition)) {
mEntity.setDisposition(CommonUtil.encryptBASE64(disposition));
@ -114,19 +152,33 @@ class HttpFileInfoThread implements Runnable {
if (info.startsWith("filename") && info.contains("=")) {
String[] temp = info.split("=");
if (temp.length > 1) {
String newName = URLDecoder.decode(temp[1], "utf-8");
String newName = URLDecoder.decode(temp[1], "utf-8").replaceAll("\"", "");
mEntity.setServerFileName(newName);
fileRename(newName);
renameFile(newName);
break;
}
}
}
}
}
CookieManager msCookieManager = new CookieManager();
List<String> cookiesHeader = headers.get("Set-Cookie");
if (cookiesHeader != null) {
for (String cookie : cookiesHeader) {
msCookieManager.getCookieStore().add(null, HttpCookie.parse(cookie).get(0));
}
mTaskEntity.setCookieManager(msCookieManager);
}
mTaskEntity.setCode(code);
if (code == HttpURLConnection.HTTP_PARTIAL) {
if (!checkLen(len) && !isChunked) {
if (len < 0) {
failDownload(
new AriaIOException(TAG, String.format("任务下载失败,文件长度小于0, url: %s", mEntity.getUrl())),
false);
}
return;
}
mEntity.setFileSize(len);
@ -149,6 +201,12 @@ class HttpFileInfoThread implements Runnable {
handleUrlReTurn(conn, CommonUtil.getWindowReplaceUrl(sb.toString()));
return;
} else if (!checkLen(len) && !isChunked) {
if (len < 0) {
failDownload(
new AriaIOException(TAG, String.format("任务下载失败,文件长度小于0, url: %s", mEntity.getUrl())),
false);
}
ALog.d(TAG, "len < 0");
return;
}
mEntity.setFileSize(len);
@ -156,14 +214,18 @@ class HttpFileInfoThread implements Runnable {
mTaskEntity.setSupportBP(false);
end = true;
} else if (code == HttpURLConnection.HTTP_NOT_FOUND) {
failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:404", true);
failDownload(new AriaIOException(TAG,
String.format("任务下载失败,errorCode:404, url: %s", mEntity.getUrl())), true);
} else if (code == HttpURLConnection.HTTP_MOVED_TEMP
|| code == HttpURLConnection.HTTP_MOVED_PERM
|| code == HttpURLConnection.HTTP_SEE_OTHER
|| code == HttpURLConnection.HTTP_CREATED // 201 跳转
|| code == 307) {
handleUrlReTurn(conn, conn.getHeaderField("Location"));
} else {
failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:" + code, true);
failDownload(new AriaIOException(TAG,
String.format("任务下载失败,errorCode:%s, errorMsg: %s, url: %s", code,
conn.getResponseMessage(), mEntity.getUrl())), true);
}
if (end) {
mTaskEntity.setChunked(isChunked);
@ -178,7 +240,7 @@ class HttpFileInfoThread implements Runnable {
/**
* 重命名文件
*/
private void fileRename(String newName) {
private void renameFile(String newName) {
if (TextUtils.isEmpty(newName)) {
ALog.w(TAG, "重命名失败【服务器返回的文件名为空】");
return;
@ -201,19 +263,20 @@ class HttpFileInfoThread implements Runnable {
if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null") || !newUrl.startsWith(
"http")) {
if (onFileInfoCallback != null) {
onFileInfoCallback.onFail(mEntity.getUrl(), "获取重定向链接失败", false);
onFileInfoCallback.onFail(mEntity.getUrl(), new TaskException(TAG, "获取重定向链接失败"), false);
}
return;
}
if (!CheckUtil.checkUrl(newUrl)) {
failDownload("下载失败,重定向url错误", false);
failDownload(new TaskException(TAG, "下载失败,重定向url错误"), false);
return;
}
mTaskEntity.setRedirectUrl(newUrl);
mEntity.setRedirect(true);
mEntity.setRedirectUrl(newUrl);
String cookies = conn.getHeaderField("Set-Cookie");
conn = (HttpURLConnection) new URL(newUrl).openConnection();
URL url = new URL(CommonUtil.convertUrl(newUrl));
conn = ConnectionHelp.handleConnection(url, mTaskEntity);
conn = ConnectionHelp.setConnectParam(mTaskEntity, conn);
conn.setRequestProperty("Cookie", cookies);
conn.setRequestProperty("Range", "bytes=" + 0 + "-");
@ -233,17 +296,12 @@ class HttpFileInfoThread implements Runnable {
if (len != mEntity.getFileSize()) {
mTaskEntity.setNewTask(true);
}
if (len < 0) {
failDownload("任务【" + mEntity.getUrl() + "】下载失败,文件长度小于0", true);
return false;
}
return true;
}
private void failDownload(String errorMsg, boolean needRetry) {
ALog.e(TAG, errorMsg);
private void failDownload(BaseException e, boolean needRetry) {
if (onFileInfoCallback != null) {
onFileInfoCallback.onFail(mEntity.getUrl(), errorMsg, needRetry);
onFileInfoCallback.onFail(mEntity.getUrl(), e, needRetry);
}
}
}

@ -15,13 +15,15 @@
*/
package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.AbsThreadTask;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.common.StateConstance;
import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.IDownloadListener;
import com.arialyy.aria.exception.AriaIOException;
import com.arialyy.aria.exception.TaskException;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.BufferedRandomAccessFile;
import com.arialyy.aria.util.CommonUtil;
@ -29,13 +31,17 @@ import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.util.Map;
import java.util.Set;
/**
* Created by lyy on 2017/1/18.
@ -49,20 +55,19 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
HttpThreadTask(StateConstance constance, IDownloadListener listener,
SubThreadConfig<DownloadTaskEntity> downloadInfo) {
super(constance, listener, downloadInfo);
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
mConnectTimeOut = manager.getDownloadConfig().getConnectTimeOut();
mReadTimeOut = manager.getDownloadConfig().getIOTimeOut();
mBufSize = manager.getDownloadConfig().getBuffSize();
isNotNetRetry = manager.getDownloadConfig().isNotNetRetry();
mConnectTimeOut = mAridManager.getDownloadConfig().getConnectTimeOut();
mReadTimeOut = mAridManager.getDownloadConfig().getIOTimeOut();
mBufSize = mAridManager.getDownloadConfig().getBuffSize();
isNotNetRetry = mAridManager.getDownloadConfig().isNotNetRetry();
isOpenDynamicFile = STATE.TASK_RECORD.isOpenDynamicFile;
isBlock = STATE.TASK_RECORD.isBlock;
setMaxSpeed(manager.getDownloadConfig().getMaxSpeed());
}
@Override public void run() {
if (mConfig.THREAD_RECORD.isComplete) {
@Override public HttpThreadTask call() throws Exception {
super.call();
if (getThreadRecord().isComplete) {
handleComplete();
return;
return this;
}
HttpURLConnection conn = null;
BufferedInputStream is = null;
@ -76,7 +81,6 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
ALog.d(TAG,
String.format("任务【%s】线程__%s__开始下载【开始位置 : %s,结束位置:%s】", mConfig.TEMP_FILE.getName(),
mConfig.THREAD_ID, mConfig.START_LOCATION, mConfig.END_LOCATION));
//在头里面请求下载开始位置和结束位置
conn.setRequestProperty("Range",
String.format("bytes=%s-%s", mConfig.START_LOCATION, (mConfig.END_LOCATION - 1)));
} else {
@ -86,6 +90,23 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
conn.setConnectTimeout(mConnectTimeOut);
conn.setReadTimeout(mReadTimeOut); //设置读取流的等待时间,必须设置该参数
conn.connect();
if (mTaskEntity.getRequestEnum() == RequestEnum.POST) {
Map<String, String> params = mTaskEntity.getParams();
if (params != null) {
OutputStreamWriter dos = new OutputStreamWriter(conn.getOutputStream());
Set<String> keys = params.keySet();
StringBuilder sb = new StringBuilder();
for (String key : keys) {
sb.append(key).append("=").append(URLEncoder.encode(params.get(key))).append("&");
}
String paramStr = sb.toString();
paramStr = paramStr.substring(0, paramStr.length() - 1);
dos.write(paramStr);
dos.flush();
dos.close();
}
}
is = new BufferedInputStream(ConnectionHelp.convertInputStream(conn));
if (isOpenDynamicFile) {
readDynamicFile(is);
@ -102,11 +123,17 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
handleComplete();
}
} catch (MalformedURLException e) {
fail(mChildCurrentLocation, "下载链接异常", e);
fail(mChildCurrentLocation, new TaskException(TAG,
String.format("任务【%s】下载失败,filePath: %s, url: %s", mConfig.TEMP_FILE.getName(),
mEntity.getDownloadPath(), mEntity.getUrl()), e));
} catch (IOException e) {
fail(mChildCurrentLocation, String.format("下载失败【%s】", mConfig.URL), e);
fail(mChildCurrentLocation, new TaskException(TAG,
String.format("任务【%s】下载失败,filePath: %s, url: %s", mConfig.TEMP_FILE.getName(),
mEntity.getDownloadPath(), mEntity.getUrl()), e));
} catch (Exception e) {
fail(mChildCurrentLocation, "获取流失败", e);
fail(mChildCurrentLocation, new TaskException(TAG,
String.format("任务【%s】下载失败,filePath: %s, url: %s", mConfig.TEMP_FILE.getName(),
mEntity.getDownloadPath(), mEntity.getUrl()), e));
} finally {
try {
if (file != null) {
@ -122,6 +149,7 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
e.printStackTrace();
}
}
return this;
}
/**
@ -137,26 +165,38 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
foc = fos.getChannel();
fic = Channels.newChannel(is);
ByteBuffer bf = ByteBuffer.allocate(mBufSize);
while ((len = fic.read(bf)) != -1) {
//如果要通过 Future 的 cancel 方法取消正在运行的任务,那么该任务必定是可以 对线程中断做出响应 的任务。
while (isLive() && (len = fic.read(bf)) != -1) {
if (isBreak()) {
break;
}
if (mSleepTime > 0) {
Thread.sleep(mSleepTime);
if (mSpeedBandUtil != null) {
mSpeedBandUtil.limitNextBytes(len);
}
if (mChildCurrentLocation + len >= mConfig.END_LOCATION) {
len = (int) (mConfig.END_LOCATION - mChildCurrentLocation);
bf.flip();
fos.write(bf.array(), 0, len);
bf.compact();
progress(len);
break;
} else {
bf.flip();
foc.write(bf);
bf.compact();
progress(len);
}
bf.flip();
foc.write(bf);
bf.compact();
progress(len);
}
handleComplete();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
fail(mChildCurrentLocation, String.format("下载失败【%s】", mConfig.URL), e);
fail(mChildCurrentLocation, new AriaIOException(TAG,
String.format("文件下载失败,savePath: %s, url: %s", mEntity.getDownloadPath(), mConfig.URL),
e));
} finally {
try {
if (fos != null) {
fos.flush();
fos.close();
}
if (foc != null) {
@ -177,7 +217,7 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
* @deprecated 暂时先这样处理无chun
*/
private void readChunk(InputStream is, BufferedRandomAccessFile file)
throws IOException, InterruptedException {
throws IOException {
readNormal(is, file);
}
@ -185,15 +225,15 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
* 读取普通的文件流
*/
private void readNormal(InputStream is, BufferedRandomAccessFile file)
throws IOException, InterruptedException {
throws IOException {
byte[] buffer = new byte[mBufSize];
int len;
while ((len = is.read(buffer)) != -1) {
while (isLive() && (len = is.read(buffer)) != -1) {
if (isBreak()) {
break;
}
if (mSleepTime > 0) {
Thread.sleep(mSleepTime);
if (mSpeedBandUtil != null) {
mSpeedBandUtil.limitNextBytes(len);
}
file.write(buffer, 0, len);
progress(len);
@ -219,9 +259,9 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
if (isBlock) {
boolean success = mergeFile();
if (!success) {
ALog.e(TAG, String.format("任务【%s】分块文件合并失败", mConfig.TEMP_FILE.getName()));
STATE.isRunning = false;
mListener.onFail(false);
mListener.onFail(false, new TaskException(TAG,
String.format("任务【%s】分块文件合并失败", mConfig.TEMP_FILE.getName())));
return;
}
}
@ -231,7 +271,10 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
}
if (STATE.isFail()) {
STATE.isRunning = false;
mListener.onFail(false);
mListener.onFail(false,
new TaskException(TAG,
String.format("任务【%s】下载失败,filePath: %s, url: %s", mConfig.TEMP_FILE.getName(),
mEntity.getDownloadPath(), mEntity.getUrl())));
}
} else {
ALog.i(TAG, "任务下载完成");
@ -242,4 +285,8 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
STATE.FAIL_NUM++;
}
}
@Override public int getMaxSpeed() {
return mAridManager.getDownloadConfig().getMaxSpeed();
}
}

@ -17,6 +17,7 @@ package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.inf.IDownloadListener;
import com.arialyy.aria.exception.BaseException;
/**
* Created by Aria.Lao on 2017/7/20.
@ -54,7 +55,7 @@ public interface IDownloadGroupListener extends IDownloadListener {
/**
* 子任务下载失败
*/
void onSubFail(DownloadEntity subEntity);
void onSubFail(DownloadEntity subEntity, BaseException e);
/**
* 子任务取消下载

@ -23,7 +23,8 @@ import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IDownloadListener;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.util.ErrorHelp;
import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.exception.TaskException;
/**
* Created by lyy on 2015/8/25.
@ -77,7 +78,7 @@ public class SimpleDownloadUtil implements IUtil, Runnable {
* 多线程断点续传下载文件开始下载
*/
@Override public void start() {
if (isStop || isCancel){
if (isStop || isCancel) {
return;
}
new Thread(this).start();
@ -87,16 +88,15 @@ public class SimpleDownloadUtil implements IUtil, Runnable {
start();
}
public void setMaxSpeed(double maxSpeed) {
mDownloader.setMaxSpeed(maxSpeed);
@Override public void setMaxSpeed(int speed) {
mDownloader.setMaxSpeed(speed);
}
private void failDownload(String msg, boolean needRetry) {
private void failDownload(BaseException e, boolean needRetry) {
if (isStop || isCancel) {
return;
}
mListener.onFail(needRetry);
ErrorHelp.saveError(TAG, msg, "");
mListener.onFail(needRetry, e);
}
@Override public void run() {
@ -125,8 +125,9 @@ public class SimpleDownloadUtil implements IUtil, Runnable {
mDownloader.start();
}
@Override public void onFail(String url, String errorMsg, boolean needRetry) {
failDownload(errorMsg, needRetry);
@Override public void onFail(String url, BaseException e, boolean needRetry) {
failDownload(e, needRetry);
mDownloader.closeTimer();
}
});
case AbsTaskEntity.D_HTTP:
@ -135,8 +136,9 @@ public class SimpleDownloadUtil implements IUtil, Runnable {
mDownloader.start();
}
@Override public void onFail(String url, String errorMsg, boolean needRetry) {
failDownload(errorMsg, needRetry);
@Override public void onFail(String url, BaseException e, boolean needRetry) {
failDownload(e, needRetry);
mDownloader.closeTimer();
}
});
}

@ -19,11 +19,12 @@ import android.os.Parcel;
import android.os.Parcelable;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.orm.annotation.Ignore;
import java.io.Serializable;
/**
* Created by AriaL on 2017/6/29.
*/
public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable {
public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable, Serializable {
/**
* 速度
*/

@ -21,10 +21,8 @@ import com.arialyy.aria.core.download.downloader.AbsGroupUtil;
* Created by AriaL on 2017/6/29.
* 任务组任务抽象类
*/
public abstract class AbsGroupTask<TASK_ENTITY extends AbsGroupTaskEntity>
extends AbsTask<TASK_ENTITY> {
protected AbsGroupUtil mUtil;
public abstract class AbsGroupTask<ENTITY extends AbsEntity, TASK_ENTITY extends AbsGroupTaskEntity>
extends AbsTask<ENTITY, TASK_ENTITY> {
@Override public String getKey() {
return mTaskEntity.getEntity().getKey();
@ -37,7 +35,7 @@ public abstract class AbsGroupTask<TASK_ENTITY extends AbsGroupTaskEntity>
*/
public void startSubTask(String url) {
if (mUtil != null) {
mUtil.startSubTask(url);
((AbsGroupUtil) mUtil).startSubTask(url);
}
}
@ -48,7 +46,7 @@ public abstract class AbsGroupTask<TASK_ENTITY extends AbsGroupTaskEntity>
*/
public void stopSubTask(String url) {
if (mUtil != null) {
mUtil.stopSubTask(url);
((AbsGroupUtil) mUtil).stopSubTask(url);
}
}
@ -59,7 +57,7 @@ public abstract class AbsGroupTask<TASK_ENTITY extends AbsGroupTaskEntity>
*/
public void cancelSubTask(String url) {
if (mUtil != null) {
mUtil.cancelSubTask(url);
((AbsGroupUtil) mUtil).cancelSubTask(url);
}
}
}

@ -18,15 +18,8 @@ package com.arialyy.aria.core.inf;
/**
* Created by lyy on 2017/6/3.
*/
public abstract class AbsNormalTask<TASK_ENTITY extends AbsNormalTaskEntity>
extends AbsTask<TASK_ENTITY> {
/**
* 暂停任务并让任务处于等待状态
*/
public void stopAndWait() {
}
public abstract class AbsNormalTask<ENTITY extends AbsEntity, TASK_ENTITY extends AbsNormalTaskEntity>
extends AbsTask<ENTITY, TASK_ENTITY> {
/**
* 最高优先级命令最高优先级命令有以下属性

@ -21,10 +21,14 @@ import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.ICmd;
import com.arialyy.aria.core.command.normal.CancelCmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.common.TaskRecord;
import com.arialyy.aria.core.common.http.PostDelegate;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.util.ArrayList;
@ -34,8 +38,8 @@ import java.util.List;
* Created by AriaL on 2017/7/3.
*/
public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity>
implements ITarget<TARGET> {
protected String TAG ;
implements ITarget {
protected String TAG;
protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity;
protected String mTargetName;
@ -64,17 +68,33 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
ALog.d("AbsTarget", "任务正在下载,即将删除任务");
cancel();
} else {
mEntity.deleteData();
if (mEntity instanceof AbsNormalEntity) {
TaskRecord record =
DbEntity.findFirst(TaskRecord.class, "TaskRecord.filePath=?", mTaskEntity.getKey());
if (record != null) {
CommonUtil.delTaskRecord(record, mTaskEntity.isRemoveFile(), (AbsNormalEntity) mEntity);
} else {
mEntity.deleteData();
}
} else if (mEntity instanceof DownloadGroupEntity) {
CommonUtil.delGroupTaskRecord(mTaskEntity.isRemoveFile(), ((DownloadGroupEntity) mEntity));
}
TEManager.getInstance().removeTEntity(mEntity.getKey());
}
}
/**
* 获取任务实体
*/
public TASK_ENTITY getTaskEntity() {
return mTaskEntity;
}
/**
* 获取任务进度如果任务存在则返回当前进度
*
* @return 该任务进度
*/
@Override
public long getCurrentProgress() {
return mEntity == null ? -1 : mEntity.getCurrentProgress();
}
@ -84,7 +104,7 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
*
* @return 文件大小
*/
@Override public long getSize() {
public long getSize() {
return mEntity == null ? 0 : mEntity.getFileSize();
}
@ -93,7 +113,7 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
*
* @return 文件大小{@code xxx mb}
*/
@Override public String getConvertSize() {
public String getConvertSize() {
return mEntity == null ? "0b" : CommonUtil.formatFileSize(mEntity.getFileSize());
}
@ -129,7 +149,6 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
*
* @return {@link IEntity}
*/
@Override
public int getTaskState() {
return mEntity.getState();
}
@ -139,7 +158,7 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
*
* @return 返回任务进度
*/
@Override public int getPercent() {
public int getPercent() {
if (mEntity == null) {
ALog.e("AbsTarget", "下载管理器中没有该任务");
return 0;
@ -178,14 +197,28 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
}
}
/**
* 任务是否在执行
*
* @return {@code true} 任务正在执行
*/
public abstract boolean isRunning();
/**
* 任务是否存在
*
* @return {@code true} 任务存在
*/
public abstract boolean taskExists();
/**
* 开始任务
*/
@Override public void start() {
if (checkEntity()) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START,
checkTaskType()))
.setCmd(
CommonUtil.createNormalCmd(mTaskEntity, NormalCmdFactory.TASK_START, checkTaskType()))
.exe();
}
}
@ -204,8 +237,8 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
@Override public void stop() {
if (checkEntity()) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP,
checkTaskType()))
.setCmd(
CommonUtil.createNormalCmd(mTaskEntity, NormalCmdFactory.TASK_STOP, checkTaskType()))
.exe();
}
}
@ -216,8 +249,8 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
@Override public void resume() {
if (checkEntity()) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START,
checkTaskType()))
.setCmd(
CommonUtil.createNormalCmd(mTaskEntity, NormalCmdFactory.TASK_START, checkTaskType()))
.exe();
}
}
@ -228,7 +261,7 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
@Override public void cancel() {
if (checkEntity()) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CANCEL,
.setCmd(CommonUtil.createNormalCmd(mTaskEntity, NormalCmdFactory.TASK_CANCEL,
checkTaskType()))
.exe();
}
@ -242,10 +275,8 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
List<ICmd> cmds = new ArrayList<>();
int taskType = checkTaskType();
cmds.add(
CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP,
taskType));
cmds.add(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START,
taskType));
CommonUtil.createNormalCmd(mTaskEntity, NormalCmdFactory.TASK_STOP, taskType));
cmds.add(CommonUtil.createNormalCmd(mTaskEntity, NormalCmdFactory.TASK_START, taskType));
AriaManager.getInstance(AriaManager.APP).setCmds(cmds).exe();
}
}
@ -258,8 +289,9 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
*/
public void cancel(boolean removeFile) {
if (checkEntity()) {
CancelCmd cancelCmd = (CancelCmd) CommonUtil.createNormalCmd(mTargetName, mTaskEntity,
NormalCmdFactory.TASK_CANCEL, checkTaskType());
CancelCmd cancelCmd =
(CancelCmd) CommonUtil.createNormalCmd(mTaskEntity, NormalCmdFactory.TASK_CANCEL,
checkTaskType());
cancelCmd.removeFile = removeFile;
AriaManager.getInstance(AriaManager.APP).setCmd(cancelCmd).exe();
}

@ -17,12 +17,19 @@ package com.arialyy.aria.core.inf;
import android.content.Context;
import android.os.Handler;
import android.text.TextUtils;
import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.util.HashMap;
import java.util.Map;
/**
* Created by AriaL on 2017/6/29.
*/
public abstract class AbsTask<TASK_ENTITY extends AbsTaskEntity> implements ITask<TASK_ENTITY> {
public abstract class AbsTask<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity>
implements ITask<TASK_ENTITY> {
public static final String ERROR_INFO_KEY = "ERROR_INFO_KEY";
/**
* 是否需要重试默认为true
@ -30,19 +37,64 @@ public abstract class AbsTask<TASK_ENTITY extends AbsTaskEntity> implements ITas
public boolean needRetry = true;
protected TASK_ENTITY mTaskEntity;
protected Handler mOutHandler;
/**
* 用于生成该任务对象的hash码
*/
private String mTargetName;
protected Context mContext;
protected boolean isHeighestTask = false;
boolean isHeighestTask = false;
private boolean isCancel = false, isStop = false;
protected IUtil mUtil;
/**
* 扩展信息
*/
private Map<String, Object> mExpand = new HashMap<>();
/**
* 该任务的调度类型
*/
@TaskSchedulerType
private int mSchedulerType = TaskSchedulerType.TYPE_DEFAULT;
protected IEventListener mListener;
protected ENTITY mEntity;
protected String TAG;
protected AbsTask() {
TAG = CommonUtil.getClassName(this);
}
public Handler getOutHandler() {
return mOutHandler;
}
/**
* 添加扩展数据
* 读取扩展数据{@link #getExpand(String)}
*/
public void putExpand(String key, Object obj) {
if (TextUtils.isEmpty(key)) {
ALog.e(TAG, "key 为空");
return;
} else if (obj == null) {
ALog.e(TAG, "扩展数据为空");
return;
}
mExpand.put(key, obj);
}
/**
* 读取扩展数据
*/
public Object getExpand(String key) {
return mExpand.get(key);
}
/**
* 设置最大下载/上传速度
*
* @param speed 单位为kb
*/
public void setMaxSpeed(int speed) {
if (mUtil != null) {
mUtil.setMaxSpeed(speed);
}
}
/**
* 任务是否完成
*
@ -118,16 +170,55 @@ public abstract class AbsTask<TASK_ENTITY extends AbsTaskEntity> implements ITas
*
* @return 如果实体不存在则返回null否则返回扩展字段
*/
@Override public String getExtendField() {
public String getExtendField() {
return mTaskEntity.getEntity() == null ? null : mTaskEntity.getEntity().getStr();
}
@Override public void start() {
if (mUtil.isRunning()) {
ALog.d(TAG, "任务正在下载");
} else {
mUtil.start();
}
}
@Override public void stop() {
stop(TaskSchedulerType.TYPE_DEFAULT);
}
@Override public void stop(@TaskSchedulerType int type) {
isStop = true;
mSchedulerType = type;
if (mUtil.isRunning()) {
mUtil.stop();
} else {
mListener.onStop(mEntity.getCurrentProgress());
}
}
@Override public void cancel() {
isCancel = true;
if (!mUtil.isRunning()) {
mListener.onCancel();
} else {
mUtil.cancel();
}
}
/**
* 是否真正下载
*
* @return {@code true} 真正下载
*/
@Override public boolean isRunning() {
return mUtil.isRunning();
}
/**
* 任务的调度类型
*/
public int getSchedulerType() {
return mSchedulerType;
}
/**
@ -199,14 +290,6 @@ public abstract class AbsTask<TASK_ENTITY extends AbsTaskEntity> implements ITas
*/
public abstract String getTaskName();
public String getTargetName() {
return mTargetName;
}
@Override public void setTargetName(String targetName) {
this.mTargetName = targetName;
}
public boolean isHighestPriorityTask() {
return isHeighestTask;
}

@ -19,8 +19,12 @@ import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.orm.annotation.Ignore;
import java.net.CookieManager;
import java.net.HttpCookie;
import java.net.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@ -55,6 +59,8 @@ public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
*/
public static final int U_FTP = 0xA2;
@Ignore private CookieManager cookieManager;
/**
* 账号和密码
*/
@ -70,6 +76,11 @@ public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
*/
@Ignore private boolean isNewTask = false;
/**
* 请求参数
*/
@Ignore private Map<String, String> params;
/**
* 任务状态和Entity的state同步
*/
@ -129,6 +140,14 @@ public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
public abstract ENTITY getEntity();
public CookieManager getCookieManager() {
return cookieManager;
}
public void setCookieManager(CookieManager cookieManager) {
this.cookieManager = cookieManager;
}
/**
* 获取任务下载状态
*
@ -256,4 +275,12 @@ public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
public void setCode(int code) {
this.code = code;
}
public Map<String, String> getParams() {
return params;
}
public void setParams(Map<String, String> params) {
this.params = params;
}
}

@ -15,6 +15,8 @@
*/
package com.arialyy.aria.core.inf;
import com.arialyy.aria.exception.BaseException;
/**
* Created by Aria.Lao on 2017/7/18.
* 基础事件
@ -58,8 +60,9 @@ public interface IEventListener {
/**
* 下载失败
*
* @param needRetry 是否需要重试{@code true} 需要
* @param e 失败信息
*/
void onFail(boolean needRetry);
void onFail(boolean needRetry, BaseException e);
}

@ -16,6 +16,7 @@
package com.arialyy.aria.core.inf;
import android.support.annotation.CheckResult;
import java.net.Proxy;
/**
* Created by laoyuyu on 2018/3/9.
@ -45,4 +46,12 @@ public interface IFtpTarget<TARGET extends ITarget> {
*/
@CheckResult
TARGET login(String userName, String password, String account);
/**
* 设置代理
*
* @param proxy {@link Proxy}
*/
@CheckResult
TARGET setProxy(Proxy proxy);
}

@ -19,13 +19,14 @@ import android.support.annotation.CheckResult;
import android.support.annotation.NonNull;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.download.DownloadEntity;
import java.net.Proxy;
import java.util.Map;
/**
* Created by laoyuyu on 2018/3/9.
* HTTP Header功能接口
*/
public interface IHttpHeaderTarget<TARGET extends ITarget> {
public interface IHttpHeaderDelegate<TARGET extends ITarget> {
/**
* 给url请求添加Header数据
@ -46,11 +47,6 @@ public interface IHttpHeaderTarget<TARGET extends ITarget> {
@CheckResult
TARGET addHeaders(Map<String, String> headers);
/**
* 设置HTTP请求类型
*
* @param requestEnum {@link RequestEnum}
*/
@CheckResult
TARGET setRequestMode(RequestEnum requestEnum);
TARGET setUrlProxy(Proxy proxy);
}

@ -0,0 +1,31 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.core.inf;
import java.util.Map;
/**
* post 通用处理接口
*/
public interface IPostDelegate<TARGET extends ITarget> {
/**
* 设置Post请求参数
*/
TARGET setParams(Map<String, String> params);
TARGET setParam(String key, String value);
}

@ -18,48 +18,7 @@ package com.arialyy.aria.core.inf;
/**
* Created by AriaL on 2017/6/29.
*/
public interface ITarget<TARGET extends ITarget> {
/**
* 获取任务状态
*
* @return {@link IEntity}
*/
int getTaskState();
/**
* 任务是否在执行
*
* @return {@code true} 任务正在执行
*/
boolean isRunning();
/**
* 任务是否存在
*
* @return {@code true} 任务存在
*/
boolean taskExists();
/**
* 任务文件大小
*/
long getSize();
/**
* 转换后的大小
*/
String getConvertSize();
/**
* 获取任务进度百分比
*/
int getPercent();
/**
* 获取任务进度如果任务存在则返回当前进度
*/
long getCurrentProgress();
public interface ITarget {
/**
* 开始下载
*/

@ -25,11 +25,6 @@ public interface ITask<TASK_ENTITY extends AbsTaskEntity> {
*/
int getState();
/**
* 获取扩展字段
*/
String getExtendField();
/**
* 唯一标识符DownloadTask 为下载地址UploadTask 为文件路径
*/
@ -49,8 +44,17 @@ public interface ITask<TASK_ENTITY extends AbsTaskEntity> {
void start();
/**
* 停止任务
*/
void stop();
/**
* 停止任务
* @param type {@code 0}默认操作{@code 1}停止任务不自动执行下一任务
*/
void stop(int type);
void cancel();
/**
@ -89,6 +93,4 @@ public interface ITask<TASK_ENTITY extends AbsTaskEntity> {
* @return 返回 3mb
*/
String getConvertCurrentProgress();
void setTargetName(String targetName);
}

@ -0,0 +1,22 @@
package com.arialyy.aria.core.inf;
import android.support.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@IntDef({
TaskSchedulerType.TYPE_DEFAULT,
TaskSchedulerType.TYPE_STOP_NOT_NEXT,
TaskSchedulerType.TYPE_STOP_AND_WAIT
})
@Retention(RetentionPolicy.SOURCE) public @interface TaskSchedulerType {
int TYPE_DEFAULT = 1;
/**
* 停止当前任务并且不自动启动下一任务
*/
int TYPE_STOP_NOT_NEXT = 2;
/**
* 停止任务并让当前任务处于等待状态
*/
int TYPE_STOP_AND_WAIT = 3;
}

@ -59,15 +59,11 @@ class DGTEFactory implements IGTEFactory<DownloadGroupEntity, DownloadGroupTaskE
if (gte == null) {
// 创建新的任务组任务实体
gte = new DownloadGroupTaskEntity();
//创建子任务的任务实体
gte.setSubTaskEntities(createDGSubTaskEntity(entity));
} else if (gte.getSubTaskEntities() == null || gte.getSubTaskEntities().isEmpty()) {
gte.setSubTaskEntities(createDGSubTaskEntity(entity));
}
} else {
gte = new DownloadGroupTaskEntity();
gte.setSubTaskEntities(createDGSubTaskEntity(entity));
}
gte.setSubTaskEntities(createDGSubTaskEntity(entity));
gte.setKey(entity.getGroupName());
gte.setEntity(entity);

@ -0,0 +1,135 @@
/*
* 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.manager;
import com.arialyy.aria.core.common.AbsThreadTask;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* 线程管理器
*/
public class ThreadTaskManager {
private static volatile ThreadTaskManager INSTANCE = null;
private static final Object LOCK = new Object();
private final String TAG = "ThreadTaskManager";
private ExecutorService mExePool;
private Map<String, Set<Future>> mThreadTasks = new HashMap<>();
public static ThreadTaskManager getInstance() {
if (INSTANCE == null) {
synchronized (LOCK) {
INSTANCE = new ThreadTaskManager();
}
}
return INSTANCE;
}
private ThreadTaskManager() {
mExePool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
}
/**
* 启动线程任务
*
* @param key 任务对应的key{@link AbsTaskEntity#getKey()}
* @param threadTask 线程任务{@link AbsThreadTask}
*/
public synchronized void startThread(String key, AbsThreadTask threadTask) {
if (mExePool.isShutdown()) {
ALog.e(TAG, "线程池已经关闭");
return;
}
key = getKey(key);
Set<Future> temp = mThreadTasks.get(key);
if (temp == null) {
temp = new HashSet<>();
mThreadTasks.put(key, temp);
}
temp.add(mExePool.submit(threadTask));
}
/**
* 停止任务的所有线程
*
* @param key 任务对应的key{@link AbsTaskEntity#getKey()}
*/
public synchronized void stopTaskThread(String key) {
if (mExePool.isShutdown()) {
ALog.e(TAG, "线程池已经关闭");
return;
}
key = getKey(key);
Set<Future> temp = mThreadTasks.get(key);
if (temp != null && temp.size() > 0) {
try {
for (Future future : temp) {
if (future.isDone() || future.isCancelled()) {
continue;
}
AbsThreadTask task = (AbsThreadTask) future.get();
task.setInterrupted(true);
future.cancel(true);
}
} catch (Exception e) {
ALog.e(TAG, e);
}
temp.clear();
}
mThreadTasks.remove(key);
}
/**
* 重试线程任务
*
* @param task 线程任务
*/
public synchronized void retryThread(AbsThreadTask task) {
if (mExePool.isShutdown()) {
ALog.e(TAG, "线程池已经关闭");
return;
}
try {
if (task == null || task.isInterrupted()) {
ALog.e(TAG, "线程为空或线程已经中断");
return;
}
} catch (Exception e) {
ALog.e(TAG, e);
return;
}
mExePool.submit(task);
}
/**
* map中的key
*
* @param key 任务的key{@link AbsTaskEntity#getKey()}
* @return 转换后的map中的key
*/
private String getKey(String key) {
return CommonUtil.getStrMd5(key);
}
}

@ -19,9 +19,12 @@ package com.arialyy.aria.core.queue;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.TaskSchedulerType;
import com.arialyy.aria.core.queue.pool.BaseCachePool;
import com.arialyy.aria.core.queue.pool.BaseExecutePool;
import com.arialyy.aria.util.ALog;
import java.util.Map;
import java.util.Set;
/**
* Created by lyy on 2017/2/23.
@ -67,17 +70,37 @@ abstract class AbsTaskQueue<TASK extends AbsTask, TASK_ENTITY extends AbsTaskEnt
* 停止所有任务
*/
@Override public void stopAllTask() {
mCachePool.clear();
for (String key : mExecutePool.getAllTask().keySet()) {
TASK task = mExecutePool.getAllTask().get(key);
if (task != null) {
int state = task.getState();
if (task.isRunning() || (state != IEntity.STATE_COMPLETE
&& state != IEntity.STATE_CANCEL)) {
task.stop();
task.stop(TaskSchedulerType.TYPE_STOP_NOT_NEXT);
}
}
}
for (String key : mCachePool.getAllTask().keySet()) {
TASK task = mCachePool.getAllTask().get(key);
if (task != null) {
task.stop(TaskSchedulerType.TYPE_STOP_NOT_NEXT);
}
}
mCachePool.clear();
}
/**
* 最大下载速度
*/
public void setMaxSpeed(int maxSpeed) {
Map<String, TASK> tasks = mExecutePool.getAllTask();
Set<String> keys = tasks.keySet();
for (String key : keys) {
TASK task = tasks.get(key);
task.setMaxSpeed(maxSpeed);
}
}
/**
@ -173,7 +196,6 @@ abstract class AbsTaskQueue<TASK extends AbsTask, TASK_ENTITY extends AbsTaskEnt
}
@Override public void removeTaskFormQueue(String key) {
//TEManager.getInstance().removeTEntity(key);
TASK task = mExecutePool.getTask(key);
if (task != null) {
ALog.d(TAG, String.format("从执行池删除任务【%s】%s", task.getTaskName(),
@ -191,10 +213,6 @@ abstract class AbsTaskQueue<TASK extends AbsTask, TASK_ENTITY extends AbsTaskEnt
ALog.e(TAG, "任务重试失败,原因:task 为null");
return;
}
//if (!NetUtils.isConnected(AriaManager.APP)) {
// ALog.e(TAG, "任务【" + task.getTaskName() + "】重试失败,原因:网络未连接");
// return;
//}
if (!task.isRunning()) {
task.start();
} else {

@ -16,7 +16,6 @@
package com.arialyy.aria.core.queue;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadGroupTask;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
@ -60,19 +59,15 @@ public class DownloadGroupTaskQueue
return AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMaxTaskNum();
}
@Override public DownloadGroupTask createTask(String targetName, DownloadGroupTaskEntity entity) {
@Override public DownloadGroupTask createTask(DownloadGroupTaskEntity entity) {
DownloadGroupTask task = null;
if (!TextUtils.isEmpty(targetName)) {
if (mCachePool.getTask(entity.getEntity().getKey()) == null
&& mExecutePool.getTask(entity.getEntity().getKey()) == null) {
task = (DownloadGroupTask) TaskFactory.getInstance()
.createTask(targetName, entity, DownloadGroupSchedulers.getInstance());
mCachePool.putTask(task);
} else {
ALog.w(TAG, "任务已存在");
}
if (mCachePool.getTask(entity.getEntity().getKey()) == null
&& mExecutePool.getTask(entity.getEntity().getKey()) == null) {
task = (DownloadGroupTask) TaskFactory.getInstance()
.createTask(entity, DownloadGroupSchedulers.getInstance());
mCachePool.putTask(task);
} else {
ALog.e(TAG, "target name 为 null!!");
ALog.w(TAG, "任务已存在");
}
return task;
}

@ -16,10 +16,11 @@
package com.arialyy.aria.core.queue;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.TaskSchedulerType;
import com.arialyy.aria.core.queue.pool.BaseCachePool;
import com.arialyy.aria.core.queue.pool.BaseExecutePool;
import com.arialyy.aria.core.queue.pool.DownloadSharePool;
@ -89,7 +90,7 @@ public class DownloadTaskQueue extends AbsTaskQueue<DownloadTask, DownloadTaskEn
DownloadTask oldTsk = mExecutePool.pollTask();
if (oldTsk != null && oldTsk.isRunning()) {
if (i == maxSize - 1) {
oldTsk.stopAndWait();
oldTsk.stop(TaskSchedulerType.TYPE_STOP_AND_WAIT);
mCachePool.putTaskToFirst(oldTsk);
break;
}
@ -104,31 +105,15 @@ public class DownloadTaskQueue extends AbsTaskQueue<DownloadTask, DownloadTaskEn
}
}
/**
* 最大下载速度
*/
public void setMaxSpeed(double maxSpeed) {
Map<String, DownloadTask> tasks = mExecutePool.getAllTask();
Set<String> keys = tasks.keySet();
for (String key : keys) {
DownloadTask task = tasks.get(key);
task.setMaxSpeed(maxSpeed);
}
}
@Override public DownloadTask createTask(String target, DownloadTaskEntity entity) {
@Override public DownloadTask createTask(DownloadTaskEntity entity) {
DownloadTask task = null;
if (!TextUtils.isEmpty(target)) {
if (mCachePool.getTask(entity.getEntity().getKey()) == null
&& mExecutePool.getTask(entity.getEntity().getKey()) == null) {
task = (DownloadTask) TaskFactory.getInstance()
.createTask(target, entity, DownloadSchedulers.getInstance());
mCachePool.putTask(task);
} else {
ALog.w(TAG, "任务已存在");
}
if (mCachePool.getTask(entity.getEntity().getKey()) == null
&& mExecutePool.getTask(entity.getEntity().getKey()) == null) {
task = (DownloadTask) TaskFactory.getInstance()
.createTask(entity, DownloadSchedulers.getInstance());
mCachePool.putTask(task);
} else {
ALog.e(TAG, "target name 为 null!!");
ALog.w(TAG, "任务已存在");
}
return task;

@ -113,10 +113,9 @@ public interface ITaskQueue<TASK extends AbsTask, TASK_ENTITY extends AbsTaskEnt
* 创建一个新的任务创建时只是将新任务存储到缓存池
*
* @param entity 任务实体{@link DownloadTaskEntity}{@link UploadTaskEntity}
* @param targetName 生成该任务的对象
* @return {@link DownloadTask}{@link UploadTask}
*/
TASK createTask(String targetName, TASK_ENTITY entity);
TASK createTask(TASK_ENTITY entity);
/**
* 通过工作实体缓存池或任务池搜索下载任务如果缓存池或任务池都没有任务则创建新任务

@ -21,8 +21,8 @@ import com.arialyy.aria.core.download.DownloadGroupTask;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.ITask;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.ITask;
import com.arialyy.aria.core.scheduler.DownloadSchedulers;
import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.core.scheduler.UploadSchedulers;
@ -61,13 +61,13 @@ class TaskFactory {
* @return {@link DownloadTask}{@link UploadTask}{@link DownloadGroupTask}
*/
<TASK_ENTITY extends AbsTaskEntity, SCHEDULER extends ISchedulers> ITask createTask(
String targetName, TASK_ENTITY entity, SCHEDULER schedulers) {
TASK_ENTITY entity, SCHEDULER schedulers) {
if (entity instanceof DownloadTaskEntity) {
return createDownloadTask(targetName, (DownloadTaskEntity) entity, schedulers);
return createDownloadTask((DownloadTaskEntity) entity, schedulers);
} else if (entity instanceof UploadTaskEntity) {
return createUploadTask(targetName, (UploadTaskEntity) entity, schedulers);
return createUploadTask((UploadTaskEntity) entity, schedulers);
} else if (entity instanceof DownloadGroupTaskEntity) {
return createDownloadGroupTask(targetName, (DownloadGroupTaskEntity) entity, schedulers);
return createDownloadGroupTask((DownloadGroupTaskEntity) entity, schedulers);
}
return null;
}
@ -78,9 +78,9 @@ class TaskFactory {
* @param entity 下载任务实体{@link DownloadGroupTask}
* @param schedulers {@link ISchedulers}
*/
private DownloadGroupTask createDownloadGroupTask(String targetName,
DownloadGroupTaskEntity entity, ISchedulers schedulers) {
DownloadGroupTask.Builder builder = new DownloadGroupTask.Builder(targetName, entity);
private DownloadGroupTask createDownloadGroupTask(DownloadGroupTaskEntity entity,
ISchedulers schedulers) {
DownloadGroupTask.Builder builder = new DownloadGroupTask.Builder(entity);
builder.setOutHandler(schedulers);
return builder.build();
}
@ -89,10 +89,8 @@ class TaskFactory {
* @param entity 上传任务实体{@link UploadTaskEntity}
* @param schedulers {@link ISchedulers}
*/
private UploadTask createUploadTask(String targetName, UploadTaskEntity entity,
ISchedulers schedulers) {
private UploadTask createUploadTask(UploadTaskEntity entity, ISchedulers schedulers) {
UploadTask.Builder builder = new UploadTask.Builder();
builder.setTargetName(targetName);
builder.setUploadTaskEntity(entity);
builder.setOutHandler(schedulers);
return builder.build();
@ -102,9 +100,8 @@ class TaskFactory {
* @param entity 下载任务实体{@link DownloadTaskEntity}
* @param schedulers {@link ISchedulers}
*/
private DownloadTask createDownloadTask(String targetName, DownloadTaskEntity entity,
ISchedulers schedulers) {
DownloadTask.Builder builder = new DownloadTask.Builder(targetName, entity);
private DownloadTask createDownloadTask(DownloadTaskEntity entity, ISchedulers schedulers) {
DownloadTask.Builder builder = new DownloadTask.Builder(entity);
builder.setOutHandler(schedulers);
return builder.build();
}

@ -16,7 +16,6 @@
package com.arialyy.aria.core.queue;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.queue.pool.BaseCachePool;
import com.arialyy.aria.core.queue.pool.BaseExecutePool;
@ -62,19 +61,15 @@ public class UploadTaskQueue extends AbsTaskQueue<UploadTask, UploadTaskEntity>
return AriaManager.getInstance(AriaManager.APP).getUploadConfig().getMaxTaskNum();
}
@Override public UploadTask createTask(String targetName, UploadTaskEntity entity) {
@Override public UploadTask createTask(UploadTaskEntity entity) {
UploadTask task = null;
if (!TextUtils.isEmpty(targetName)) {
if (mCachePool.getTask(entity.getEntity().getKey()) == null
&& mExecutePool.getTask(entity.getEntity().getKey()) == null) {
task = (UploadTask) TaskFactory.getInstance()
.createTask(targetName, entity, UploadSchedulers.getInstance());
mCachePool.putTask(task);
} else {
ALog.w(TAG, "任务已存在");
}
if (mCachePool.getTask(entity.getEntity().getKey()) == null
&& mExecutePool.getTask(entity.getEntity().getKey()) == null) {
task = (UploadTask) TaskFactory.getInstance()
.createTask(entity, UploadSchedulers.getInstance());
mCachePool.putTask(task);
} else {
ALog.e(TAG, "target name 为 null是!!");
ALog.w(TAG, "任务已存在");
}
return task;
}

@ -56,6 +56,10 @@ public class AbsSchedulerListener<TASK extends ITask, SUB_ENTITY extends AbsNorm
}
@Override public void onTaskFail(TASK task, Exception e) {
}
@Override public void onTaskComplete(TASK task) {
}
@ -92,10 +96,15 @@ public class AbsSchedulerListener<TASK extends ITask, SUB_ENTITY extends AbsNorm
}
@Deprecated
public void onSubTaskFail(TASK task, SUB_ENTITY subTask) {
}
public void onSubTaskFail(TASK task, SUB_ENTITY subTask, Exception e) {
}
public void onSubTaskRunning(TASK task, SUB_ENTITY subTask) {
}

@ -26,6 +26,7 @@ import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.GroupSendParams;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.TaskSchedulerType;
import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.core.queue.ITaskQueue;
import com.arialyy.aria.core.upload.UploadTask;
@ -40,7 +41,7 @@ import java.util.concurrent.ConcurrentHashMap;
* Created by lyy on 2017/6/4.
* 事件调度器用于处理任务状态的调度
*/
abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends AbsTask<TASK_ENTITY>,
abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends AbsTask,
QUEUE extends ITaskQueue<TASK, TASK_ENTITY>> implements ISchedulers<TASK> {
private final String TAG = "AbsSchedulers";
@ -139,7 +140,8 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends Abs
listener.onSubTaskStop((TASK) params.groupTask, params.entity);
break;
case SUB_FAIL:
listener.onSubTaskFail((TASK) params.groupTask, params.entity);
listener.onSubTaskFail((TASK) params.groupTask, params.entity,
(Exception) (params.groupTask).getExpand(AbsTask.ERROR_INFO_KEY));
break;
case SUB_RUNNING:
listener.onSubTaskRunning((TASK) params.groupTask, params.entity);
@ -169,13 +171,13 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends Abs
mQueue.removeTaskFormQueue(task.getKey());
if (mQueue.getCurrentExePoolNum() < mQueue.getMaxTaskNum()) {
ALog.d(TAG, "stop_next");
startNextTask();
startNextTask(task);
}
break;
case COMPLETE:
mQueue.removeTaskFormQueue(task.getKey());
ALog.d(TAG, "complete_next");
startNextTask();
startNextTask(task);
break;
case FAIL:
handleFailTask(task);
@ -243,7 +245,7 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends Abs
listener.onTaskComplete(task);
break;
case FAIL:
listener.onTaskFail(task);
listener.onTaskFail(task, (Exception) task.getExpand(AbsTask.ERROR_INFO_KEY));
break;
case SUPPORT_BREAK_POINT:
listener.onNoSupportBreakPoint(task);
@ -259,9 +261,9 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends Abs
*/
private void handleFailTask(final TASK task) {
if (!task.needRetry || task.isStop() || task.isCancel()) {
callback(FAIL, task);
mQueue.removeTaskFormQueue(task.getKey());
ALog.d(TAG, "fail_next");
startNextTask();
startNextTask(task);
return;
}
long interval = 2000;
@ -283,8 +285,7 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends Abs
|| task.getTaskEntity().getEntity().getFailNum() > reTryNum) {
callback(FAIL, task);
mQueue.removeTaskFormQueue(task.getKey());
startNextTask();
ALog.d(TAG, "retry_next");
startNextTask(task);
TEManager.getInstance().removeTEntity(task.getKey());
return;
}
@ -302,8 +303,7 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends Abs
mQueue.reTryStart(task);
} else {
mQueue.removeTaskFormQueue(task.getKey());
startNextTask();
ALog.d(TAG, "retry_next_1");
startNextTask(task);
TEManager.getInstance().removeTEntity(task.getKey());
}
}
@ -314,11 +314,14 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends Abs
/**
* 启动下一个任务条件任务停止取消下载任务完成
*/
private void startNextTask() {
private void startNextTask(TASK oldTask) {
if (oldTask.getSchedulerType() == TaskSchedulerType.TYPE_STOP_NOT_NEXT) {
return;
}
TASK newTask = mQueue.getNextTask();
if (newTask == null) {
if (mQueue.getCurrentExePoolNum() == 0) {
ALog.i(TAG, "没有下一任务");
ALog.i(TAG, "没有等待中的任务");
}
return;
}

@ -59,10 +59,18 @@ public interface ISchedulerListener<TASK extends ITask> {
void onTaskCancel(TASK task);
/**
* 任务下载失败
* 任务失败
*
* @deprecated {@link #onTaskFail(ITask, Exception)}
*/
@Deprecated
void onTaskFail(TASK task);
/**
* 任务失败
*/
void onTaskFail(TASK task, Exception e);
/**
* 任务完成
*/

@ -80,6 +80,16 @@ abstract class BaseNormalTarget<TARGET extends AbsUploadTarget>
mEntity.save();
mTaskEntity.save();
}
if (mTaskEntity.getUrlEntity() != null && mTaskEntity.getUrlEntity().isFtps) {
if (TextUtils.isEmpty(mTaskEntity.getUrlEntity().storePath)) {
ALog.e(TAG, "证书路径为空");
return false;
}
if (TextUtils.isEmpty(mTaskEntity.getUrlEntity().keyAlias)) {
ALog.e(TAG, "证书别名为空");
return false;
}
}
return b;
}

@ -16,128 +16,27 @@
package com.arialyy.aria.core.upload;
import android.os.Handler;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.BaseListener;
import com.arialyy.aria.core.common.TaskRecord;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.IUploadListener;
import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CommonUtil;
import java.lang.ref.WeakReference;
/**
* 下载监听类
*/
class BaseUListener<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>, TASK extends AbsTask<TASK_ENTITY>>
class BaseUListener extends BaseListener<UploadEntity, UploadTaskEntity, UploadTask>
implements IUploadListener {
private WeakReference<Handler> outHandler;
private int RUN_SAVE_INTERVAL = 5 * 1000; //5s保存一次下载中的进度
private long mLastLen = 0; //上一次发送长度
private boolean isFirst = true;
protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity;
protected TASK mTask;
private boolean isConvertSpeed = false;
boolean isWait = false;
private long mLastSaveTime;
private long mUpdateInterval;
BaseUListener(TASK task, Handler outHandler) {
this.outHandler = new WeakReference<>(outHandler);
this.mTask = new WeakReference<>(task).get();
this.mEntity = this.mTask.getTaskEntity().getEntity();
this.mTaskEntity = this.mTask.getTaskEntity();
final AriaManager manager = AriaManager.getInstance(AriaManager.APP);
isConvertSpeed = manager.getDownloadConfig().isConvertSpeed();
mLastLen = mEntity.getCurrentProgress();
mLastSaveTime = System.currentTimeMillis();
BaseUListener(UploadTask task, Handler outHandler) {
super(task, outHandler);
isConvertSpeed = manager.getUploadConfig().isConvertSpeed();
mUpdateInterval = manager.getUploadConfig().getUpdateInterval();
}
@Override public void onPre() {
saveData(IEntity.STATE_PRE, -1);
sendInState2Target(ISchedulers.PRE);
}
@Override public void onStart(long startLocation) {
saveData(IEntity.STATE_RUNNING, startLocation);
sendInState2Target(ISchedulers.START);
}
@Override public void onResume(long resumeLocation) {
saveData(IEntity.STATE_RUNNING, resumeLocation);
sendInState2Target(ISchedulers.RESUME);
}
@Override public void onProgress(long currentLocation) {
mEntity.setCurrentProgress(currentLocation);
long speed = currentLocation - mLastLen;
if (isFirst) {
speed = 0;
isFirst = false;
}
handleSpeed(speed);
sendInState2Target(ISchedulers.RUNNING);
if (System.currentTimeMillis() - mLastSaveTime >= RUN_SAVE_INTERVAL) {
saveData(IEntity.STATE_RUNNING, currentLocation);
mLastSaveTime = System.currentTimeMillis();
}
mLastLen = currentLocation;
}
@Override public void onStop(long stopLocation) {
saveData(isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP, stopLocation);
handleSpeed(0);
sendInState2Target(ISchedulers.STOP);
}
@Override public void onCancel() {
saveData(IEntity.STATE_CANCEL, -1);
handleSpeed(0);
sendInState2Target(ISchedulers.CANCEL);
}
@Override public void onComplete() {
saveData(IEntity.STATE_COMPLETE, mEntity.getFileSize());
handleSpeed(0);
sendInState2Target(ISchedulers.COMPLETE);
}
@Override public void onFail(boolean needRetry) {
mEntity.setFailNum(mEntity.getFailNum() + 1);
saveData(IEntity.STATE_FAIL, mEntity.getCurrentProgress());
handleSpeed(0);
mTask.needRetry = needRetry;
sendInState2Target(ISchedulers.FAIL);
}
private void handleSpeed(long speed) {
if (mUpdateInterval != 1000) {
speed = speed * 1000 / mUpdateInterval;
}
if (isConvertSpeed) {
mEntity.setConvertSpeed(CommonUtil.formatFileSize(speed < 0 ? 0 : speed) + "/s");
}
mEntity.setSpeed(speed < 0 ? 0 : speed);
mEntity.setPercent((int) (mEntity.getFileSize() <= 0 ? 0
: mEntity.getCurrentProgress() * 100 / mEntity.getFileSize()));
}
/**
* 将任务状态发送给下载器
*
* @param state {@link ISchedulers#START}
*/
private void sendInState2Target(int state) {
if (outHandler.get() != null) {
outHandler.get().obtainMessage(state, mTask).sendToTarget();
}
}
private void saveData(int state, long location) {
@Override
protected void saveData(int state, long location) {
mTaskEntity.setState(state);
mEntity.setState(state);
mEntity.setComplete(state == IEntity.STATE_COMPLETE);
@ -146,7 +45,7 @@ class BaseUListener<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<
TaskRecord record =
DbEntity.findFirst(TaskRecord.class, "TaskRecord.filePath=?", mTaskEntity.getKey());
if (record != null) {
CommonUtil.delTaskRecord(record, mTaskEntity.isRemoveFile(), (UploadEntity) mEntity);
CommonUtil.delTaskRecord(record, mTaskEntity.isRemoveFile(), mEntity);
}
}
//else if (mEntity instanceof AbsGroupEntity) {

@ -17,11 +17,14 @@ package com.arialyy.aria.core.upload;
import android.support.annotation.CheckResult;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.delegate.FtpDelegate;
import com.arialyy.aria.core.common.ftp.FTPSConfig;
import com.arialyy.aria.core.common.ftp.FtpDelegate;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IFtpTarget;
import com.arialyy.aria.util.CommonUtil;
import java.net.Proxy;
/**
* Created by Aria.Lao on 2017/7/27.
@ -29,7 +32,7 @@ import com.arialyy.aria.util.CommonUtil;
*/
public class FtpUploadTarget extends BaseNormalTarget<FtpUploadTarget>
implements IFtpTarget<FtpUploadTarget> {
private FtpDelegate<FtpUploadTarget, UploadEntity, UploadTaskEntity> mDelegate;
private FtpDelegate<FtpUploadTarget> mDelegate;
private String mAccount, mUser, mPw;
private boolean needLogin = false;
@ -42,7 +45,7 @@ public class FtpUploadTarget extends BaseNormalTarget<FtpUploadTarget>
private void initTask(String filePath) {
initTarget(filePath);
mTaskEntity.setRequestType(AbsTaskEntity.U_FTP);
mDelegate = new FtpDelegate<>(this, mTaskEntity);
mDelegate = new FtpDelegate<>(this);
}
/**
@ -51,7 +54,7 @@ public class FtpUploadTarget extends BaseNormalTarget<FtpUploadTarget>
public void add() {
if (checkEntity()) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE,
.setCmd(CommonUtil.createNormalCmd(mTaskEntity, NormalCmdFactory.TASK_CREATE,
checkTaskType()))
.exe();
}
@ -62,7 +65,16 @@ public class FtpUploadTarget extends BaseNormalTarget<FtpUploadTarget>
if (!b) {
return false;
}
mTaskEntity.setUrlEntity(CommonUtil.getFtpUrlInfo(mTempUrl));
FtpUrlEntity temp = mTaskEntity.getUrlEntity();
FtpUrlEntity newEntity = CommonUtil.getFtpUrlInfo(mTempUrl);
if (temp != null) { //处理FTPS的信息
newEntity.isFtps = temp.isFtps;
newEntity.storePass = temp.storePass;
newEntity.keyAlias = temp.keyAlias;
newEntity.protocol = temp.protocol;
newEntity.storePath = temp.storePath;
}
mTaskEntity.setUrlEntity(newEntity);
mTaskEntity.getUrlEntity().account = mAccount;
mTaskEntity.getUrlEntity().user = mUser;
mTaskEntity.getUrlEntity().password = mPw;
@ -70,6 +82,21 @@ public class FtpUploadTarget extends BaseNormalTarget<FtpUploadTarget>
return true;
}
/**
* 是否是FTPS协议
* 如果是FTPS协议需要使用{@link FTPSConfig#setStorePath(String)} {@link FTPSConfig#setAlias(String)}
* 设置证书信息
*/
@CheckResult
public FTPSConfig<FtpUploadTarget> asFtps() {
if (mTaskEntity.getUrlEntity() == null) {
FtpUrlEntity urlEntity = new FtpUrlEntity();
urlEntity.isFtps = true;
mTaskEntity.setUrlEntity(urlEntity);
}
return new FTPSConfig<>(this);
}
@CheckResult
@Override public FtpUploadTarget charSet(String charSet) {
return mDelegate.charSet(charSet);
@ -89,4 +116,8 @@ public class FtpUploadTarget extends BaseNormalTarget<FtpUploadTarget>
mAccount = account;
return this;
}
@Override public FtpUploadTarget setProxy(Proxy proxy) {
return mDelegate.setProxy(proxy);
}
}

@ -16,6 +16,7 @@
package com.arialyy.aria.core.upload;
import com.arialyy.aria.core.inf.IUploadListener;
import com.arialyy.aria.exception.BaseException;
/**
* Created by lyy on 2017/2/23.
@ -49,7 +50,7 @@ class UploadListener implements IUploadListener {
}
@Override public void onFail(boolean needRetry) {
@Override public void onFail(boolean needRetry, BaseException e) {
}
}

@ -20,6 +20,7 @@ import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.ICmd;
import com.arialyy.aria.core.command.normal.CancelAllCmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.common.ProxyHelper;
import com.arialyy.aria.core.inf.AbsReceiver;
@ -39,6 +40,16 @@ import java.util.Set;
public class UploadReceiver extends AbsReceiver {
private static final String TAG = "UploadReceiver";
/**
* 设置最大上传速度单位kb
*
* @param maxSpeed 为0表示不限速
*/
public UploadReceiver setMaxSpeed(int maxSpeed) {
AriaManager.getInstance(AriaManager.APP).getUploadConfig().setMaxSpeed(maxSpeed);
return this;
}
/**
* 加载HTTP单文件上传任务
*
@ -78,7 +89,7 @@ public class UploadReceiver extends AbsReceiver {
* @return {@code true}存在{@code false} 不存在
*/
public boolean taskExists(String filePath) {
return DbEntity.findFirst(UploadEntity.class, "filePath=?", filePath) != null;
return DbEntity.checkDataExist(UploadTaskEntity.class, "key=?", filePath);
}
/**
@ -112,7 +123,7 @@ public class UploadReceiver extends AbsReceiver {
public void stopAllTask() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(NormalCmdFactory.getInstance()
.createCmd(targetName, new UploadTaskEntity(), NormalCmdFactory.TASK_STOP_ALL,
.createCmd(new UploadTaskEntity(), NormalCmdFactory.TASK_STOP_ALL,
ICmd.TASK_TYPE_UPLOAD))
.exe();
}
@ -125,10 +136,11 @@ public class UploadReceiver extends AbsReceiver {
*/
public void removeAllTask(boolean removeFile) {
final AriaManager am = AriaManager.getInstance(AriaManager.APP);
am.setCmd(CommonUtil.createNormalCmd(targetName, new UploadTaskEntity(),
NormalCmdFactory.TASK_CANCEL_ALL, ICmd.TASK_TYPE_UPLOAD)).exe();
CancelAllCmd cancelCmd =
(CancelAllCmd) CommonUtil.createNormalCmd(new UploadTaskEntity(),
NormalCmdFactory.TASK_CANCEL_ALL, ICmd.TASK_TYPE_UPLOAD);
cancelCmd.removeFile = removeFile;
am.setCmd(cancelCmd).exe();
Set<String> keys = am.getReceiver().keySet();
for (String key : keys) {
am.getReceiver().remove(key);
@ -148,9 +160,15 @@ public class UploadReceiver extends AbsReceiver {
ALog.e(TAG, String.format("【%s】观察者为空", targetName));
return;
}
Set<String> cCounter = ProxyHelper.getInstance().uploadCounter;
if (cCounter != null && cCounter.contains(targetName)) {
UploadSchedulers.getInstance().register(obj);
Set<Integer> set = ProxyHelper.getInstance().checkProxyType(obj.getClass());
if (set != null && !set.isEmpty()) {
for (Integer type : set) {
if (type == ProxyHelper.PROXY_TYPE_UPLOAD) {
UploadSchedulers.getInstance().register(obj);
}
}
} else {
ALog.i(TAG, "没有Aria的注解方法");
}
}
@ -179,9 +197,14 @@ public class UploadReceiver extends AbsReceiver {
ALog.e(TAG, String.format("【%s】观察者为空", targetName));
return;
}
Set<String> dCounter = ProxyHelper.getInstance().uploadCounter;
if (dCounter != null && dCounter.contains(targetName)) {
UploadSchedulers.getInstance().unRegister(obj);
Set<Integer> set = ProxyHelper.getInstance().mProxyCache.get(obj.getClass().getName());
if (set != null) {
for (Integer integer : set) {
if (integer == ProxyHelper.PROXY_TYPE_UPLOAD) {
UploadSchedulers.getInstance().unRegister(obj);
}
}
}
}
}

@ -17,10 +17,11 @@ package com.arialyy.aria.core.upload;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.delegate.HttpHeaderDelegate;
import com.arialyy.aria.core.common.http.HttpHeaderDelegate;
import com.arialyy.aria.core.common.http.PostDelegate;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IHttpHeaderTarget;
import com.arialyy.aria.core.inf.IHttpHeaderDelegate;
import java.net.Proxy;
import java.util.Map;
/**
@ -28,8 +29,8 @@ import java.util.Map;
* http 单文件上传
*/
public class UploadTarget extends BaseNormalTarget<UploadTarget>
implements IHttpHeaderTarget<UploadTarget> {
private HttpHeaderDelegate<UploadTarget, UploadEntity, UploadTaskEntity> mDelegate;
implements IHttpHeaderDelegate<UploadTarget> {
private HttpHeaderDelegate<UploadTarget> mDelegate;
UploadTarget(String filePath, String targetName) {
this.mTargetName = targetName;
@ -42,7 +43,14 @@ public class UploadTarget extends BaseNormalTarget<UploadTarget>
//http暂时不支持断点上传
mTaskEntity.setSupportBP(false);
mTaskEntity.setRequestType(AbsTaskEntity.U_HTTP);
mDelegate = new HttpHeaderDelegate<>(this, mTaskEntity);
mDelegate = new HttpHeaderDelegate<>(this);
}
/**
* Post处理
*/
public PostDelegate asPost() {
return new PostDelegate<>(this);
}
/**
@ -86,8 +94,7 @@ public class UploadTarget extends BaseNormalTarget<UploadTarget>
return mDelegate.addHeaders(headers);
}
@CheckResult
@Override public UploadTarget setRequestMode(RequestEnum requestEnum) {
return mDelegate.setRequestMode(requestEnum);
@Override public UploadTarget setUrlProxy(Proxy proxy) {
return mDelegate.setUrlProxy(proxy);
}
}

@ -15,7 +15,8 @@
*/
package com.arialyy.aria.core.upload.uploader;
import com.arialyy.aria.core.common.AbsFtpInfoThread;
import aria.apache.commons.net.ftp.FTPFile;
import com.arialyy.aria.core.common.ftp.AbsFtpInfoThread;
import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.common.TaskRecord;
@ -25,7 +26,6 @@ import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.DbHelper;
import java.util.ArrayList;
import org.apache.commons.net.ftp.FTPFile;
/**
* Created by Aria.Lao on 2017/9/26.

@ -15,20 +15,21 @@
*/
package com.arialyy.aria.core.upload.uploader;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.AbsFtpThreadTask;
import aria.apache.commons.net.ftp.FTPClient;
import aria.apache.commons.net.ftp.FTPReply;
import aria.apache.commons.net.ftp.OnFtpInputStreamListener;
import com.arialyy.aria.core.common.StateConstance;
import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.common.ftp.AbsFtpThreadTask;
import com.arialyy.aria.core.inf.IEventListener;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.exception.AriaIOException;
import com.arialyy.aria.exception.TaskException;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.BufferedRandomAccessFile;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.OnFtpInputStreamListener;
/**
* Created by Aria.Lao on 2017/7/28.
@ -41,14 +42,18 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
FtpThreadTask(StateConstance constance, IEventListener listener,
SubThreadConfig<UploadTaskEntity> info) {
super(constance, listener, info);
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
mConnectTimeOut = manager.getUploadConfig().getConnectTimeOut();
mReadTimeOut = manager.getUploadConfig().getIOTimeOut();
mBufSize = manager.getUploadConfig().getBuffSize();
isNotNetRetry = manager.getUploadConfig().isNotNetRetry();
mConnectTimeOut = mAridManager.getUploadConfig().getConnectTimeOut();
mReadTimeOut = mAridManager.getUploadConfig().getIOTimeOut();
mBufSize = mAridManager.getUploadConfig().getBuffSize();
isNotNetRetry = mAridManager.getUploadConfig().isNotNetRetry();
}
@Override public void run() {
@Override public int getMaxSpeed() {
return mAridManager.getUploadConfig().getMaxSpeed();
}
@Override public FtpThreadTask call() throws Exception {
super.call();
//当前子线程的下载位置
mChildCurrentLocation = mConfig.START_LOCATION;
FTPClient client = null;
@ -58,16 +63,21 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
String.format("任务【%s】线程__%s__开始上传【开始位置 : %s,结束位置:%s】", mConfig.TEMP_FILE.getName(),
mConfig.THREAD_ID, mConfig.START_LOCATION, mConfig.END_LOCATION));
client = createClient();
if (client == null) return;
if (client == null) {
return this;
}
initPath();
client.makeDirectory(dir);
client.changeWorkingDirectory(dir);
client.setRestartOffset(mConfig.START_LOCATION);
int reply = client.getReplyCode();
if (!FTPReply.isPositivePreliminary(reply) && reply != FTPReply.FILE_ACTION_OK) {
fail(mChildCurrentLocation, "上传失败,错误码为:" + reply + ",msg:" + client.getReplyString(), null);
fail(mChildCurrentLocation,
new AriaIOException(TAG,
String.format("文件上传错误,错误码为:%s, msg:%s, filePath: %s", reply,
client.getReplyString(), mEntity.getFilePath())));
client.disconnect();
return;
return this;
}
file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize);
@ -77,7 +87,7 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
}
upload(client, file);
if (isBreak()) {
return;
return this;
}
ALog.i(TAG,
String.format("任务【%s】线程__%s__上传完毕", mConfig.TEMP_FILE.getName(), mConfig.THREAD_ID));
@ -90,12 +100,14 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
}
if (STATE.isFail()) {
STATE.isRunning = false;
mListener.onFail(false);
mListener.onFail(false, new TaskException(TAG,
String.format("上传失败,filePath: %s, uploadUrl: %s", mEntity.getFilePath(), mConfig.URL)));
}
} catch (IOException e) {
fail(mChildCurrentLocation, String.format("上传失败【%s】", mConfig.URL), e);
fail(mChildCurrentLocation, new AriaIOException(TAG,
String.format("上传失败,filePath: %s, uploadUrl: %s", mEntity.getFilePath(), mConfig.URL)));
} catch (Exception e) {
fail(mChildCurrentLocation, "获取流失败", e);
fail(mChildCurrentLocation, new AriaIOException(TAG, null, e));
} finally {
try {
if (file != null) {
@ -108,6 +120,7 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
e.printStackTrace();
}
}
return this;
}
private void initPath() throws UnsupportedEncodingException {
@ -122,28 +135,32 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
throws IOException {
try {
ALog.d(TAG, String.format("remotePath【%s】", remotePath));
ALog.d(TAG, String.format("remotePath: %s", remotePath));
client.storeFile(remotePath, new FtpFISAdapter(bis), new OnFtpInputStreamListener() {
boolean isStoped = false;
@Override public void onFtpInputStream(FTPClient client, long totalBytesTransferred,
int bytesTransferred, long streamSize) {
if (isBreak() && !isStoped) {
try {
try {
if (isBreak() && !isStoped) {
isStoped = true;
client.abor();
} catch (IOException e) {
e.printStackTrace();
}
if (mSpeedBandUtil != null) {
mSpeedBandUtil.limitNextBytes(bytesTransferred);
}
progress(bytesTransferred);
} catch (IOException e) {
e.printStackTrace();
}
progress(bytesTransferred);
}
});
} catch (IOException e) {
if (e.getMessage().contains("IOException caught while copying")) {
if (e.getMessage().contains("AriaIOException caught while copying")) {
e.printStackTrace();
} else {
fail(mChildCurrentLocation, "上传失败", e);
fail(mChildCurrentLocation,
new AriaIOException(TAG, String.format("上传失败,filePath: %s", mEntity.getFilePath()), e));
}
}
@ -151,8 +168,9 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
if (!FTPReply.isPositiveCompletion(reply)) {
if (reply != FTPReply.TRANSFER_ABORTED) {
fail(mChildCurrentLocation,
String.format("上传文件错误,错误码为:%s,msg:%s", reply, client.getReplyString()),
null);
new AriaIOException(TAG,
String.format("文件上传错误,错误码为:%s, msg:%s, filePath: %s", reply,
client.getReplyString(), mEntity.getFilePath())));
}
if (client.isConnected()) {
client.disconnect();

@ -15,13 +15,14 @@
*/
package com.arialyy.aria.core.upload.uploader;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.AbsThreadTask;
import com.arialyy.aria.core.common.StateConstance;
import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.inf.IUploadListener;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.exception.TaskException;
import com.arialyy.aria.util.ALog;
import java.io.BufferedReader;
import java.io.File;
@ -52,19 +53,20 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
HttpThreadTask(StateConstance constance, IUploadListener listener,
SubThreadConfig<UploadTaskEntity> uploadInfo) {
super(constance, listener, uploadInfo);
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
mConnectTimeOut = manager.getUploadConfig().getConnectTimeOut();
mReadTimeOut = manager.getUploadConfig().getIOTimeOut();
mBufSize = manager.getUploadConfig().getBuffSize();
isNotNetRetry = manager.getUploadConfig().isNotNetRetry();
mConnectTimeOut = mAridManager.getUploadConfig().getConnectTimeOut();
mReadTimeOut = mAridManager.getUploadConfig().getIOTimeOut();
mBufSize = mAridManager.getUploadConfig().getBuffSize();
isNotNetRetry = mAridManager.getUploadConfig().isNotNetRetry();
}
@Override public void run() {
@Override public HttpThreadTask call() throws Exception {
super.call();
File uploadFile = new File(mEntity.getFilePath());
if (!uploadFile.exists()) {
ALog.e(TAG, String.format("【%s】,文件不存在。", mEntity.getFilePath()));
fail();
return;
fail(new TaskException(TAG,
String.format("上传失败,文件不存在;filePath: %s, url: %s", mEntity.getFilePath(),
mEntity.getUrl())));
return this;
}
mListener.onPre();
URL url;
@ -103,13 +105,15 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
mListener.onComplete();
} catch (Exception e) {
e.printStackTrace();
fail();
fail(new TaskException(TAG,
String.format("上传失败,filePath: %s, url: %s", mEntity.getFilePath(), mEntity.getUrl()), e));
}
return this;
}
private void fail() {
private void fail(BaseException e1) {
try {
mListener.onFail(true);
mListener.onFail(true, e1);
STATE.isRunning = false;
if (mOutputStream != null) {
mOutputStream.close();
@ -167,6 +171,9 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
if (STATE.isCancel) {
break;
}
if (mSpeedBandUtil != null) {
mSpeedBandUtil.limitNextBytes(bytesRead);
}
}
mOutputStream.flush();
@ -198,7 +205,7 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
if (status == HttpURLConnection.HTTP_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(mHttpConn.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
while (isLive() && (line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
@ -212,4 +219,8 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
mOutputStream.close();
return response.toString();
}
@Override public int getMaxSpeed() {
return mAridManager.getUploadConfig().getMaxSpeed();
}
}

@ -22,6 +22,8 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IUploadListener;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.exception.TaskException;
import com.arialyy.aria.util.CheckUtil;
/**
@ -60,8 +62,8 @@ public class SimpleUploadUtil implements IUtil, Runnable {
}
}
@Override public void onFail(String url, String errorMsg, boolean needRetry) {
mListener.onFail(needRetry);
@Override public void onFail(String url, BaseException e, boolean needRetry) {
mListener.onFail(needRetry, e);
}
}).start();
break;
@ -99,7 +101,7 @@ public class SimpleUploadUtil implements IUtil, Runnable {
mUploader.cancel();
}
@Override public void setMaxSpeed(double maxSpeed) {
mUploader.setMaxSpeed(maxSpeed);
@Override public void setMaxSpeed(int speed) {
mUploader.setMaxSpeed(speed);
}
}

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

Loading…
Cancel
Save